Skip to content

Commit f0efde5

Browse files
1.4.1 (1.4 is skipped internally)
- Required data is now searched only on defined PE sections instead of linearly searching from beginning of kernel to the end, eliminating the page faults. (#3 #6) - Expiration date is now erased from SharedData only if patch fully succeeds, instead of erasing it as a first step, thus solving the confusion when patch fails midway. - VS 2013 w/ WDK 8.1 build config added, which supports from NT 6.1 (and potentially 6.0, though untested) onwards. This was required because M$ killed the support for 32-bit and anything prior to NT 10.0 with latest WDK 11 update. - Some code cleanup. - GPLv3 license added.
1 parent 872c0e8 commit f0efde5

6 files changed

Lines changed: 810 additions & 1624 deletions

File tree

Driver.cpp

Lines changed: 119 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ extern "C" __kernel_entry NTSTATUS NTAPI ZwQuerySystemInformation(
99
PVOID SystemInformation,
1010
ULONG SystemInformationLength,
1111
PULONG ReturnLength OPTIONAL
12-
);
12+
);
1313

1414
typedef struct _RTL_PROCESS_MODULE_INFORMATION {
1515
PVOID Section;
@@ -22,12 +22,17 @@ typedef struct _RTL_PROCESS_MODULE_INFORMATION {
2222
USHORT LoadCount;
2323
USHORT OffsetToFileName;
2424
UCHAR FullPathName[256];
25-
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
25+
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
2626

2727
typedef struct _RTL_PROCESS_MODULES {
2828
ULONG NumberOfModules;
2929
RTL_PROCESS_MODULE_INFORMATION Modules[1];
30-
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
30+
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
31+
32+
typedef struct {
33+
unsigned long RVA;
34+
unsigned long size;
35+
} PAGESections;
3136

3237
extern "C" DRIVER_INITIALIZE DriverEntry;
3338

@@ -40,115 +45,153 @@ extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING Reg
4045

4146
// Address of SystemExpirationDate field at KUSER_SHARED_DATA
4247
#if defined(AMD64)
43-
LARGE_INTEGER* li = (LARGE_INTEGER*)0xfffff780000002c8;
48+
LARGE_INTEGER* li = (LARGE_INTEGER*)0xfffff780000002c8;
4449
#elif defined(i386)
4550
LARGE_INTEGER* li = (LARGE_INTEGER*)0xffdf02c8;
4651
#else
4752
#error Unsupported architecture.
4853
#endif
54+
4955
// Print version info.
50-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[*] TimeDefuser: version 1.3.1 loaded. \
51-
| Compiled on " __DATE__ " " __TIME__ " | https://github.com/NevermindExpress/TimeDefuser\n"));
56+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[*] TimeDefuser: version 1.4.1 loaded "
57+
"| Compiled on " __DATE__ " " __TIME__ " | https://github.com/NevermindExpress/TimeDefuser\n"));
5258

53-
// Change SystemExpirationDate
54-
unsigned long long TimebombStamp = li->QuadPart; li->QuadPart = 0;
59+
// Get SystemExpirationDate
60+
unsigned long long TimebombStamp = li->QuadPart;
5561
if (!TimebombStamp) {
56-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: No timebomb found, exiting.\n"));
62+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: No timebomb found, exiting.\n"));
5763
return STATUS_FAILED_DRIVER_ENTRY;
5864
}
59-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: SystemExpirationDate is updated and it is now: %llu\n", li->QuadPart));
65+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: SystemExpirationDate is 0x%p\n", TimebombStamp));
6066

6167
// Get kernel base
6268
RTL_PROCESS_MODULES ModuleInfo = { 0 };
6369
status = ZwQuerySystemInformation(SystemModuleInformation, &ModuleInfo, sizeof(ModuleInfo), 0);
6470
unsigned long long* KernelBase = (unsigned long long*)ModuleInfo.Modules[0].ImageBase;
65-
ULONG KernelSize = ModuleInfo.Modules[0].ImageSize;
71+
#pragma warning(disable:4189)
72+
ULONG KernelSize = ModuleInfo.Modules[0].ImageSize;
6673
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: Kernel Base address is 0x%p and size is %lu\n", KernelBase, KernelSize));
67-
68-
// Search for timebomb stamp in memory
69-
BOOLEAN occurence1 = FALSE;
70-
void* pExpNtExpirationDate = NULL;
71-
72-
KernelSize /= sizeof(unsigned long long);
73-
for (size_t i = 0; i < KernelSize; i++) {
74-
if (KernelBase[i] == TimebombStamp) {
75-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: Timebomb stamp found at 0x%p\n", &KernelBase[i]));
76-
KernelBase[i] = 0x7FFFFFFFFFFFFFFF;
7774

78-
if (occurence1) {
79-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: ExpNtExpirationDate address is 0x%p\n", &KernelBase[i]));
80-
pExpNtExpirationDate = &KernelBase[i]; break;
81-
}
82-
else occurence1 = TRUE;
83-
}
84-
}
85-
86-
//KernelBase += (unsigned long long)KernelBase % 4096;
87-
//unsigned char* PotentialTimeRef = (unsigned char*)(KernelBase + 0x500000);
88-
//int KernelSize2 = KernelSize * 8 - 0x500000;
89-
////UNICODE_STRING us; us.Buffer = L"ExGetExpirationDate"; us.Length = 19; us.MaximumLength = 19;
90-
////KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "TimeDefuser: ExGetExpirationDate found at 0x%p\n", MmGetSystemRoutineAddress(&us)));
91-
////us.Buffer = L"ExpTimeRefreshWork"; us.Length = 18; us.MaximumLength = 18;
92-
////KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "TimeDefuser: ExpTimeRefreshWork found at 0x%p\n", MmGetSystemRoutineAddress(&us)));
93-
//
94-
//KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "TimeDefuser: Adjusted Kernel Base address is 0x%p and size is %lu\n", KernelBase, KernelSize2));
95-
96-
// Search for PE headers
97-
const short header = 0x5a4d;
75+
// Check for PE Header existance.
76+
const short header = 0x5a4d; // MZ
9877
if (*(short*)KernelBase != header) {
9978
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: PE Header not found!\n"));
10079
goto patchFail;
101-
}
102-
103-
const __int64 sectName = 0x00004b4c45474150; // "PAGELK\0\0"
80+
}
81+
82+
const __int64 sectNamePAGE = 0x4154414445474150; // "PAGEDATA"
10483
unsigned int KernelSize2 = 0;
105-
unsigned char* PotentialTimeRef = (unsigned char*)KernelBase;
84+
unsigned char* PotentialTimestamp = (unsigned char*)KernelBase;
10685

