11#include "TimeDefuser.h"
22
3+ #ifndef TD_LEGACY
4+ BOOLEAN PatchExGetExpirationDate (void * pExGetExpirationDate ){
5+ PMDL mdl = NULL ;
6+ void * map = NULL ;
7+ // Create a MDL paging to get over write protection.
8+ mdl = IoAllocateMdl (pExGetExpirationDate , 8 , FALSE, FALSE, NULL );
9+ if (!mdl ) {
10+ TDPrint ("[X] TimeDefuser: IoAllocateMdl failed.\n" );
11+ return FALSE;
12+ }
13+
14+ MmProbeAndLockPages (mdl , KernelMode , IoReadAccess );
15+ map = MmMapLockedPagesSpecifyCache (mdl , KernelMode , MmNonCached , NULL , FALSE, NormalPagePriority );
16+ if (!map ) {
17+ TDPrint ("[X] TimeDefuser: MmMapLockedPagesSpecifyCache failed.\n" );
18+ return FALSE;
19+ }
20+ MmProtectMdlSystemAddress (mdl , PAGE_READWRITE );
21+ // Write to newly created MDL mapping.
22+ * (int * )map = 0xC3C03148 ; // xor eax,eax \ ret | This is apparently same for both x86 and x64
23+ // Unmap the MDL
24+ MmUnmapLockedPages (map , mdl );
25+ MmUnlockPages (mdl );
26+ IoFreeMdl (mdl );
27+ return TRUE;
28+ }
29+ #endif
30+
331NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject , PUNICODE_STRING RegistryPath ) {
432 LARGE_INTEGER * li = KUSERSystemExpirationDate ; // Address of SystemExpirationDate field at KUSER_SHARED_DATA
533 unsigned long long TimebombStamp = 0 ; // Expiration date stamp
634 RTL_PROCESS_MODULES ModuleInfo = { 0 }; // Structure used for getting kernel base address
735 unsigned long long * KernelBase = NULL ; // Kernel Base address
836 ULONG KernelSize = 0 ; // Kernel image size
37+ HANDLE hKey = OpenRegistryKey (RegistryPath );
938#ifndef TD_LEGACY
1039 unsigned int KernelSize2 = 0 ; // Var used in loops as a max value
1140 PAGESections ps [5 ] = { 0 }; // PE sections that name starts with "PAGE"
@@ -14,7 +43,6 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
1443
1544 // Unrefence unused variables.
1645 UNREFERENCED_PARAMETER (DriverObject );
17- UNREFERENCED_PARAMETER (RegistryPath );
1846
1947 // Print version info.
2048 TDPrint ("[*] TimeDefuser: version " td_version td_variant " loaded "
@@ -39,6 +67,52 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
3967 KernelSize = ModuleInfo .Modules [0 ].ImageSize ;
4068 TDPrint ("[+] TimeDefuser: Kernel Base address is 0x%p and size is %lu\n" , KernelBase , KernelSize );
4169
70+ // Check whether addresses are cached
71+ if (hKey ) {
72+ if (CompareKernelVersion (hKey )) {
73+ // Get cached address offsets for timestamps.
74+ int Stamp1 = RegReadValue (hKey , L"Stamp1" , NULL , 0 ),
75+ Stamp2 = RegReadValue (hKey , L"Stamp2" , NULL , 0 );
76+
77+ // Zero first timestamp
78+ if (!Stamp1 ) {
79+ // No cached address, assume nothing is cached.
80+ goto patchBeginning ;
81+ }
82+ TDPrint ("[*] TimeDefuser: Cached addresses are found on registry.\n" );
83+ TDPrint ("[+] TimeDefuser: Cached ExpNtExpirationDate address 0x%p is used.\n" , (unsigned long long * )((char * )KernelBase + Stamp1 ));
84+ * (unsigned long long * )((char * )KernelBase + Stamp1 ) = 0 ;
85+ #ifdef TD_LEGACY
86+ // On legacy, for some reason, actual timebomb stamp
87+ // is the next qword (on XP 2526). We will zero that too.
88+ * (unsigned long long * )((char * )KernelBase + Stamp1 + 8 ) = 0 ;
89+ #endif
90+
91+ // Zero second timestamp if available.
92+ if (Stamp2 ) {
93+ TDPrint ("[+] TimeDefuser: Cached ExpNtExpirationData address 0x%p is used.\n" , (char * )KernelBase + Stamp2 );
94+ #ifdef TD_LEGACY
95+ RtlZeroMemory ((char * )KernelBase + Stamp2 , 16 );
96+ #else
97+ * (unsigned long long * )((char * )KernelBase + Stamp2 ) = 0 ;
98+ #endif
99+ }
100+
101+ #ifndef TD_LEGACY
102+ int Function = RegReadValue (hKey , L"Function" , NULL , 0 );
103+ TDPrint ("[+] TimeDefuser: Cached ExGetExpirationDate function address 0x%p is used.\n" , (char * )KernelBase + Function );
104+ if (!PatchExGetExpirationDate ((char * )KernelBase + Function ))
105+ goto patchFail ;
106+ #endif
107+ goto patchOK ;
108+ }
109+ else {
110+ // Kernel version mismatch.
111+ }
112+ }
113+ patchBeginning :
114+ TDPrint ("[*] TimeDefuser: No or mismatching cached addresses are found on registry.\n" );
115+ SaveKernelVersion (hKey );
42116#ifdef TD_LEGACY
43117 // Search for timebomb stamp in memory
44118 KernelSize /= sizeof (unsigned __int64 );
@@ -49,6 +123,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
49123 // For some reason actual timebomb was the next qword on XP 2526, I'll save this and search for it again.
50124 TimebombStamp = KernelBase [i + 1 ]; // Save the lower part of stamp.
51125 KernelBase [i + 1 ] = 0 ; // And null where I found it too.
126+ RegWriteDword (hKey , L"Stamp1" , (ULONG )((unsigned char * )& KernelBase [i ] - (unsigned char * )KernelBase ));
52127 break ;
53128 }
54129 }
@@ -58,6 +133,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
58133 if ((int )KernelBase [i ] == (int )TimebombStamp ) {
59134 TDPrint ("[+] TimeDefuser: ExpNtExpirationData found at 0x%p\n" , & KernelBase [i ]);
60135 RtlZeroMemory (& KernelBase [i ], 16 );
136+ RegWriteDword (hKey , L"Stamp2" , (ULONG )((unsigned char * )& KernelBase [i ] - (unsigned char * )KernelBase ));
61137 goto patchOK ;
62138 }
63139 }
@@ -98,18 +174,22 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
98174 KdPrintEx ((DPFLTR_IHVDRIVER_ID , DPFLTR_ERROR_LEVEL , "[+] TimeDefuser: searching for stamp at 0x%p in %d bytes\n" , PotentialTimestamp , KernelSize2 ));
99175
100176 KernelSize2 ;
101- for (size_t i = 0 ; i < KernelSize2 ; i ++ ) {
177+ for (ULONG i = 0 ; i < KernelSize2 ; i ++ ) {
102178 if (* (unsigned long long * ) & PotentialTimestamp [i ] == TimebombStamp ) {
103179 KdPrintEx ((DPFLTR_IHVDRIVER_ID , DPFLTR_ERROR_LEVEL , "[+] TimeDefuser: Timebomb stamp found at 0x%p\n" , & PotentialTimestamp [i ]));
104180 * (unsigned long long * )(& PotentialTimestamp [i ]) = 0 ;
105181 pExpNtExpirationDate = & PotentialTimestamp [i ];
106182
107183 if (occurance ) {
108184 pExpNtExpirationDate = & PotentialTimestamp [i ];
185+ RegWriteDword (hKey , L"Stamp2" , (ULONG )(& PotentialTimestamp [i ] - (unsigned char * )KernelBase ));
109186 occurance = 2 ;
110187 break ;
111188 }
112- else occurance = 1 ;
189+ else {
190+ occurance = 1 ;
191+ RegWriteDword (hKey , L"Stamp1" , (ULONG )((unsigned char * )& PotentialTimestamp [i ] - (unsigned char * )KernelBase ));
192+ }
113193 }
114194 }
115195
@@ -168,31 +248,13 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
168248 for (unsigned char j = 0 ; j < 100 ; j ++ ) {
169249 if (* (unsigned char * )& PotentialTimeRef [i - j ] == 0xe8 ) { // CALL instruction found.
170250 unsigned char * pExGetExpirationDate = & PotentialTimeRef [i - j + 5 ];
171- PMDL mdl = NULL ;
172- void * map = NULL ;
173251 pExGetExpirationDate += * (unsigned int * )& PotentialTimeRef [i - j + 1 ]; // Next 4 bytes are relative address to our current location.
252+ RegWriteDword (hKey , L"Function" , (ULONG )(pExGetExpirationDate - (unsigned char * )KernelBase ));
174253 TDPrint ("[+] TimeDefuser: ExGetExpirationDate found at 0x%p\n" , pExGetExpirationDate );
175- // Create a MDL paging to get over write protection.
176- mdl = IoAllocateMdl (pExGetExpirationDate , 8 , FALSE, FALSE, NULL );
177- if (!mdl ) {
178- TDPrint ("[X] TimeDefuser: IoAllocateMdl failed.\n" );
179- goto patchFail ;
180- }
181-
182- MmProbeAndLockPages (mdl , KernelMode , IoReadAccess );
183- map = MmMapLockedPagesSpecifyCache (mdl , KernelMode , MmNonCached , NULL , FALSE, NormalPagePriority );
184- if (!map ) {
185- TDPrint ("[X] TimeDefuser: MmMapLockedPagesSpecifyCache failed.\n" );
254+ if (!PatchExGetExpirationDate (pExGetExpirationDate ))
186255 goto patchFail ;
187- }
188- MmProtectMdlSystemAddress (mdl , PAGE_READWRITE );
189- // Write to newly created MDL mapping.
190- * (int * )map = 0xC3C03148 ; // xor eax,eax \ ret | This is apparently same for both x86 and x64
191- // Unmap the MDL
192- MmUnmapLockedPages (map , mdl );
193- MmUnlockPages (mdl );
194- IoFreeMdl (mdl );
195- goto patchOK ;
256+ else
257+ goto patchOK ;
196258 }
197259 }
198260 break ;
@@ -212,7 +274,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
212274 // Clear the ExpirationdDate field in SharedData.
213275 // Since 1.4, this is the last step so it will stay there in case of failure
214276 // and won't cause any false positives anymore.
215- li -> QuadPart = 0 ;
277+ li -> QuadPart = 0 ; ZwClose ( hKey );
216278 TDPrint ("[*] TimeDefuser: Patch completed successfully.\n" );
217279 return STATUS_SUCCESS ;
218280}
0 commit comments