├── README.md
├── commandsOffsets.h
├── RealExtern.vcxproj.user
├── RealExtern.vcxproj.filters
├── RealExtern.inf
├── RealExtern.sln
├── kdmapperTraces.h
├── RealExtern.vcxproj
├── Driver.cpp
├── Undocumented.h
└── KernelUtils.h
/README.md:
--------------------------------------------------------------------------------
1 | # What this is for:
2 |
3 | This is a simple kernel driver for reading / writing process memory, it uses IOCTL communication, in case someone claims IOCTL communication is detected: byte patch a part of the ioctl function with a jmp I described that better in the source itself.
4 |
5 | # Note:
6 | This driver won't work on every Winver, until you update the memory addresses for it in the source code itself. Offsets that need to be changed are located in disk.sys, “ULONG64 hook Location = (ULONG64)diskSysBase + 0x32A2;” and “ ULONG64 returnPlaceOfIOCTL = (ULONG64)diskSysBase + 0x16AF; “. This is intended to be manually mapped.
7 |
--------------------------------------------------------------------------------
/commandsOffsets.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Undocumented.h"
4 |
5 |
6 |
7 |
8 | struct communicationStruct
9 | {
10 | DWORD64 address;
11 | DWORD commandID;
12 | DWORD64 processID;
13 | DWORD size;
14 | const UCHAR buffer[25];
15 | char section[10];
16 | char wildCard;
17 | BOOLEAN dataOnly;
18 | wchar_t targetmoduleName[20];
19 | wchar_t currentmoduleName[20];
20 | };
21 |
22 |
23 |
24 | /* super important info!!!! 1137!!! */
25 | ULONG64 interceptedIRP = (ULONG64)0x5555;
26 | communicationStruct* SystemBuffer;
27 | PEPROCESS TargetProcess;
28 | DWORD64 ClientBaseAddress = 0;
29 | DWORD64 GameBaseAddress = 0;
30 | static DWORD64 readOutputAddress; // for sending data to usermode
31 | PEPROCESS clientProcess;
32 |
33 | const int sigScanCommand = 120;
34 | const int CleanTraces = 3121;
35 | const int ReadMemoryCommand = 244;
36 | const int WriteMemorycommand = 384;
37 | const int initProcessInfoCommand = 943;
38 | const int exitProcess = 666;
39 | const int resolveAddressCommand = 23;
40 | const int testCommand = 304;
--------------------------------------------------------------------------------
/RealExtern.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Off
5 | New Computer
6 |
7 |
8 | New Computer
9 |
10 |
11 | New Computer
12 |
13 |
14 | New Computer
15 |
16 |
17 | New Computer
18 |
19 |
20 | New Computer
21 |
22 |
23 | New Computer
24 |
25 |
26 | New Computer
27 |
28 |
--------------------------------------------------------------------------------
/RealExtern.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {8E41214B-6785-4CFE-B992-037D68949A14}
18 | inf;inv;inx;mof;mc;
19 |
20 |
21 |
22 |
23 | Driver Files
24 |
25 |
26 |
27 |
28 | Source Files
29 |
30 |
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 | Source Files
40 |
41 |
42 | Source Files
43 |
44 |
45 |
--------------------------------------------------------------------------------
/RealExtern.inf:
--------------------------------------------------------------------------------
1 | ;
2 | ; RealExtern.inf
3 | ;
4 |
5 | [Version]
6 | Signature="$WINDOWS NT$"
7 | Class=Sample ; TODO: edit Class
8 | ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid
9 | Provider=%ManufacturerName%
10 | CatalogFile=RealExtern.cat
11 | DriverVer= ; TODO: set DriverVer in stampinf property pages
12 |
13 | [DestinationDirs]
14 | DefaultDestDir = 12
15 | RealExtern_Device_CoInstaller_CopyFiles = 11
16 |
17 | ; ================= Class section =====================
18 |
19 | [ClassInstall32]
20 | Addreg=SampleClassReg
21 |
22 | [SampleClassReg]
23 | HKR,,,0,%ClassName%
24 | HKR,,Icon,,-5
25 |
26 | [SourceDisksNames]
27 | 1 = %DiskName%,,,""
28 |
29 | [SourceDisksFiles]
30 | RealExtern.sys = 1,,
31 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
32 |
33 | ;*****************************************
34 | ; Install Section
35 | ;*****************************************
36 |
37 | [Manufacturer]
38 | %ManufacturerName%=Standard,NT$ARCH$
39 |
40 | [Standard.NT$ARCH$]
41 | %RealExtern.DeviceDesc%=RealExtern_Device, Root\RealExtern ; TODO: edit hw-id
42 |
43 | [RealExtern_Device.NT]
44 | CopyFiles=Drivers_Dir
45 |
46 | [Drivers_Dir]
47 | RealExtern.sys
48 |
49 | ;-------------- Service installation
50 | [RealExtern_Device.NT.Services]
51 | AddService = RealExtern,%SPSVCINST_ASSOCSERVICE%, RealExtern_Service_Inst
52 |
53 | ; -------------- RealExtern driver install sections
54 | [RealExtern_Service_Inst]
55 | DisplayName = %RealExtern.SVCDESC%
56 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER
57 | StartType = 3 ; SERVICE_DEMAND_START
58 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL
59 | ServiceBinary = %12%\RealExtern.sys
60 |
61 | ;
62 | ;--- RealExtern_Device Coinstaller installation ------
63 | ;
64 |
65 | [RealExtern_Device.NT.CoInstallers]
66 | AddReg=RealExtern_Device_CoInstaller_AddReg
67 | CopyFiles=RealExtern_Device_CoInstaller_CopyFiles
68 |
69 | [RealExtern_Device_CoInstaller_AddReg]
70 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
71 |
72 | [RealExtern_Device_CoInstaller_CopyFiles]
73 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
74 |
75 | [RealExtern_Device.NT.Wdf]
76 | KmdfService = RealExtern, RealExtern_wdfsect
77 | [RealExtern_wdfsect]
78 | KmdfLibraryVersion = $KMDFVERSION$
79 |
80 | [Strings]
81 | SPSVCINST_ASSOCSERVICE= 0x00000002
82 | ManufacturerName="" ;TODO: Replace with your manufacturer name
83 | ClassName="Samples" ; TODO: edit ClassName
84 | DiskName = "RealExtern Installation Disk"
85 | RealExtern.DeviceDesc = "RealExtern Device"
86 | RealExtern.SVCDESC = "RealExtern Service"
87 |
--------------------------------------------------------------------------------
/RealExtern.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30128.74
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RealExtern", "RealExtern.vcxproj", "{3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|ARM = Debug|ARM
11 | Debug|ARM64 = Debug|ARM64
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|ARM = Release|ARM
15 | Release|ARM64 = Release|ARM64
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|ARM.ActiveCfg = Debug|ARM
21 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|ARM.Build.0 = Debug|ARM
22 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|ARM.Deploy.0 = Debug|ARM
23 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|ARM64.Deploy.0 = Debug|ARM64
26 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|x64.ActiveCfg = Debug|x64
27 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|x64.Build.0 = Debug|x64
28 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|x64.Deploy.0 = Debug|x64
29 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|x86.ActiveCfg = Debug|Win32
30 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|x86.Build.0 = Debug|Win32
31 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Debug|x86.Deploy.0 = Debug|Win32
32 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|ARM.ActiveCfg = Release|ARM
33 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|ARM.Build.0 = Release|ARM
34 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|ARM.Deploy.0 = Release|ARM
35 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|ARM64.ActiveCfg = Release|ARM64
36 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|ARM64.Build.0 = Release|ARM64
37 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|ARM64.Deploy.0 = Release|ARM64
38 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|x64.ActiveCfg = Release|x64
39 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|x64.Build.0 = Release|x64
40 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|x64.Deploy.0 = Release|x64
41 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|x86.ActiveCfg = Release|Win32
42 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|x86.Build.0 = Release|Win32
43 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}.Release|x86.Deploy.0 = Release|Win32
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(ExtensibilityGlobals) = postSolution
49 | SolutionGuid = {9B6ECC2A-4B26-4079-AAB7-A48D63CC538F}
50 | EndGlobalSection
51 | EndGlobal
52 |
--------------------------------------------------------------------------------
/kdmapperTraces.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "KernelUtils.h"
4 |
5 | BOOLEAN IsUnloadedDriverEntryEmpty(
6 | _In_ PMM_UNLOADED_DRIVER Entry
7 | )
8 | {
9 | if (Entry->Name.MaximumLength == 0 ||
10 | Entry->Name.Length == 0 ||
11 | Entry->Name.Buffer == NULL)
12 | {
13 | return TRUE;
14 | }
15 |
16 | return FALSE;
17 | }
18 |
19 | UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"iqvw64e.sys");
20 | UNICODE_STRING NewDriverName = RTL_CONSTANT_STRING(L"ddlpqgz.sys");
21 |
22 |
23 | PMM_UNLOADED_DRIVER MmUnloadedDrivers;
24 | PULONG MmLastUnloadedDriver;
25 | UCHAR MmUnloadedDriverSig[] = "\x4C\x8B\x00\x00\x00\x00\x00\x4C\x8B\xC9\x4D\x85\x00\x74";
26 |
27 | NTSTATUS findMMunloadedDrivers()
28 | {
29 | PVOID MmUnloadedDriversPtr = NULL;
30 |
31 | NTSTATUS status = BBScanSection("PAGE", MmUnloadedDriverSig, 0x00, sizeof(MmUnloadedDriverSig) - 1, (PVOID*)(&MmUnloadedDriversPtr));
32 | if (!NT_SUCCESS(status)) {
33 | DbgPrint("Unable to find MmUnloadedDriver sig %p\n", MmUnloadedDriversPtr);
34 | return FALSE;
35 | }
36 | DbgPrint("MmUnloadedDriversPtr address found: %p \n", MmUnloadedDriversPtr);
37 |
38 |
39 | MmUnloadedDrivers = *(PMM_UNLOADED_DRIVER*)ResolveRelativeAddress(MmUnloadedDriversPtr, 3, 7);
40 | //REAL REAL mmunloadeddrivers
41 | DbgPrint("MmUnloadedDrivers real location is: %p\n", &MmUnloadedDrivers);
42 |
43 | return status;
44 | }
45 |
46 |
47 |
48 |
49 |
50 |
51 | UCHAR PiDDBLockPtr_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C";
52 | UCHAR PiDDBCacheTablePtr_sig[] = "\x66\x03\xD2\x48\x8D\x0D";
53 |
54 | bool LocatePiDDB(PERESOURCE* lock, PRTL_AVL_TABLE* table)
55 | {
56 | PVOID PiDDBLockPtr = nullptr, PiDDBCacheTablePtr = nullptr;
57 | if (!NT_SUCCESS(BBScanSection("PAGE", PiDDBLockPtr_sig, 0, sizeof(PiDDBLockPtr_sig) - 1, reinterpret_cast(&PiDDBLockPtr)))) {
58 | DbgPrint("Unable to find PiDDBLockPtr sig. Piddblockptr is: %p.\n", PiDDBLockPtr);
59 | return false;
60 | }
61 | DbgPrint("found PiDDBLockPtr sig. Piddblockptr is: %p\n", PiDDBLockPtr);
62 |
63 | if (!NT_SUCCESS(BBScanSection("PAGE", PiDDBCacheTablePtr_sig, 0, sizeof(PiDDBCacheTablePtr_sig) - 1, reinterpret_cast(&PiDDBCacheTablePtr)))) {
64 | DbgPrint("Unable to find PiDDBCacheTablePtr sig. PiDDBCacheTablePtr is: %p\n", PiDDBCacheTablePtr);
65 | return false;
66 | }
67 | DbgPrint("found PiDDBCacheTablePtr sig. PiDDBCacheTablePtr is: %p\n", PiDDBCacheTablePtr);
68 |
69 |
70 | PiDDBCacheTablePtr = PVOID((uintptr_t)PiDDBCacheTablePtr + 3);
71 |
72 | *lock = (PERESOURCE)(ResolveRelativeAddress(PiDDBLockPtr, 3, 7));
73 | *table = (PRTL_AVL_TABLE)(ResolveRelativeAddress(PiDDBCacheTablePtr, 3, 7));
74 |
75 | return true;
76 | }
77 |
78 |
79 |
80 |
81 |
82 | BOOLEAN ClearPiddbCacheTable()
83 | {
84 | PERESOURCE PiDDBLock = NULL;
85 | PRTL_AVL_TABLE PiDDBCacheTable = NULL;
86 | NTSTATUS Status = LocatePiDDB(&PiDDBLock, &PiDDBCacheTable);
87 | if (PiDDBCacheTable == NULL || PiDDBLock == NULL)
88 | {
89 | DbgPrint("LocatePIDDB lock and/or cachetable not found\n");
90 | return Status;
91 | }
92 | else
93 | {
94 | DbgPrint("Successfully found PiddbCachetable and lock!!!1111\n");
95 | DbgPrint("PiddbLock: %p\n", PiDDBLock);
96 | DbgPrint("PiddbCacheTable: %p\n", PiDDBCacheTable);
97 |
98 | PIDCacheobj Entry;
99 | UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"iqvw64e.sys");
100 | Entry.DriverName = DriverName;
101 | Entry.TimeDateStamp = 0x5284EAC3;
102 | ExAcquireResourceExclusiveLite(PiDDBLock, TRUE);
103 | PIDCacheobj* pFoundEntry = (PIDCacheobj*)RtlLookupElementGenericTableAvl(PiDDBCacheTable, &Entry);
104 |
105 | if (pFoundEntry == NULL)
106 | {
107 | DbgPrint("pFoundEntry not found !!!\n");
108 | // release ddb resource lock
109 | ExReleaseResourceLite(PiDDBLock);
110 | return FALSE;
111 | }
112 | else
113 | {
114 | DbgPrint("Found iqvw64e.sys in PiDDBCachetable!!\n");
115 | //unlink from list
116 | RemoveEntryList(&pFoundEntry->List);
117 | RtlDeleteElementGenericTableAvl(PiDDBCacheTable, pFoundEntry);
118 | // release the ddb resource lock
119 | ExReleaseResourceLite(PiDDBLock);
120 | DbgPrint("Clear success and finish !!!\n");
121 | return TRUE;
122 | }
123 |
124 | }
125 | }
126 |
127 |
128 |
129 | BOOLEAN isMmUnloadedDriversFilled()
130 | {
131 | PMM_UNLOADED_DRIVER entry;
132 | for (ULONG Index = 0; Index < MM_UNLOADED_DRIVERS_SIZE; ++Index)
133 | {
134 | entry = &MmUnloadedDrivers[Index];
135 | if (entry->Name.Buffer == NULL || entry->Name.Length == 0 || entry->Name.MaximumLength == 0)
136 | {
137 | return FALSE;
138 | }
139 |
140 | }
141 | return TRUE;
142 | }
143 |
144 |
145 |
146 |
147 | BOOLEAN cleanUnloadedDriverString()
148 | {
149 | findMMunloadedDrivers();
150 | BOOLEAN cleared = FALSE;
151 | BOOLEAN Filled = isMmUnloadedDriversFilled();
152 |
153 | DbgPrint("about to clear mmunload\n");
154 |
155 | for (ULONG Index = 0; Index < MM_UNLOADED_DRIVERS_SIZE; ++Index)
156 | {
157 |
158 |
159 | PMM_UNLOADED_DRIVER Entry = &MmUnloadedDrivers[Index];
160 |
161 | if (RtlCompareUnicodeString(&DriverName, &Entry->Name, TRUE))
162 | {
163 | if (Index == 0)
164 | {
165 | RtlZeroMemory(Entry, sizeof(MM_UNLOADED_DRIVER));
166 | }
167 | else
168 | {
169 | //random 7 letter name
170 | RtlCopyUnicodeString(&Entry->Name, &NewDriverName);
171 | Entry->UnloadTime = MmUnloadedDrivers[Index - 1].UnloadTime - 50;
172 |
173 | DbgPrint("DONE randomizing name inside CleanUnloadedDriverString\n");
174 | }
175 | return TRUE;
176 | }
177 | }
178 | DbgPrint("cannot find iqvw64e.sys!!!!111 cleanunloadeddriverstring fail!!1111\n");
179 |
180 | return FALSE;
181 | }
182 |
183 |
184 | BOOLEAN clearKdmapperTraces()
185 | {
186 | BOOLEAN status;
187 | status = cleanUnloadedDriverString();
188 | if (status == FALSE)
189 | {
190 | DbgPrint("problem with mmunloadeddrivers\n");
191 | }
192 | status = ClearPiddbCacheTable();
193 | if (status == FALSE)
194 | {
195 | DbgPrint("problem with PiddbCacheTable\n");
196 | }
197 | return status;
198 | }
--------------------------------------------------------------------------------
/RealExtern.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 | Debug
22 | ARM
23 |
24 |
25 | Release
26 | ARM
27 |
28 |
29 | Debug
30 | ARM64
31 |
32 |
33 | Release
34 | ARM64
35 |
36 |
37 |
38 | {3C45CB8A-8CD5-4DF9-89EE-D347F34D3DE9}
39 | {1bc93793-694f-48fe-9372-81e2b05556fd}
40 | v4.5
41 | 12.0
42 | Debug
43 | Win32
44 | RealExtern
45 |
46 |
47 |
48 | Windows10
49 | true
50 | WindowsKernelModeDriver10.0
51 | Driver
52 | KMDF
53 | Universal
54 |
55 |
56 | Windows10
57 | false
58 | WindowsKernelModeDriver10.0
59 | Driver
60 | KMDF
61 | Universal
62 |
63 |
64 | Windows10
65 | true
66 | WindowsKernelModeDriver10.0
67 | Driver
68 | KMDF
69 | Universal
70 |
71 |
72 | Windows10
73 | false
74 | WindowsKernelModeDriver10.0
75 | Driver
76 | KMDF
77 | Universal
78 |
79 |
80 | Windows10
81 | true
82 | WindowsKernelModeDriver10.0
83 | Driver
84 | KMDF
85 | Universal
86 |
87 |
88 | Windows10
89 | false
90 | WindowsKernelModeDriver10.0
91 | Driver
92 | KMDF
93 | Universal
94 |
95 |
96 | Windows10
97 | true
98 | WindowsKernelModeDriver10.0
99 | Driver
100 | KMDF
101 | Universal
102 |
103 |
104 | Windows10
105 | false
106 | WindowsKernelModeDriver10.0
107 | Driver
108 | KMDF
109 | Universal
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | DbgengKernelDebugger
121 |
122 |
123 | DbgengKernelDebugger
124 |
125 |
126 | DbgengKernelDebugger
127 |
128 |
129 | DbgengKernelDebugger
130 |
131 |
132 | DbgengKernelDebugger
133 |
134 |
135 | DbgengKernelDebugger
136 |
137 |
138 | DbgengKernelDebugger
139 |
140 |
141 | DbgengKernelDebugger
142 |
143 |
144 |
145 | false
146 | false
147 | TurnOffAllWarnings
148 | false
149 |
150 |
151 | DriverA
152 |
153 |
154 |
155 |
156 | false
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/Driver.cpp:
--------------------------------------------------------------------------------
1 | #include "KernelUtils.h"
2 | #include "kdmapperTraces.h"
3 | #include "commandsOffsets.h"
4 |
5 |
6 |
7 |
8 | DWORD64 initProcess(HANDLE processID, HANDLE clientProcessID, communicationStruct* systemBuffer) /* setup required info (and sig scan), find read output buffer */
9 | {
10 | PsLookupProcessByProcessId(processID, &TargetProcess);
11 | PsLookupProcessByProcessId(clientProcessID, &clientProcess);
12 |
13 |
14 | // get address of output buffer
15 | BOOLEAN isWow64 = (PsGetProcessWow64Process(TargetProcess) != NULL) ? TRUE : FALSE;
16 | UNICODE_STRING clientprocessName;
17 | RtlInitUnicodeString(&clientprocessName, systemBuffer->currentmoduleName);
18 |
19 | DWORD64 gameBaseAddress = 0;
20 | BOOLEAN isclientWow64 = (PsGetProcessWow64Process(clientProcess) != NULL) ? TRUE : FALSE;
21 | UNICODE_STRING processName;
22 |
23 | RtlInitUnicodeString(&processName, systemBuffer->targetmoduleName);
24 |
25 |
26 | KAPC_STATE apc;
27 | KeStackAttachProcess(TargetProcess, &apc);
28 |
29 |
30 | gameBaseAddress = (ULONG64)GetUserModule(TargetProcess, &processName, isWow64);
31 | GameBaseAddress = gameBaseAddress;
32 |
33 |
34 | KeUnstackDetachProcess(&apc);
35 |
36 | if (gameBaseAddress == 0)
37 | {
38 | gameBaseAddress = 0x400000;
39 | }
40 |
41 | KeStackAttachProcess(clientProcess, &apc);
42 |
43 |
44 | DWORD64 clientBaseAddress = (ULONG64)GetUserModule(clientProcess, &clientprocessName, isclientWow64); //BSOD (sometimes)
45 |
46 | ClientBaseAddress = clientBaseAddress;
47 |
48 | UCHAR pattern[] = { 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4 };
49 | UINT64 realPattern = 0xFFFF8F08F280E084;
50 | RtlCopyMemory(pattern, (PVOID64)&realPattern, sizeof(UINT64));
51 | BBScanSection(".data", pattern, 0xCC, sizeof(UINT64), reinterpret_cast(&readOutputAddress), (PVOID64)ClientBaseAddress, TRUE);
52 |
53 | readOutputAddress += 8;
54 |
55 | RtlCopyMemory(&readOutputAddress, (PVOID64)readOutputAddress, sizeof(DWORD64));
56 |
57 | DbgPrint("initProcess(): Buffer Address is: %p \n", readOutputAddress);
58 |
59 | RtlCopyMemory((PVOID64)readOutputAddress, &GameBaseAddress, sizeof(GameBaseAddress));
60 |
61 |
62 | KeUnstackDetachProcess(&apc);
63 |
64 | ClientBaseAddress = clientBaseAddress;
65 |
66 | DbgPrint("reached 1 \n");
67 |
68 | return gameBaseAddress;
69 | }
70 |
71 | void exitProcessFunction()
72 | {
73 | if (clientProcess)
74 | {
75 | ObDereferenceObject(clientProcess);
76 | }
77 | if (TargetProcess)
78 | {
79 | ObDereferenceObject(TargetProcess);
80 | }
81 | }
82 |
83 |
84 | void EVERYTHINGhandler(communicationStruct* SystemBuffer)
85 | {
86 | SystemBuffer = (communicationStruct*)(((PIRP)interceptedIRP)->AssociatedIrp.SystemBuffer);
87 |
88 | DWORD64 result;
89 | KFLOATING_SAVE saveData;
90 | KAPC_STATE apcState;
91 | KeSaveFloatingPointState(&saveData);
92 | switch (SystemBuffer->commandID)
93 | {
94 | case CleanTraces:
95 | clearKdmapperTraces(); /* clear traces */
96 | break;
97 | case ReadMemoryCommand:
98 | ReadMemory(SystemBuffer->address, (PVOID)&SystemBuffer->buffer, SystemBuffer->size, TargetProcess, clientProcess, (PVOID)readOutputAddress); /* Read memory */
99 | break;
100 | case WriteMemorycommand:
101 | WriteMemory(SystemBuffer->address, (PVOID)&SystemBuffer->buffer, SystemBuffer->size, TargetProcess); /* Write memory */
102 | break;
103 | case initProcessInfoCommand:
104 | GameBaseAddress = initProcess((HANDLE)SystemBuffer->processID, (HANDLE)SystemBuffer->address, SystemBuffer);
105 | break; /* setup required info (and sig scan) */
106 | case sigScanCommand:
107 |
108 | KeStackAttachProcess(TargetProcess, &apcState);
109 | BBScanSection(SystemBuffer->section, SystemBuffer->buffer, SystemBuffer->wildCard, SystemBuffer->size,
110 | (PVOID64*)&SystemBuffer->address, (PVOID64)GameBaseAddress, SystemBuffer->dataOnly);
111 | KeUnstackDetachProcess(&apcState);
112 |
113 | WriteMemory(readOutputAddress, &SystemBuffer->address, sizeof(DWORD64), clientProcess);
114 | break;
115 | case resolveAddressCommand:
116 | KeStackAttachProcess(TargetProcess, &apcState);
117 | result = (DWORD64)ResolveRelativeAddress((PVOID)SystemBuffer->address, *(int*)(SystemBuffer->buffer), SystemBuffer->size);
118 | KeUnstackDetachProcess(&apcState);
119 | WriteMemory(readOutputAddress, &result, sizeof(DWORD64), clientProcess);
120 | break;
121 | case testCommand:
122 | DbgPrint("test command called\n");
123 | break;
124 | case exitProcess:
125 | exitProcessFunction();
126 | break;
127 | default:
128 | break;
129 | }
130 |
131 | KeRestoreFloatingPointState(&saveData);
132 | return;
133 | }
134 |
135 |
136 | #pragma optimize("", off)
137 | // handles EVERY COMMAND
138 | void EVERYTHING()
139 | {
140 |
141 | // here we get command from IRP system buffer (RSI)
142 | int a1 = 5;
143 | int a2 = 5;
144 | int a3 = 5; // 32 free bytes
145 | int a4 = 5;
146 |
147 | EVERYTHINGhandler(SystemBuffer);
148 |
149 | // hook my own function like a nigga because microsoft wont let me use inline asm
150 | // padding for the shellcode
151 | int a5 = 5;
152 | int a6 = 5; // 32 free bytes
153 | int a7 = 5;
154 | int a8 = 5;
155 | DbgPrint("EVERYTHING failed to return\n");
156 | }
157 | #pragma optimize("", on)
158 |
159 |
160 |
161 |
162 |
163 |
164 | // hook my own function like a nigga because microsoft wont let me use inline asm
165 | BOOLEAN PlaceEverythingHook()
166 | {
167 | ULONG diskSysSize;
168 | PVOID diskSysBase = getDiskSysBase(&diskSysSize);
169 |
170 | ULONG64 returnPlaceOfIOCTL = (ULONG64)diskSysBase + 0x112E;
171 |
172 | //grab values from rsi and r14 (device object and pirp)
173 |
174 | ULONG64 handlerPointer = (ULONG64)(PVOID64)EVERYTHING;
175 | handlerPointer += 48; //skip past dbgprint
176 |
177 | UCHAR shellCode[] = "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xE0";
178 |
179 | ULONG64 jumpAddress = (ULONG64)(PVOID64)returnPlaceOfIOCTL;
180 |
181 | memcpy(shellCode + 2, &jumpAddress, 8); // copy address into shellcode
182 |
183 |
184 |
185 |
186 |
187 |
188 | /*
189 | get value from r14 and pop into interceptedIRP variable
190 | 14 bytes required
191 |
192 | 41 56 push r14
193 | 48 b8 00 00 00 00 00 00 00 00 mov rax, &interceptedIRP
194 | 8f 00 pop[rax]
195 | */
196 |
197 |
198 | UCHAR shellCodeForR14[] = "\x56\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x00\x90\x90";
199 | PVOID64 iinterceptedIRP = &interceptedIRP;
200 | memcpy(shellCodeForR14 + 3, (PVOID64)(&iinterceptedIRP), 8); //has to be 3 if its push rsi
201 |
202 | DbgPrint("address of intercepted IRP pointer is: %p \n", (ULONG64)&interceptedIRP);
203 |
204 | if (MmIsAddressValid((PVOID)handlerPointer) && MmIsAddressValid((PVOID)(handlerPointer + sizeof(shellCode) - 1)))
205 | {
206 | KIRQL tempirql = KeRaiseIrqlToDpcLevel();
207 |
208 | ULONG64 cr0 = __readcr0();
209 |
210 | cr0 &= 0xfffffffffffeffff;
211 |
212 | __writecr0(cr0);
213 |
214 | _disable();
215 |
216 | RtlCopyMemory((PVOID)handlerPointer, shellCode, 12);
217 |
218 | handlerPointer = (ULONG64)(PVOID64)EVERYTHING;
219 |
220 | handlerPointer += 21; // should be 20 if it is push r14, 21 if its push rsi
221 |
222 | RtlCopyMemory((PVOID)handlerPointer, shellCodeForR14, sizeof(shellCodeForR14) - 1);
223 | cr0 = __readcr0();
224 |
225 | cr0 |= 0x10000;
226 |
227 | _enable();
228 |
229 | __writecr0(cr0);
230 |
231 | KeLowerIrql(tempirql);
232 | }
233 | return TRUE;
234 |
235 |
236 | }
237 |
238 |
239 |
240 | BOOLEAN PlaceDiskHook()
241 | {
242 | // Setup all the require info
243 |
244 | ULONG diskSysSize;
245 | PVOID diskSysBase = getDiskSysBase(&diskSysSize);
246 |
247 |
248 |
249 | //DiskIoctlVerify
250 | ULONG64 hookLocation = (ULONG64)diskSysBase + 0x2D90;
251 |
252 |
253 | // "\x48\xB8" EVERYTHING address "\xFF\xE0";
254 | //mov rax, EVERYTHING
255 | //jmp rax
256 |
257 |
258 | BYTE shellCode[] = { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0 };
259 |
260 | ULONG64 jumpAddress = (ULONG64)(PVOID64)EVERYTHING;
261 | jumpAddress += 21; // skip sub rsp and padding (should be 20 if you push r14 instead)
262 |
263 | memcpy(shellCode + 2, &jumpAddress, 8);
264 |
265 |
266 |
267 | //for now we will write without using write function because we don't want to attach to any process
268 |
269 | if (MmIsAddressValid((PVOID)hookLocation) && MmIsAddressValid((PVOID)(hookLocation + sizeof(shellCode) - 1)))
270 | {
271 | KIRQL tempirql = KeRaiseIrqlToDpcLevel();
272 |
273 | ULONG64 cr0 = __readcr0();
274 |
275 | cr0 &= 0xfffffffffffeffff;
276 |
277 | __writecr0(cr0);
278 |
279 | _disable();
280 |
281 | RtlCopyMemory((PVOID64)hookLocation, shellCode, 12);
282 |
283 | cr0 = __readcr0();
284 |
285 | cr0 |= 0x10000;
286 |
287 | _enable();
288 |
289 | __writecr0(cr0);
290 |
291 | KeLowerIrql(tempirql);
292 | }
293 | return TRUE;
294 |
295 | }
296 |
297 |
298 |
299 | /*
300 | loc_2D90:
301 | 48 8B D6 mov rdx, rsi
302 | 49 8B CE mov rcx, r14 ; DeviceObject
303 | E8 C9 15 00 00 call DiskIoctlVerify
304 | 90 nop
305 | E9 8D E3 FF FF jmp loc_112E
306 | */
307 |
308 | extern "C"
309 | NTSTATUS DriverEntry(_In_ _DRIVER_OBJECT * DriverObject, _In_ PUNICODE_STRING RegistryPath)
310 | {
311 | NTSTATUS Status = STATUS_SUCCESS;
312 | UNREFERENCED_PARAMETER(DriverObject);
313 | UNREFERENCED_PARAMETER(RegistryPath);
314 | ULONG sizeOfModule;
315 | PlaceDiskHook();
316 | PlaceEverythingHook();
317 | return Status;
318 | }
319 |
320 |
321 |
322 | NTSTATUS DriverA(_In_ _DRIVER_OBJECT* DriverObject, _In_ PUNICODE_STRING RegistryPath)
323 | {
324 | DbgPrint("driver start \n");
325 | NTSTATUS Status = STATUS_SUCCESS;
326 | BOOLEAN ClearStatus;
327 |
328 |
329 | UNREFERENCED_PARAMETER(DriverObject);
330 | UNREFERENCED_PARAMETER(RegistryPath);
331 | DriverEntry(NULL, NULL);
332 | return Status;
333 | }
334 |
--------------------------------------------------------------------------------
/Undocumented.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 |
9 |
10 | #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
11 |
12 | #define FLT_MAX 3.402823466e+38F /* max value */
13 | extern "C" int _fltused = 0;
14 |
15 |
16 |
17 | extern "C" __declspec(dllimport)
18 | NTSTATUS NTAPI MmCopyVirtualMemory
19 | (
20 | PEPROCESS SourceProcess,
21 | PVOID SourceAddress,
22 | PEPROCESS TargetProcess,
23 | PVOID TargetAddress,
24 | SIZE_T BufferSize,
25 | KPROCESSOR_MODE PreviousMode,
26 | PSIZE_T ReturnSize
27 | );
28 |
29 | typedef struct _IMAGE_DATA_DIRECTORY
30 | {
31 | ULONG VirtualAddress;
32 | ULONG Size;
33 | } IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY;
34 |
35 |
36 |
37 | typedef enum _SYSTEM_INFORMATION_CLASS
38 | {
39 | SystemBasicInformation = 0,
40 | SystemProcessorInformation = 1, // obsolete...delete
41 | SystemPerformanceInformation = 2,
42 | SystemTimeOfDayInformation = 3,
43 | SystemPathInformation = 4,
44 | SystemProcessInformation = 5,
45 | SystemCallCountInformation = 6,
46 | SystemDeviceInformation = 7,
47 | SystemProcessorPerformanceInformation = 8,
48 | SystemFlagsInformation = 9,
49 | SystemCallTimeInformation = 10,
50 | SystemModuleInformation = 11,
51 | SystemLocksInformation = 12,
52 | SystemStackTraceInformation = 13,
53 | SystemPagedPoolInformation = 14,
54 | SystemNonPagedPoolInformation = 15,
55 | SystemHandleInformation = 16,
56 | SystemObjectInformation = 17,
57 | SystemPageFileInformation = 18,
58 | SystemVdmInstemulInformation = 19,
59 | SystemVdmBopInformation = 20,
60 | SystemFileCacheInformation = 21,
61 | SystemPoolTagInformation = 22,
62 | SystemInterruptInformation = 23,
63 | SystemDpcBehaviorInformation = 24,
64 | SystemFullMemoryInformation = 25,
65 | SystemLoadGdiDriverInformation = 26,
66 | SystemUnloadGdiDriverInformation = 27,
67 | SystemTimeAdjustmentInformation = 28,
68 | SystemSummaryMemoryInformation = 29,
69 | SystemMirrorMemoryInformation = 30,
70 | SystemPerformanceTraceInformation = 31,
71 | SystemObsolete0 = 32,
72 | SystemExceptionInformation = 33,
73 | SystemCrashDumpStateInformation = 34,
74 | SystemKernelDebuggerInformation = 35,
75 | SystemContextSwitchInformation = 36,
76 | SystemRegistryQuotaInformation = 37,
77 | SystemExtendServiceTableInformation = 38,
78 | SystemPrioritySeperation = 39,
79 | SystemVerifierAddDriverInformation = 40,
80 | SystemVerifierRemoveDriverInformation = 41,
81 | SystemProcessorIdleInformation = 42,
82 | SystemLegacyDriverInformation = 43,
83 | SystemCurrentTimeZoneInformation = 44,
84 | SystemLookasideInformation = 45,
85 | SystemTimeSlipNotification = 46,
86 | SystemSessionCreate = 47,
87 | SystemSessionDetach = 48,
88 | SystemSessionInformation = 49,
89 | SystemRangeStartInformation = 50,
90 | SystemVerifierInformation = 51,
91 | SystemVerifierThunkExtend = 52,
92 | SystemSessionProcessInformation = 53,
93 | SystemLoadGdiDriverInSystemSpace = 54,
94 | SystemNumaProcessorMap = 55,
95 | SystemPrefetcherInformation = 56,
96 | SystemExtendedProcessInformation = 57,
97 | SystemRecommendedSharedDataAlignment = 58,
98 | SystemComPlusPackage = 59,
99 | SystemNumaAvailableMemory = 60,
100 | SystemProcessorPowerInformation = 61,
101 | SystemEmulationBasicInformation = 62,
102 | SystemEmulationProcessorInformation = 63,
103 | SystemExtendedHandleInformation = 64,
104 | SystemLostDelayedWriteInformation = 65,
105 | SystemBigPoolInformation = 66,
106 | SystemSessionPoolTagInformation = 67,
107 | SystemSessionMappedViewInformation = 68,
108 | SystemHotpatchInformation = 69,
109 | SystemObjectSecurityMode = 70,
110 | SystemWatchdogTimerHandler = 71,
111 | SystemWatchdogTimerInformation = 72,
112 | SystemLogicalProcessorInformation = 73,
113 | SystemWow64SharedInformation = 74,
114 | SystemRegisterFirmwareTableInformationHandler = 75,
115 | SystemFirmwareTableInformation = 76,
116 | SystemModuleInformationEx = 77,
117 | SystemVerifierTriageInformation = 78,
118 | SystemSuperfetchInformation = 79,
119 | SystemMemoryListInformation = 80,
120 | SystemFileCacheInformationEx = 81,
121 | MaxSystemInfoClass = 82 // MaxSystemInfoClass should always be the last enum
122 |
123 | } SYSTEM_INFORMATION_CLASS;
124 |
125 |
126 | typedef struct _SYSTEM_THREADS
127 | {
128 | LARGE_INTEGER KernelTime;
129 | LARGE_INTEGER UserTime;
130 | LARGE_INTEGER CreateTime;
131 | ULONG WaitTime;
132 | PVOID StartAddress;
133 | CLIENT_ID ClientID;
134 | KPRIORITY Priority;
135 | KPRIORITY BasePriority;
136 | ULONG ContextSwitchCount;
137 | ULONG ThreadState;
138 | KWAIT_REASON WaitReason;
139 | ULONG Reserved; //Add
140 | }SYSTEM_THREADS, * PSYSTEM_THREADS;
141 |
142 |
143 | typedef struct _SYSTEM_PROCESS_INFORMATION {
144 | ULONG NextEntryOffset;
145 | ULONG NumberOfThreads;
146 | LARGE_INTEGER Reserved[3];
147 | LARGE_INTEGER CreateTime;
148 | LARGE_INTEGER UserTime;
149 | LARGE_INTEGER KernelTime;
150 | UNICODE_STRING ImageName;
151 | KPRIORITY BasePriority;
152 | HANDLE ProcessId;
153 | HANDLE InheritedFromProcessId;
154 | ULONG HandleCount;
155 | ULONG Reserved2[2];
156 | ULONG PrivatePageCount;
157 | VM_COUNTERS VirtualMemoryCounters;
158 | IO_COUNTERS IoCounters;
159 | SYSTEM_THREADS Threads[1];
160 | } SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;
161 |
162 |
163 | typedef struct _PEB32
164 | {
165 | UCHAR InheritedAddressSpace;
166 | UCHAR ReadImageFileExecOptions;
167 | UCHAR BeingDebugged;
168 | UCHAR BitField;
169 | ULONG Mutant;
170 | ULONG ImageBaseAddress;
171 | ULONG Ldr;
172 | ULONG ProcessParameters;
173 | ULONG SubSystemData;
174 | ULONG ProcessHeap;
175 | ULONG FastPebLock;
176 | ULONG AtlThunkSListPtr;
177 | ULONG IFEOKey;
178 | ULONG CrossProcessFlags;
179 | ULONG UserSharedInfoPtr;
180 | ULONG SystemReserved;
181 | ULONG AtlThunkSListPtr32;
182 | ULONG ApiSetMap;
183 | } PEB32, * PPEB32;
184 |
185 |
186 | typedef struct _PEB_LDR_DATA32
187 | {
188 | ULONG Length;
189 | UCHAR Initialized;
190 | ULONG SsHandle;
191 | LIST_ENTRY32 InLoadOrderModuleList;
192 | LIST_ENTRY32 InMemoryOrderModuleList;
193 | LIST_ENTRY32 InInitializationOrderModuleList;
194 | } PEB_LDR_DATA32, * PPEB_LDR_DATA32;
195 |
196 |
197 | typedef struct _LDR_DATA_TABLE_ENTRY
198 | {
199 | LIST_ENTRY InLoadOrderLinks;
200 | LIST_ENTRY InMemoryOrderLinks;
201 | LIST_ENTRY InInitializationOrderLinks;
202 | PVOID DllBase;
203 | PVOID EntryPoint;
204 | ULONG SizeOfImage;
205 | UNICODE_STRING FullDllName;
206 | UNICODE_STRING BaseDllName;
207 | ULONG Flags;
208 | USHORT LoadCount;
209 | USHORT TlsIndex;
210 | LIST_ENTRY HashLinks;
211 | ULONG TimeDateStamp;
212 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
213 | typedef struct _LDR_DATA_TABLE_ENTRY32
214 | {
215 | LIST_ENTRY32 InLoadOrderLinks;
216 | LIST_ENTRY32 InMemoryOrderLinks;
217 | LIST_ENTRY32 InInitializationOrderLinks;
218 | ULONG DllBase;
219 | ULONG EntryPoint;
220 | ULONG SizeOfImage;
221 | UNICODE_STRING32 FullDllName;
222 | UNICODE_STRING32 BaseDllName;
223 | ULONG Flags;
224 | USHORT LoadCount;
225 | USHORT TlsIndex;
226 | LIST_ENTRY32 HashLinks;
227 | ULONG TimeDateStamp;
228 | } LDR_DATA_TABLE_ENTRY32, * PLDR_DATA_TABLE_ENTRY32;
229 |
230 | typedef struct _PEB_LDR_DATA
231 | {
232 | ULONG Length;
233 | UCHAR Initialized;
234 | PVOID SsHandle;
235 | LIST_ENTRY InLoadOrderModuleList;
236 | LIST_ENTRY InMemoryOrderModuleList;
237 | LIST_ENTRY InInitializationOrderModuleList;
238 | } PEB_LDR_DATA, * PPEB_LDR_DATA;
239 |
240 | typedef struct _PEB
241 | {
242 | UCHAR InheritedAddressSpace;
243 | UCHAR ReadImageFileExecOptions;
244 | UCHAR BeingDebugged;
245 | UCHAR BitField;
246 | PVOID Mutant;
247 | PVOID ImageBaseAddress;
248 | PPEB_LDR_DATA Ldr;
249 | PVOID ProcessParameters;
250 | PVOID SubSystemData;
251 | PVOID ProcessHeap;
252 | PVOID FastPebLock;
253 | PVOID AtlThunkSListPtr;
254 | PVOID IFEOKey;
255 | PVOID CrossProcessFlags;
256 | PVOID KernelCallbackTable;
257 | ULONG SystemReserved;
258 | ULONG AtlThunkSListPtr32;
259 | PVOID ApiSetMap;
260 | } PEB, * PPEB;
261 |
262 | typedef struct PiDDBCacheEntry
263 | {
264 | LIST_ENTRY List;
265 | UNICODE_STRING DriverName;
266 | ULONG TimeDateStamp;
267 | NTSTATUS LoadStatus;
268 | char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers
269 | }PIDCacheobj;
270 |
271 | typedef struct _RTL_PROCESS_MODULE_INFORMATION
272 | {
273 | HANDLE Section; // Not filled in
274 | PVOID MappedBase;
275 | PVOID ImageBase;
276 | ULONG ImageSize;
277 | ULONG Flags;
278 | USHORT LoadOrderIndex;
279 | USHORT InitOrderIndex;
280 | USHORT LoadCount;
281 | USHORT OffsetToFileName;
282 | UCHAR FullPathName[MAXIMUM_FILENAME_LENGTH];
283 | } RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
284 |
285 |
286 | typedef struct _RTL_PROCESS_MODULES
287 | {
288 | ULONG NumberOfModules;
289 | RTL_PROCESS_MODULE_INFORMATION Modules[1];
290 | } RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
291 |
292 | typedef struct _IMAGE_SECTION_HEADER {
293 | BYTE Name[8];
294 | union {
295 | DWORD PhysicalAddress;
296 | DWORD VirtualSize;
297 | } Misc;
298 | DWORD VirtualAddress;
299 | DWORD SizeOfRawData;
300 | DWORD PointerToRawData;
301 | DWORD PointerToRelocations;
302 | DWORD PointerToLinenumbers;
303 | WORD NumberOfRelocations;
304 | WORD NumberOfLinenumbers;
305 | DWORD Characteristics;
306 | } IMAGE_SECTION_HEADER, * PIMAGE_SECTION_HEADER;
307 |
308 |
309 | typedef struct _IMAGE_FILE_HEADER // Size=20
310 | {
311 | USHORT Machine;
312 | USHORT NumberOfSections;
313 | ULONG TimeDateStamp;
314 | ULONG PointerToSymbolTable;
315 | ULONG NumberOfSymbols;
316 | USHORT SizeOfOptionalHeader;
317 | USHORT Characteristics;
318 | } IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER;
319 |
320 | typedef struct _IMAGE_OPTIONAL_HEADER64
321 | {
322 | USHORT Magic;
323 | UCHAR MajorLinkerVersion;
324 | UCHAR MinorLinkerVersion;
325 | ULONG SizeOfCode;
326 | ULONG SizeOfInitializedData;
327 | ULONG SizeOfUninitializedData;
328 | ULONG AddressOfEntryPoint;
329 | ULONG BaseOfCode;
330 | ULONGLONG ImageBase;
331 | ULONG SectionAlignment;
332 | ULONG FileAlignment;
333 | USHORT MajorOperatingSystemVersion;
334 | USHORT MinorOperatingSystemVersion;
335 | USHORT MajorImageVersion;
336 | USHORT MinorImageVersion;
337 | USHORT MajorSubsystemVersion;
338 | USHORT MinorSubsystemVersion;
339 | ULONG Win32VersionValue;
340 | ULONG SizeOfImage;
341 | ULONG SizeOfHeaders;
342 | ULONG CheckSum;
343 | USHORT Subsystem;
344 | USHORT DllCharacteristics;
345 | ULONGLONG SizeOfStackReserve;
346 | ULONGLONG SizeOfStackCommit;
347 | ULONGLONG SizeOfHeapReserve;
348 | ULONGLONG SizeOfHeapCommit;
349 | ULONG LoaderFlags;
350 | ULONG NumberOfRvaAndSizes;
351 | struct _IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
352 | } IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64;
353 |
354 |
355 |
356 | typedef struct _MM_UNLOADED_DRIVER
357 | {
358 | UNICODE_STRING Name;
359 | PVOID ModuleStart;
360 | PVOID ModuleEnd;
361 | ULONG64 UnloadTime;
362 | } MM_UNLOADED_DRIVER, * PMM_UNLOADED_DRIVER;
363 |
364 |
365 |
366 |
367 | typedef struct _IMAGE_NT_HEADERS64 {
368 | DWORD Signature;
369 | IMAGE_FILE_HEADER FileHeader;
370 | IMAGE_OPTIONAL_HEADER64 OptionalHeader;
371 | } IMAGE_NT_HEADERS64, * PIMAGE_NT_HEADERS64;
372 |
373 |
374 | EXTERN_C NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(
375 | IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
376 | OUT PVOID SystemInformation,
377 | IN ULONG SystemInformationLength,
378 | OUT PULONG ReturnLength OPTIONAL
379 | );
380 |
381 | EXTERN_C NTKERNELAPI PVOID NTAPI PsGetProcessWow64Process(
382 | _In_ PEPROCESS Process
383 | );
384 |
385 | EXTERN_C NTKERNELAPI PPEB NTAPI PsGetProcessPeb(IN PEPROCESS Process);
386 |
387 | EXTERN_C
388 | NTSYSAPI
389 | PIMAGE_NT_HEADERS
390 | NTAPI
391 | RtlImageNtHeader(
392 | IN PVOID ModuleAddress);
--------------------------------------------------------------------------------
/KernelUtils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #pragma once
5 | #include "Undocumented.h"
6 | #include
7 |
8 |
9 |
10 |
11 | #define MM_UNLOADED_DRIVERS_SIZE 50
12 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
13 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
14 | #define IMAGE_SCN_CNT_CODE 0x00000020
15 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000
16 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
17 | #define IMAGE_NT_SIGNATURE 0x00004550
18 | #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
19 | #define STANDARD_RIGHTS_ALL 0x001F0000L
20 |
21 |
22 |
23 |
24 |
25 | ULONG KernelSize;
26 | PVOID KernelBase;
27 | PVOID getKernelBase(OUT PULONG pSize)
28 | {
29 | NTSTATUS Status = STATUS_SUCCESS;
30 | ULONG Bytes = 0;
31 | PRTL_PROCESS_MODULES arrayOfModules;
32 | PVOID routinePtr = NULL; /*RoutinePtr points to a
33 | routine and checks if it is in Ntoskrnl*/
34 |
35 | UNICODE_STRING routineName;
36 |
37 | if (KernelBase != NULL)
38 | {
39 | if (pSize)
40 | *pSize = KernelSize;
41 | return KernelBase;
42 | }
43 |
44 | RtlUnicodeStringInit(&routineName, L"NtOpenFile");
45 | routinePtr = MmGetSystemRoutineAddress(&routineName); //get address of NtOpenFile
46 |
47 |
48 | if (routinePtr == NULL)
49 | {
50 | return NULL;
51 | }
52 | else
53 | {
54 |
55 | DbgPrint("MmGetSystemRoutineAddress inside getkernelbase succeed\n");
56 | }
57 |
58 |
59 | //get size of system module information
60 | Status = ZwQuerySystemInformation(SystemModuleInformation, 0, Bytes, &Bytes);
61 | if (Bytes == 0)
62 | {
63 | DbgPrint("%s: Invalid SystemModuleInformation size\n");
64 | return NULL;
65 | }
66 |
67 |
68 | arrayOfModules = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPool, Bytes, 0x454E4F45); //array of loaded kernel modules
69 | RtlZeroMemory(arrayOfModules, Bytes); //clean memory
70 |
71 |
72 | Status = ZwQuerySystemInformation(SystemModuleInformation, arrayOfModules, Bytes, &Bytes);
73 | if (NT_SUCCESS(Status))
74 | {
75 | DbgPrint("ZwQuerySystemInformation inside getkernelbase succeed\n");
76 | PRTL_PROCESS_MODULE_INFORMATION pMod = arrayOfModules->Modules;
77 | for (int i = 0; i < arrayOfModules->NumberOfModules; ++i)
78 | {
79 |
80 | if (routinePtr >= pMod[i].ImageBase && routinePtr < (PVOID)((PUCHAR)pMod[i].ImageBase + pMod[i].ImageSize))
81 | {
82 |
83 | KernelBase = pMod[i].ImageBase;
84 | KernelSize = pMod[i].ImageSize;
85 |
86 | if (pSize)
87 | *pSize = KernelSize;
88 | break;
89 | }
90 | }
91 | }
92 | if (arrayOfModules)
93 | ExFreePoolWithTag(arrayOfModules, 0x454E4F45); // 'ENON'
94 |
95 | DbgPrint("KernelSize : %i\n", KernelSize);
96 | DbgPrint("g_KernelBase : %p\n", KernelBase);
97 | return (PVOID)KernelBase;
98 | }
99 |
100 |
101 |
102 |
103 | PVOID getDiskSysBase(OUT PULONG pSize)
104 | {
105 | NTSTATUS Status = STATUS_SUCCESS;
106 | ULONG Bytes = 0;
107 | PRTL_PROCESS_MODULES arrayOfModules;
108 |
109 |
110 |
111 | PVOID diskSysBase = 0;
112 | ULONG64 DiskSysSize = 0;
113 |
114 |
115 |
116 | //get size of system module information
117 | Status = ZwQuerySystemInformation(SystemModuleInformation, 0, Bytes, &Bytes);
118 | if (Bytes == 0)
119 | {
120 | DbgPrint("%s: Invalid SystemModuleInformation size\n");
121 | return NULL;
122 | }
123 |
124 |
125 | arrayOfModules = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPool, Bytes, 0x45454545); //array of loaded kernel modules
126 | RtlZeroMemory(arrayOfModules, Bytes); //clean memory
127 |
128 |
129 | Status = ZwQuerySystemInformation(SystemModuleInformation, arrayOfModules, Bytes, &Bytes);
130 |
131 | if (NT_SUCCESS(Status))
132 | {
133 | DbgPrint("ZwQuerySystemInformation inside getkernelbase succeed\n");
134 | PRTL_PROCESS_MODULE_INFORMATION pMod = arrayOfModules->Modules;
135 | for (int i = 0; i < arrayOfModules->NumberOfModules; ++i)
136 | {
137 | //list the module names:
138 |
139 | DbgPrint("Image name: %s\n", pMod[i].FullPathName + pMod[i].OffsetToFileName);
140 | // path name plus some amount of characters will lead to the name itself
141 | const char* DriverName = (const char*)pMod[i].FullPathName + pMod[i].OffsetToFileName;
142 |
143 | if (strcmp(DriverName, "disk.sys") == 0)
144 | {
145 | DbgPrint("found disk.sys\n");
146 |
147 |
148 | diskSysBase = pMod[i].ImageBase;
149 | DiskSysSize = pMod[i].ImageSize;
150 |
151 | DbgPrint("Disk.sys Size : %i\n", DiskSysSize);
152 | DbgPrint("Disk.sys Base : %p\n", diskSysBase);
153 |
154 |
155 | if (arrayOfModules)
156 | ExFreePoolWithTag(arrayOfModules, 0x45454545); // 'ENON'
157 |
158 |
159 |
160 |
161 | *pSize = DiskSysSize;
162 | return diskSysBase;
163 | }
164 | }
165 | }
166 | if (arrayOfModules)
167 | ExFreePoolWithTag(arrayOfModules, 0x45454545); // 'ENON'
168 |
169 |
170 |
171 | *pSize = DiskSysSize;
172 | return (PVOID)diskSysBase;
173 | }
174 |
175 |
176 |
177 |
178 |
179 | NTSTATUS BBSearchPattern(IN PCUCHAR pattern, IN UCHAR wildcard, IN ULONG_PTR len, IN const VOID* base, IN ULONG_PTR size, OUT PVOID* ppFound)
180 | {
181 | ASSERT(ppFound != NULL && pattern != NULL && base != NULL);
182 | if (ppFound == NULL || pattern == NULL || base == NULL)
183 | return STATUS_INVALID_PARAMETER;
184 |
185 | for (ULONG_PTR i = 0; i < size - len; i++)
186 | {
187 | BOOLEAN found = TRUE;
188 | for (ULONG_PTR j = 0; j < len; j++)
189 | {
190 | if (pattern[j] != wildcard && pattern[j] != ((PCUCHAR)base)[i + j])
191 | {
192 | found = FALSE;
193 | break;
194 | }
195 | }
196 |
197 | if (found != FALSE)
198 | {
199 | *ppFound = (PUCHAR)base + i;
200 | return STATUS_SUCCESS;
201 | }
202 | }
203 |
204 | return STATUS_NOT_FOUND;
205 | }
206 |
207 |
208 |
209 | NTSTATUS BBScanSection(IN PCCHAR section, IN PCUCHAR pattern, IN UCHAR wildcard, IN ULONG_PTR len, OUT PVOID* ppFound, PVOID base = nullptr, BOOLEAN dataOnly = FALSE)
210 | {
211 |
212 | //ASSERT(ppFound != NULL);
213 | if (ppFound == NULL)
214 | return STATUS_ACCESS_DENIED; //STATUS_INVALID_PARAMETER
215 |
216 | if (nullptr == base)
217 | base = getKernelBase(NULL);
218 | if (base == nullptr)
219 | return STATUS_ACCESS_DENIED; //STATUS_NOT_FOUND;
220 |
221 | PIMAGE_NT_HEADERS64 pHdr = (PIMAGE_NT_HEADERS64)RtlImageNtHeader(base);
222 | if (!pHdr)
223 | return STATUS_ACCESS_DENIED; // STATUS_INVALID_IMAGE_FORMAT;
224 |
225 | //PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)(pHdr + 1);
226 | PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)((uintptr_t)&pHdr->FileHeader + pHdr->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER));
227 |
228 | PVOID ptr = NULL;
229 |
230 | for (PIMAGE_SECTION_HEADER pSection = pFirstSection; pSection < pFirstSection + pHdr->FileHeader.NumberOfSections; pSection++)
231 | {
232 |
233 | ANSI_STRING s1, s2;
234 | RtlInitAnsiString(&s1, section);
235 | RtlInitAnsiString(&s2, (PCCHAR)pSection->Name);
236 | if ((dataOnly == FALSE) && ((RtlCompareString(&s1, &s2, TRUE) == 0) || (pSection->Characteristics & IMAGE_SCN_CNT_CODE) || (pSection->Characteristics & IMAGE_SCN_MEM_EXECUTE)))
237 | {
238 |
239 | NTSTATUS status = BBSearchPattern(pattern, wildcard, len, (PUCHAR)base + pSection->VirtualAddress, pSection->Misc.VirtualSize, &ptr);
240 | if (NT_SUCCESS(status)) {
241 | *(PULONG64)ppFound = (ULONG_PTR)(ptr); //- (PUCHAR)base
242 | DbgPrint("found\r\n");
243 | return status;
244 | }
245 | //we continue scanning because there can be multiple sections with the same name.
246 | }
247 | else if ((dataOnly == TRUE) && (RtlCompareString(&s1, &s2, TRUE) == 0))
248 | {
249 | DbgPrint("valid section\r\n");
250 | ptr = NULL;
251 | NTSTATUS status = BBSearchPattern(pattern, wildcard, len, (PUCHAR)base + pSection->VirtualAddress, pSection->Misc.VirtualSize, &ptr);
252 | if (NT_SUCCESS(status)) {
253 | *(PULONG64)ppFound = (ULONG_PTR)(ptr); //- (PUCHAR)base
254 | DbgPrint("BBscansection(): found at address: %p ", *(PULONG64)ppFound);
255 | return status;
256 | }
257 | return status;
258 | //we continue scanning because there can be multiple sections with the same name.
259 | }
260 | }
261 |
262 | return STATUS_ACCESS_DENIED; //STATUS_NOT_FOUND;
263 | }
264 |
265 | PVOID ResolveRelativeAddress(
266 | _In_ PVOID Instruction,
267 | _In_ ULONG OffsetOffset,
268 | _In_ ULONG InstructionSize
269 | )
270 | {
271 | ULONG_PTR Instr = (ULONG_PTR)Instruction;
272 | LONG RipOffset = *(PLONG)(Instr + OffsetOffset);
273 | PVOID ResolvedAddr = (PVOID)(Instr + InstructionSize + RipOffset);
274 |
275 | return ResolvedAddr;
276 | }
277 |
278 |
279 |
280 |
281 |
282 | PVOID GetUserModule(IN PEPROCESS pProcess, IN PUNICODE_STRING ModuleName, IN BOOLEAN isWow64)
283 | {
284 | ASSERT(pProcess != NULL);
285 | if (pProcess == NULL)
286 | return NULL;
287 |
288 | // Protect from UserMode AV
289 | __try
290 | {
291 | LARGE_INTEGER time = { 0 };
292 | time.QuadPart = -250ll * 10 * 1000; // 250 msec.
293 |
294 | // Wow64 process
295 | if (isWow64)
296 | {
297 | PPEB32 pPeb32 = (PPEB32)PsGetProcessWow64Process(pProcess);
298 | if (pPeb32 == NULL)
299 | {
300 | return NULL;
301 | }
302 |
303 | // Wait for loader a bit
304 | for (INT i = 0; !pPeb32->Ldr && i < 10; i++)
305 | {
306 | KeDelayExecutionThread(KernelMode, TRUE, &time);
307 | }
308 |
309 | // Still no loader
310 | if (!pPeb32->Ldr)
311 | {
312 | return NULL;
313 | }
314 |
315 | // Search in InLoadOrderModuleList
316 | for (PLIST_ENTRY32 pListEntry = (PLIST_ENTRY32)((PPEB_LDR_DATA32)pPeb32->Ldr)->InLoadOrderModuleList.Flink;
317 | pListEntry != &((PPEB_LDR_DATA32)pPeb32->Ldr)->InLoadOrderModuleList;
318 | pListEntry = (PLIST_ENTRY32)pListEntry->Flink)
319 | {
320 | UNICODE_STRING ustr;
321 | PLDR_DATA_TABLE_ENTRY32 pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
322 |
323 | RtlUnicodeStringInit(&ustr, (PWCH)pEntry->BaseDllName.Buffer);
324 |
325 | if (RtlCompareUnicodeString(&ustr, ModuleName, TRUE) == 0)
326 | return (PVOID)pEntry->DllBase;
327 | }
328 | }
329 | // Native process
330 | else
331 | {
332 | PPEB pPeb = PsGetProcessPeb(pProcess);
333 | if (!pPeb)
334 | {
335 | return NULL;
336 | }
337 |
338 | // Wait for loader a bit
339 | for (INT i = 0; !pPeb->Ldr && i < 10; i++)
340 | {
341 | KeDelayExecutionThread(KernelMode, TRUE, &time);
342 | }
343 |
344 | // Still no loader
345 | if (!pPeb->Ldr)
346 | {
347 | return NULL;
348 | }
349 |
350 | // Search in InLoadOrderModuleList
351 | for (PLIST_ENTRY pListEntry = pPeb->Ldr->InLoadOrderModuleList.Flink;
352 | pListEntry != &pPeb->Ldr->InLoadOrderModuleList;
353 | pListEntry = pListEntry->Flink)
354 | {
355 | PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
356 | if (RtlCompareUnicodeString(&pEntry->BaseDllName, ModuleName, TRUE) == 0)
357 | return pEntry->DllBase;
358 | }
359 | }
360 | }
361 | __except (EXCEPTION_EXECUTE_HANDLER)
362 | {
363 | }
364 |
365 | return NULL;
366 | }
367 |
368 |
369 |
370 | HANDLE GetProcessPID(const wchar_t* NameOfProcess)
371 | {
372 | auto Status = STATUS_SUCCESS;
373 | UNICODE_STRING ClientName = { 0 };
374 | HANDLE processID = nullptr;
375 | PVOID SystemProcessInfo = nullptr;
376 | DWORD buffer_size = NULL;
377 |
378 |
379 |
380 | RtlInitUnicodeString(&ClientName, L"UserModeClient.exe");
381 | Status = ZwQuerySystemInformation(SystemProcessInformation, SystemProcessInfo, 0, &buffer_size);
382 | while (Status == STATUS_INFO_LENGTH_MISMATCH)
383 | {
384 | if (SystemProcessInfo) ExFreePool(SystemProcessInfo);
385 | SystemProcessInfo = ExAllocatePool(NonPagedPool, buffer_size);
386 | Status = ZwQuerySystemInformation(SystemProcessInformation, SystemProcessInfo, buffer_size, &buffer_size);
387 | }
388 | auto ProcessInformation = static_cast(SystemProcessInfo);
389 | for (;;)
390 | {
391 |
392 | if (FsRtlIsNameInExpression(&ClientName, &(ProcessInformation->ImageName), FALSE, NULL) == TRUE)
393 | {
394 | processID = ProcessInformation->ProcessId;
395 | break;
396 | }
397 |
398 | if (ProcessInformation->NextEntryOffset == 0)
399 | {
400 | break;
401 | }
402 | ProcessInformation = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)ProcessInformation) + ProcessInformation->NextEntryOffset);
403 | }
404 | ExFreePool(SystemProcessInfo);
405 | return processID;
406 |
407 | }
408 |
409 |
410 | struct readOutput
411 | {
412 | BYTE buffer[240];
413 | };
414 |
415 |
416 |
417 |
418 | VOID ReadMemory(ULONG64 address, PVOID buffer, SIZE_T size, PEPROCESS process, PEPROCESS clientProcess, PVOID readBufferAddress)
419 | {
420 | {
421 | KAPC_STATE apc_state;
422 | KeStackAttachProcess(process, &apc_state);
423 |
424 | if (MmIsAddressValid((PVOID64)address) && MmIsAddressValid((PVOID64)(address + size)))
425 | {
426 | RtlCopyMemory(buffer, (PVOID64)address, size);
427 | }
428 |
429 | KeUnstackDetachProcess(&apc_state);
430 | }
431 |
432 |
433 | KAPC_STATE apc_state;
434 | KeStackAttachProcess(clientProcess, &apc_state);
435 | if (MmIsAddressValid((PVOID)readBufferAddress))
436 | {
437 |
438 | KIRQL tempirql = KeRaiseIrqlToDpcLevel();
439 |
440 | ULONG64 cr0 = __readcr0();
441 |
442 | cr0 &= 0xfffffffffffeffff;
443 | __writecr0(cr0);
444 |
445 | _disable();
446 |
447 | RtlCopyMemory(readBufferAddress, buffer, size);
448 |
449 |
450 | cr0 = __readcr0();
451 |
452 | cr0 |= 0x10000;
453 |
454 | _enable();
455 |
456 | __writecr0(cr0);
457 |
458 | KeLowerIrql(tempirql);
459 | }
460 | else
461 | {
462 | DbgPrint("address invalid!!! tried to read memory at: %p \n", readBufferAddress);
463 | }
464 |
465 | KeUnstackDetachProcess(&apc_state);
466 |
467 | }
468 |
469 |
470 |
471 | VOID WriteMemory(ULONG64 address, PVOID buffer, SIZE_T size, PEPROCESS process)
472 | {
473 |
474 | KAPC_STATE apc_state;
475 | KeStackAttachProcess(process, &apc_state);
476 | if (MmIsAddressValid((PVOID)address) && MmIsAddressValid((PVOID)(address + size)))
477 | {
478 | KIRQL tempirql = KeRaiseIrqlToDpcLevel();
479 |
480 | ULONG64 cr0 = __readcr0();
481 |
482 | cr0 &= 0xfffffffffffeffff;
483 | __writecr0(cr0);
484 |
485 | _disable();
486 |
487 | RtlCopyMemory((PVOID64)address, buffer, size);
488 |
489 | cr0 = __readcr0();
490 |
491 | cr0 |= 0x10000;
492 |
493 | _enable();
494 |
495 | __writecr0(cr0);
496 |
497 | KeLowerIrql(tempirql);
498 | }
499 | KeUnstackDetachProcess(&apc_state);
500 |
501 | }
502 |
503 |
504 |
505 |
--------------------------------------------------------------------------------