107-
// Search for PAGELK section at PE sections. This section is where the
108-
// ExpTimeRefreshWork function is located at, which later calls a function named "ExGetExpirationDate"
109-
// so we are going to use its RVA and size for finding the function location.
86+
// Search for "PAGEDATA" section at PE sections. This section is where the
87+
// ExpNtExpirationDate timestamp variable is located at, so we are going
88+
// to use its RVA and size for finding the function location.
11089

11190
for (size_t i = 0; i < 768; i++) {
112-
if (KernelBase[i] == sectName) { // Check if we found the PAGELK\0\0 section name.
113-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: PAGELK Section found at 0x%p with size %d\n",&KernelBase[i], *(int*)&KernelBase[i + 1]));
91+
if (KernelBase[i] == sectNamePAGE) { // Check if we found the PAGEDATA section name.
92+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: PAGEDATA Section found at 0x%p with size %d\n", &KernelBase[i], *(int*)&KernelBase[i + 1]));
11493
KernelSize2 = *(int*)&KernelBase[i + 1]; // Get the section size
11594
// Get the function RVA and append it to kernel base address.
116-
int* asd = (int*)&KernelBase[i + 1];
117-
PotentialTimeRef += asd[1];
95+
int* asd = (int*)&KernelBase[i + 1];
96+
PotentialTimestamp += asd[1];
11897
break;
11998
}
12099
}
121-
if (!PotentialTimeRef) {
122-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: PAGELK Section not found!\n"));
100+
if (PotentialTimestamp == (unsigned char*)KernelBase) {
101+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: PAGEDATA Section not found!\n"));
123102
goto patchFail;
124103
}
125104

126-
// Search for the ExpTimeRefreshWork function at the address we got from PAGELK.
127-
// Finding it is easy because it has one of only two references to expiration date address at KUSER
128-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: searching at 0x%p in %d bytes\n", PotentialTimeRef, KernelSize2));
129-
for (size_t i = 0; i < KernelSize2; i += 4096) {
130-
// Check if given address is valid to prevent page faults
131-
if (!MmIsAddressValid(&PotentialTimeRef[i])) {
132-
//KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "- TimeDefuser: Page 0x%p is not valid.\n", &PotentialTimeRef[i]));
133-
continue;
105+
// Search for timebomb stamp in memory
106+
CHAR occurance = FALSE;
107+
void* pExpNtExpirationDate = NULL;
108+
109+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: searching for stamp at 0x%p in %d bytes\n", PotentialTimestamp, KernelSize2));
110+
111+
KernelSize2;
112+
for (size_t i = 0; i < KernelSize2; i++) {
113+
if (*(unsigned long long*)&PotentialTimestamp[i] == TimebombStamp) {
114+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: Timebomb stamp found at 0x%p\n", &PotentialTimestamp[i]));
115+
*(unsigned long long*)(&PotentialTimestamp[i]) = 0;
116+
pExpNtExpirationDate = &PotentialTimestamp[i];
117+
118+
if (occurance) {
119+
pExpNtExpirationDate = &PotentialTimestamp[i];
120+
occurance = 2;
121+
break;
122+
}
123+
else occurance = 1;
134124
}
135-
//KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "+ TimeDefuser: Searching inside page 0x%p\n", &PotentialTimeRef[i]));
125+
}
126+
127+
// Print the address according to occurrance.
128+
switch (occurance) {
129+
case 0:
130+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: can't find ExpNtExpirationDate!\n"));
131+
goto patchFail; break;
132+
case 1:
133+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: ExpNtExpirationDate address is 0x%p (first occurrance)\n", pExpNtExpirationDate));
134+
break;
135+
case 2:
136+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: ExpNtExpirationDate address is 0x%p (second occurrance)\n", pExpNtExpirationDate));
137+
break;
138+
}
136139

137-
// Search inside page for reference
138-
for (int k = 0; k < 4096;k++) {
139-
if (*(unsigned long long*)&PotentialTimeRef[i + k] == (unsigned long long)li) {
140+
const __int64 sectNamePAGELK = 0x0000000045474150; // "PAGE\0\0\0\0"
141+
142+
// Search for PAGE section at PE sections. This section or one of the next three sections is where the
143+
// "ExpTimeRefreshWork" function is located at, which later calls a function named "ExGetExpirationDate".
144+
// Due to it's variable being, we will search the PAGE section and next three sections.
145+
146+
PAGESections ps[4] = { 0 };
147+
148+
for (size_t i = 0; i < 768; i++) {
149+
if (KernelBase[i] == sectNamePAGELK) { // Check if we found the PAGE\0\0\0\0 section name.
150+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: PAGE Section found at 0x%p with size %d\n", &KernelBase[i], *(int*)&KernelBase[i + 1]));
151+
int* temp = (int*)&KernelBase[i + 1];
152+
ps[0].size = temp[0]; // Get the section size
153+
ps[0].RVA = temp[1]; // and RVA
154+
// Get the RVA and size of next three sections.
155+
for (char j = 1; j < 4; j++) {
156+
temp += 10;
157+
ps[j].size = temp[0]; // Get the section size
158+
ps[j].RVA = temp[1]; // and RVA
159+
}
160+
break;
161+
}
162+
}
163+
164+
if (!ps[0].size) {
165+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: PAGE Section not found!\n"));
166+
goto patchFail;
167+
}
168+
169+
// Search for the ExpTimeRefreshWork function at the address we got from sections.
170+
// Finding it is easy because it has one of only two references to expiration date address at KUSER
171+
for (char t = 0; t < 4; t++) {
172+
unsigned char* PotentialTimeRef = (unsigned char*)KernelBase + ps[t].RVA;
173+
KernelSize2 = ps[t].size;
174+
175+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: searching at 0x%p in %lu bytes\n", PotentialTimeRef, KernelSize2));
176+
for (size_t i = 0; i < KernelSize2; i++) {
177+
178+
#ifdef _AMD64
179+
if (*(unsigned long long*)&PotentialTimeRef[i] == (unsigned long long)li) {
180+
#else
181+
if (*(unsigned long*)&PotentialTimeRef[i] == (unsigned long)li) {
182+
#endif
140183
// We found the reference of KUSER expiration date field address.
141-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: Potential TimeRef found at 0x%p\n", &PotentialTimeRef[i + k]));
184+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: Potential TimeRef found at 0x%p\n", &PotentialTimeRef[i]));
142185
// The call to ExGetExpirationDate is a few instructions before this reference
143186
// So we search backwards for any CALL instruction (0xe8)
144187
for (unsigned char j = 0; j < 100; j++) {
145-
if (*(unsigned char*)&PotentialTimeRef[i + k - j] == 0xe8) { // CALL instruction found.
146-
unsigned char* pExGetExpirationDate = &PotentialTimeRef[i + k - j + 5];
147-
pExGetExpirationDate += *(unsigned int*)&PotentialTimeRef[i + k - j + 1]; // Next 4 bytes are relative address to our current location.
188+
if (*(unsigned char*)&PotentialTimeRef[i - j] == 0xe8) { // CALL instruction found.
189+
unsigned char* pExGetExpirationDate = &PotentialTimeRef[i - j + 5];
190+
pExGetExpirationDate += *(unsigned int*)&PotentialTimeRef[i - j + 1]; // Next 4 bytes are relative address to our current location.
148191
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] TimeDefuser: ExGetExpirationDate found at 0x%p\n", pExGetExpirationDate));
149192
// Create a MDL paging to get over write protection.
150193
PMDL mdl = IoAllocateMdl(pExGetExpirationDate, 8, FALSE, FALSE, NULL);
151-
if (!mdl) {
194+
if (!mdl) {
152195
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: IoAllocateMdl failed.\n"));
153196
goto patchFail;
154197
}
@@ -165,21 +208,23 @@ extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING Reg
165208
// Unmap the MDL
166209
MmUnmapLockedPages(map, mdl);
167210
MmUnlockPages(mdl);
168-
IoFreeMdl(mdl);
211+
IoFreeMdl(mdl);
169212
goto patchOK;
170213
}
171214
}
172-
break;
173215
}
174216
}
217+
175218
}
176219
// No references found so far so we fail.
220+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: PAGE Section not found!\n"));
177221
patchFail:
178222
// 0xC3C03148
179-
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: Patch failed.\n"));
223+
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[X] TimeDefuser: could not find ExpTimeRefreshWork!\n"));
180224
return STATUS_FAILED_DRIVER_ENTRY;
181225

182226
patchOK:
227+
li->QuadPart = 0; // Clear the ExpirationdDate field in SharedData. This is the last step so it will stay there in case of failure and won't cause any false positives anymore.
183228
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[*] TimeDefuser: Patch completed successfully.\n"));
184229
return STATUS_SUCCESS;
185230
}

0 commit comments

Comments
 (0)