├── .gitattributes
├── .gitignore
├── HandleMaster.sln
├── HandleMaster
├── HandleMaster.vcxproj
├── HandleMaster.vcxproj.filters
└── src
│ ├── drivers
│ └── cpuz
│ │ ├── cpuz_driver.cpp
│ │ ├── cpuz_driver.hpp
│ │ ├── cpuz_shellcode.cpp
│ │ └── cpuz_shellcode.h
│ ├── dyn_data.cpp
│ ├── dyn_data.hpp
│ ├── main.cpp
│ ├── process.cpp
│ ├── process.hpp
│ ├── scm.c
│ ├── scm.h
│ ├── sup.c
│ ├── sup.h
│ └── windefs.h
├── LICENSE
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/HandleMaster.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HandleMaster", "HandleMaster\HandleMaster.vcxproj", "{86B4176D-F752-413D-A0A0-57FCAD4059DB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Release|x64 = Release|x64
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {86B4176D-F752-413D-A0A0-57FCAD4059DB}.Debug|x64.ActiveCfg = Debug|x64
15 | {86B4176D-F752-413D-A0A0-57FCAD4059DB}.Debug|x64.Build.0 = Debug|x64
16 | {86B4176D-F752-413D-A0A0-57FCAD4059DB}.Release|x64.ActiveCfg = Release|x64
17 | {86B4176D-F752-413D-A0A0-57FCAD4059DB}.Release|x64.Build.0 = Release|x64
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/HandleMaster/HandleMaster.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 15.0
33 | {86B4176D-F752-413D-A0A0-57FCAD4059DB}
34 | Win32Proj
35 | HandleMaster
36 | 8.1
37 |
38 |
39 |
40 | Application
41 | true
42 | v140
43 | Unicode
44 |
45 |
46 | Application
47 | false
48 | v140
49 | true
50 | Unicode
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | true
66 | $(SolutionDir)bin\
67 | $(SolutionDir)build\$(Configuration)\$(Platform)\
68 | HandleMaster_d
69 |
70 |
71 | false
72 | $(SolutionDir)bin\
73 | $(SolutionDir)build\$(Configuration)\$(Platform)\
74 | HandleMaster
75 |
76 |
77 |
78 |
79 |
80 | Level3
81 | Disabled
82 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
83 | MultiThreadedDebug
84 |
85 |
86 | Console
87 | ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
88 | RequireAdministrator
89 |
90 |
91 |
92 |
93 | Level3
94 |
95 |
96 | MaxSpeed
97 | true
98 | true
99 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
100 | MultiThreaded
101 |
102 |
103 | Console
104 | true
105 | true
106 | ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
107 | RequireAdministrator
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/HandleMaster/HandleMaster.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;hh;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 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 |
41 |
42 | Header Files
43 |
44 |
45 | Header Files
46 |
47 |
48 | Header Files
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 | Header Files
58 |
59 |
60 | Header Files
61 |
62 |
63 |
--------------------------------------------------------------------------------
/HandleMaster/src/drivers/cpuz/cpuz_driver.cpp:
--------------------------------------------------------------------------------
1 | #include "cpuz_driver.hpp"
2 |
3 | #include "../../scm.h"
4 | #include "../../sup.h"
5 | #include "cpuz_shellcode.h"
6 |
7 | #define CPUZ_FILE_NAME L"\\SystemRoot\\System32\\drivers\\cpuz141.sys"
8 | #define CPUZ_DEVICE_NAME L"\\Device\\cpuz141"
9 |
10 | #define LODWORD(l) ((DWORD)(((DWORD_PTR)(l)) & 0xffffffff))
11 | #define HIDWORD(l) ((DWORD)((((DWORD_PTR)(l)) >> 32) & 0xffffffff))
12 |
13 | #define IOCTL_READ_CR 0x9C402428
14 | #define IOCTL_READ_MEM 0x9C402420
15 | #define IOCTL_WRITE_MEM 0x9C402430
16 |
17 | #pragma pack(push, 1)
18 | struct input_read_mem
19 | {
20 | std::uint32_t address_high;
21 | std::uint32_t address_low;
22 | std::uint32_t length;
23 | std::uint32_t buffer_high;
24 | std::uint32_t buffer_low;
25 | };
26 |
27 | struct input_write_mem
28 | {
29 | std::uint32_t address_high;
30 | std::uint32_t address_low;
31 | std::uint32_t value;
32 | };
33 |
34 | struct output
35 | {
36 | std::uint32_t operation;
37 | std::uint32_t buffer_low;
38 | };
39 |
40 | #pragma pack(pop)
41 |
42 | cpuz_driver::cpuz_driver()
43 | : deviceHandle_(INVALID_HANDLE_VALUE), serviceHandle_(INVALID_HANDLE_VALUE), unload_(false)
44 | {
45 | }
46 |
47 | cpuz_driver::~cpuz_driver()
48 | {
49 | if(deviceHandle_ != INVALID_HANDLE_VALUE)
50 | NtClose(deviceHandle_);
51 |
52 | if(unload_ && is_loaded())
53 | unload();
54 | }
55 |
56 | cpuz_driver& cpuz_driver::instance()
57 | {
58 | static cpuz_driver inst;
59 | return inst;
60 | }
61 |
62 | bool cpuz_driver::ensure_loaded()
63 | {
64 | if(!is_loaded() && !load())
65 | throw std::runtime_error{ "Driver is not loaded." };
66 |
67 | return true;
68 | }
69 |
70 | bool cpuz_driver::is_loaded()
71 | {
72 | if(!deviceHandle_ || deviceHandle_ == INVALID_HANDLE_VALUE) {
73 | IO_STATUS_BLOCK io_status;
74 | NTSTATUS status;
75 |
76 | UNICODE_STRING device_name = UNICODE_STRING{sizeof(CPUZ_DEVICE_NAME) - sizeof(WCHAR), sizeof(CPUZ_DEVICE_NAME), CPUZ_DEVICE_NAME};
77 | OBJECT_ATTRIBUTES obj_attr = OBJECT_ATTRIBUTES{ sizeof(OBJECT_ATTRIBUTES), nullptr, &device_name, 0, nullptr, nullptr };
78 |
79 | status = NtOpenFile(
80 | &deviceHandle_, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
81 | &obj_attr, &io_status, 0, OPEN_EXISTING);
82 |
83 | if(!NT_SUCCESS(status)) {
84 | ULONG i = 10;
85 | do {
86 | status = NtOpenFile(
87 | &deviceHandle_, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
88 | &obj_attr, &io_status, 0, OPEN_EXISTING);
89 | Sleep(250);
90 | } while(!NT_SUCCESS(status) && i--);
91 | }
92 | }
93 |
94 | return deviceHandle_ && deviceHandle_ != INVALID_HANDLE_VALUE;
95 | }
96 |
97 | bool cpuz_driver::load()
98 | {
99 | HANDLE service;
100 | ULONG io;
101 |
102 | if(!SupFileExists(CPUZ_FILE_NAME)) {
103 | auto file = SupCreateFile(CPUZ_FILE_NAME, FILE_GENERIC_WRITE, 0, FILE_CREATE);
104 |
105 | if(!WriteFile(file, CpuzDriverFile, sizeof(CpuzDriverFile), &io, nullptr)) {
106 | CloseHandle(file);
107 | return false;
108 | }
109 | CloseHandle(file);
110 | }
111 |
112 | if(ScmOpenServiceHandle(&service, L"cpuz141", SERVICE_STOP | DELETE)) {
113 | if(!ScmStopService(service) && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) {
114 | ScmCloseServiceHandle(service);
115 | return false;
116 | }
117 | if(!ScmDeleteService(service)) {
118 | ScmCloseServiceHandle(service);
119 | return false;
120 | }
121 | ScmCloseServiceHandle(service);
122 | }
123 |
124 | if(!ScmCreateService(
125 | &serviceHandle_,
126 | L"cpuz141", L"cpuz141",
127 | CPUZ_FILE_NAME,
128 | SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
129 | SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL))
130 | return false;
131 |
132 | if(!ScmStartService(serviceHandle_)) {
133 | ScmDeleteService(serviceHandle_);
134 | return false;
135 | }
136 |
137 | return is_loaded();
138 | }
139 |
140 | bool cpuz_driver::unload()
141 | {
142 | if(deviceHandle_ != INVALID_HANDLE_VALUE)
143 | NtClose(deviceHandle_);
144 |
145 | if(serviceHandle_ != INVALID_HANDLE_VALUE) {
146 | if(!ScmStopService(serviceHandle_) && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) {
147 | ScmCloseServiceHandle(serviceHandle_);
148 | return false;
149 | }
150 | ScmDeleteService(serviceHandle_);
151 | ScmCloseServiceHandle(serviceHandle_);
152 | }
153 |
154 | return true;
155 | }
156 |
157 | std::uint64_t cpuz_driver::read_cr0()
158 | {
159 | auto io = ULONG{ 0 };
160 | auto cr = std::uint32_t{ 0 };
161 | auto value = std::uint64_t{ 0 };
162 |
163 | if(!DeviceIoControl(deviceHandle_, IOCTL_READ_CR, &cr, sizeof(cr), &value, sizeof(value), &io, nullptr))
164 | throw std::runtime_error("Failed to read control register");
165 |
166 | return value;
167 | }
168 |
169 | std::uint64_t cpuz_driver::read_cr2()
170 | {
171 | auto io = ULONG{ 0 };
172 | auto cr = std::uint32_t{ 2 };
173 | auto value = std::uint64_t{ 0 };
174 |
175 | if(!DeviceIoControl(deviceHandle_, IOCTL_READ_CR, &cr, sizeof(cr), &value, sizeof(value), &io, nullptr))
176 | throw std::runtime_error("Failed to read control register");
177 |
178 | return value;
179 | }
180 |
181 | std::uint64_t cpuz_driver::read_cr3()
182 | {
183 | auto io = ULONG{ 0 };
184 | auto cr = std::uint32_t{ 3 };
185 | auto value = std::uint64_t{ 0 };
186 |
187 | if(!DeviceIoControl(deviceHandle_, IOCTL_READ_CR, &cr, sizeof(cr), &value, sizeof(value), &io, nullptr))
188 | throw std::runtime_error("Failed to read control register");
189 |
190 | return value;
191 | }
192 |
193 | std::uint64_t cpuz_driver::translate_linear_address(std::uint64_t directoryTableBase, LPVOID virtualAddress)
194 | {
195 | auto va = (std::uint64_t)virtualAddress;
196 |
197 | auto PML4 = (USHORT)((va >> 39) & 0x1FF); //> 30) & 0x1FF); //> 21) & 0x1FF); //> 12) & 0x1FF); //(directoryTableBase + PML4 * sizeof(ULONGLONG));
207 |
208 | if(PML4E == 0)
209 | return 0;
210 |
211 | //
212 | // The PML4E that we read is the base address of the next table on the chain,
213 | // the Page-Directory-Pointer Table.
214 | //
215 | auto PDPTE = read_physical_address((PML4E & 0xFFFFFFFFFF000) + DirectoryPtr * sizeof(ULONGLONG));
216 |
217 | if(PDPTE == 0)
218 | return 0;
219 |
220 | //Check the PS bit
221 | if((PDPTE & (1 << 7)) != 0) {
222 | // If the PDPTE’s PS flag is 1, the PDPTE maps a 1-GByte page. The
223 | // final physical address is computed as follows:
224 | // — Bits 51:30 are from the PDPTE.
225 | // — Bits 29:0 are from the original va address.
226 | return (PDPTE & 0xFFFFFC0000000) + (va & 0x3FFFFFFF);
227 | }
228 |
229 | //
230 | // PS bit was 0. That means that the PDPTE references the next table
231 | // on the chain, the Page Directory Table. Read it.
232 | //
233 | auto PDE = read_physical_address((PDPTE & 0xFFFFFFFFFF000) + Directory * sizeof(ULONGLONG));
234 |
235 | if(PDE == 0)
236 | return 0;
237 |
238 | if((PDE & (1 << 7)) != 0) {
239 | // If the PDE’s PS flag is 1, the PDE maps a 2-MByte page. The
240 | // final physical address is computed as follows:
241 | // — Bits 51:21 are from the PDE.
242 | // — Bits 20:0 are from the original va address.
243 | return (PDE & 0xFFFFFFFE00000) + (va & 0x1FFFFF);
244 | }
245 |
246 | //
247 | // PS bit was 0. That means that the PDE references a Page Table.
248 | //
249 | auto PTE = read_physical_address((PDE & 0xFFFFFFFFFF000) + Table * sizeof(ULONGLONG));
250 |
251 | if(PTE == 0)
252 | return 0;
253 |
254 | //
255 | // The PTE maps a 4-KByte page. The
256 | // final physical address is computed as follows:
257 | // — Bits 51:12 are from the PTE.
258 | // — Bits 11:0 are from the original va address.
259 | return (PTE & 0xFFFFFFFFFF000) + (va & 0xFFF);
260 | }
261 |
262 | bool cpuz_driver::read_physical_address(std::uint64_t address, LPVOID buf, size_t len)
263 | {
264 | auto io = ULONG{ 0 };
265 | auto in = input_read_mem{};
266 | auto out = output{};
267 |
268 | if(address == 0 || buf == nullptr)
269 | return false;
270 |
271 | in.address_high = HIDWORD(address);
272 | in.address_low = LODWORD(address);
273 | in.length = (std::uint32_t)len;
274 | in.buffer_high = HIDWORD(buf);
275 | in.buffer_low = LODWORD(buf);
276 |
277 | return !!DeviceIoControl(deviceHandle_, IOCTL_READ_MEM, &in, sizeof(in), &out, sizeof(out), &io, nullptr);
278 | }
279 |
280 | bool cpuz_driver::read_system_address(LPVOID address, LPVOID buf, size_t len)
281 | {
282 | const auto dirbase = read_cr3();
283 | const auto phys = translate_linear_address(dirbase, address);
284 |
285 | if(phys == 0)
286 | return false;
287 |
288 | return read_physical_address(phys, buf, len);
289 | }
290 |
291 | bool cpuz_driver::write_physical_address(std::uint64_t address, LPVOID buf, size_t len)
292 | {
293 | if(len % 4 != 0 || len == 0)
294 | throw std::runtime_error{ "The CPU-Z driver can only write lengths that are aligned to 4 bytes (4, 8, 12, 16, etc)" };
295 |
296 | auto io = ULONG{ 0 };
297 | auto in = input_write_mem{};
298 | auto out = output{};
299 |
300 | if(address == 0 || buf == nullptr)
301 | return false;
302 |
303 | if(len == 4) {
304 | in.address_high = HIDWORD(address);
305 | in.address_low = LODWORD(address);
306 | in.value = *(std::uint32_t*)buf;
307 |
308 | return !!DeviceIoControl(deviceHandle_, IOCTL_WRITE_MEM, &in, sizeof(in), &out, sizeof(out), &io, nullptr);
309 | } else {
310 | for(auto i = 0; i < len / 4; i++) {
311 | in.address_high = HIDWORD(address + 4 * i);
312 | in.address_low = LODWORD(address + 4 * i);
313 | in.value = ((std::uint32_t*)buf)[i];
314 | if(!DeviceIoControl(deviceHandle_, IOCTL_WRITE_MEM, &in, sizeof(in), &out, sizeof(out), &io, nullptr))
315 | return false;
316 | }
317 | return true;
318 | }
319 | }
320 |
321 | bool cpuz_driver::write_system_address(LPVOID address, LPVOID buf, size_t len)
322 | {
323 | const auto dirbase = read_cr3();
324 | const auto phys = translate_linear_address(dirbase, address);
325 |
326 | if(phys == 0)
327 | return false;
328 |
329 | return write_physical_address(phys, buf, len);
330 | }
331 |
--------------------------------------------------------------------------------
/HandleMaster/src/drivers/cpuz/cpuz_driver.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "../../windefs.h"
7 |
8 | class cpuz_driver
9 | {
10 | cpuz_driver();
11 | ~cpuz_driver();
12 |
13 | cpuz_driver(const cpuz_driver&) = delete;
14 | cpuz_driver(cpuz_driver&&) = delete;
15 | cpuz_driver& operator=(const cpuz_driver&) = delete;
16 | cpuz_driver& operator=(cpuz_driver&&) = delete;
17 |
18 | public:
19 | static cpuz_driver& instance();
20 |
21 | bool ensure_loaded();
22 | bool load();
23 | bool unload();
24 |
25 | void unload_on_exit(bool enable) { unload_ = enable; }
26 |
27 | /**
28 | * \brief Read some control registers
29 | */
30 | std::uint64_t read_cr0();
31 | std::uint64_t read_cr2();
32 | std::uint64_t read_cr3();
33 |
34 | /**
35 | * \brief Translates a linear (virtual) address into it's respective physical address.
36 | *
37 | * \param[in] directoryTableBase The directory base for the process that owns the address.
38 | * \param[in] virtualAddress The virtual address that you want to translate.
39 | *
40 | * \returns If the function succeeds, the return value is the physical address.
41 | * If the function fails, the return value is 0.
42 | */
43 | std::uint64_t translate_linear_address(std::uint64_t directoryTableBase, LPVOID virtualAddress);
44 |
45 | /**
46 | * \brief Reads from physical memory.
47 | */
48 | bool read_physical_address(std::uint64_t address, LPVOID buf, size_t len);
49 |
50 | /**
51 | * \brief Writes to physical memory.
52 | */
53 | bool write_physical_address(std::uint64_t address, LPVOID buf, size_t len);
54 |
55 | /**
56 | * \brief Reads from system memory. This is just a wrapper around read_physical_address
57 | */
58 | bool read_system_address(LPVOID address, LPVOID buf, size_t len);
59 |
60 | /**
61 | * \brief Writes to system memory. This is just a wrapper around write_physical_address
62 | */
63 | bool write_system_address(LPVOID address, LPVOID buf, size_t len);
64 |
65 |
66 | template
67 | T read_physical_address(U address)
68 | {
69 | T buf;
70 |
71 | if(!read_physical_address((std::uint64_t)address, (uint8_t*)&buf, sizeof(T)))
72 | throw std::runtime_error{ "Read failed" };
73 |
74 | return buf;
75 | }
76 |
77 | template
78 | T read_system_address(U address)
79 | {
80 | T buf;
81 |
82 | if(!read_system_address((LPVOID)address, (uint8_t*)&buf, sizeof(T)))
83 | throw std::runtime_error{ "Read failed" };
84 |
85 | return buf;
86 | }
87 |
88 | template
89 | bool write_physical_address(T address, U value)
90 | {
91 | return write_physical_address((LPVOID)address, (uint8_t*)&value, sizeof(U));
92 | }
93 |
94 | template
95 | bool write_system_address(T address, U value)
96 | {
97 | return write_system_address((LPVOID)address, (uint8_t*)&value, sizeof(U));
98 | }
99 | private:
100 | bool is_loaded();
101 |
102 | HANDLE serviceHandle_;
103 | HANDLE deviceHandle_;
104 | bool unload_;
105 | };
--------------------------------------------------------------------------------
/HandleMaster/src/drivers/cpuz/cpuz_shellcode.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // This is cpuz_141.sys embedded as a byte array
4 | // It is dropped to disk when necessary
5 | extern unsigned char CpuzDriverFile[46400];
6 |
--------------------------------------------------------------------------------
/HandleMaster/src/dyn_data.cpp:
--------------------------------------------------------------------------------
1 | #include "dyn_data.hpp"
2 | #include "windefs.h"
3 | #include
4 |
5 | namespace dyn_data
6 | {
7 | std::uint32_t os_version;
8 | std::uint32_t offset_directorytable;
9 | std::uint32_t offset_process_id;
10 | std::uint32_t offset_process_links;
11 | std::uint32_t offset_object_table;
12 |
13 | typedef NTSTATUS(NTAPI* RtlGetVersion_t)(
14 | _Out_ PRTL_OSVERSIONINFOW lpVersionInformation
15 | );
16 |
17 | void ensure_intel_cpu()
18 | {
19 | char buf[13] = "";
20 | int reg[4];
21 | __cpuid(reg, 0);
22 | memcpy(buf, ®[1], 4);
23 | memcpy(buf + 4, ®[3], 4);
24 | memcpy(buf + 8, ®[2], 4);
25 | buf[12] = 0;
26 |
27 | if(strcmp("GenuineIntel", buf) != 0)
28 | throw unsupported_processor(buf);
29 | }
30 |
31 | void load_information()
32 | {
33 | static auto RtlGetVersion = (RtlGetVersion_t)GetProcAddress(GetModuleHandle(TEXT("NTDLL")), "RtlGetVersion");
34 |
35 | auto osvi = OSVERSIONINFOEXW{ sizeof(OSVERSIONINFOEXW) };
36 |
37 | RtlGetVersion((POSVERSIONINFOW)&osvi);
38 |
39 | auto version_long = (osvi.dwMajorVersion << 16) | (osvi.dwMinorVersion << 8) | osvi.wServicePackMajor;
40 |
41 | switch(version_long) {
42 | case win7_sp1:
43 | os_version = win7_sp1;
44 | offset_directorytable = 0x028;
45 | offset_process_id = 0x180;
46 | offset_process_links = 0x188;
47 | offset_object_table = 0x200;
48 | break;
49 | case win8:
50 | os_version = win8;
51 | offset_directorytable = 0x028;
52 | offset_process_id = 0x2e0;
53 | offset_process_links = 0x2e8;
54 | offset_object_table = 0x408;
55 | break;
56 | case win81:
57 | os_version = win81;
58 | offset_directorytable = 0x028;
59 | offset_process_id = 0x2e0;
60 | offset_process_links = 0x2e8;
61 | offset_object_table = 0x408;
62 | break;
63 | case win10:
64 | {
65 | switch(osvi.dwBuildNumber) {
66 | case 10240:
67 | case 10586:
68 | case 14393:
69 | os_version = win10;
70 | offset_directorytable = 0x028;
71 | offset_process_id = 0x2E8;
72 | offset_process_links = 0x2F0;
73 | offset_object_table = 0x418;
74 | break;
75 | case 15063:
76 | os_version = win10_cu;
77 | offset_directorytable = 0x028;
78 | offset_process_id = 0x2E0;
79 | offset_process_links = 0x2E8;
80 | offset_object_table = 0x418;
81 | break;
82 | default:
83 | throw unsupported_version(osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.dwBuildNumber);
84 | }
85 | break;
86 | }
87 | default:
88 | {
89 | throw unsupported_version(osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.dwBuildNumber);
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/HandleMaster/src/dyn_data.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | enum supported_versions
8 | {
9 | win7_sp1 = 0x060101,
10 | win8 = 0x060200,
11 | win81 = 0x060300,
12 | win10 = 0x0A0000,
13 | win10_cu = 0x0A0002
14 | };
15 |
16 | class unsupported_version
17 | : public std::exception
18 | {
19 | public:
20 | unsupported_version(std::uint32_t major, std::uint32_t minor, std::uint32_t sp, std::uint32_t build)
21 | {
22 | char buf[128];
23 | sprintf_s(buf, "Unsupported OS build: %d.%d.%d.%d", major, minor, sp, build);
24 | message = std::string(buf, strlen(buf));
25 | }
26 |
27 | const char* what() const override
28 | {
29 | return message.data();
30 | }
31 |
32 | private:
33 | std::string message;
34 | };
35 |
36 | class unsupported_processor
37 | : public std::exception
38 | {
39 | public:
40 | unsupported_processor(const char* vendor)
41 | {
42 | char buf[128];
43 | sprintf_s(buf, "Unsupported processor (Vendor: %s)", vendor);
44 | message = std::string(buf, strlen(buf));
45 | }
46 |
47 | const char* what() const override
48 | {
49 | return message.data();
50 | }
51 |
52 | private:
53 | std::string message;
54 | };
55 |
56 | namespace dyn_data
57 | {
58 | void ensure_intel_cpu();
59 | void load_information();
60 |
61 | extern std::uint32_t os_version;
62 | extern std::uint32_t offset_directorytable;
63 | extern std::uint32_t offset_process_id;
64 | extern std::uint32_t offset_process_links;
65 | extern std::uint32_t offset_object_table;
66 | }
67 |
--------------------------------------------------------------------------------
/HandleMaster/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "windefs.h"
2 | #include
3 | #include
4 |
5 | #include "process.hpp"
6 | #include "dyn_data.hpp"
7 |
8 | int main()
9 | {
10 | try {
11 | dyn_data::ensure_intel_cpu();
12 | } catch(const unsupported_processor& ex) {
13 | fprintf(stderr, "System is running with non-Intel processor. HandleMaster Might not work properly.\n");
14 | }
15 |
16 | try {
17 | dyn_data::load_information();
18 |
19 | auto pid = process::find(L"notepad.exe");
20 |
21 | if(!pid)
22 | throw std::runtime_error("Process not running");
23 |
24 | //
25 | // Open a handle WITHOUT read access, as proof of concept
26 | //
27 | auto handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
28 |
29 | if(!handle)
30 | throw std::runtime_error("Failed to open process");
31 |
32 | //
33 | // Attach to the process that contains the handle we
34 | // want to elevate (this is the current process on this case)
35 | //
36 | if(process::attach(GetCurrentProcessId())) {
37 | //
38 | // Use CPU-Z to elevate the handle access to PROCESS_ALL_ACCESS
39 | //
40 | if(!process::grant_handle_access(handle, PROCESS_ALL_ACCESS))
41 | throw std::runtime_error("Failed to set handle access");
42 |
43 | process::detach();
44 | }
45 |
46 | //
47 | // Use the now elevated handle to perform a query and some reads.
48 | // You can use this handle for pretty much anything you want from now on. :)
49 | //
50 | ULONG return_len;
51 | PEB process_peb;
52 | PROCESS_BASIC_INFORMATION process_info;
53 | RTL_USER_PROCESS_PARAMETERS process_parameters;
54 | WCHAR buffer[512];
55 |
56 | if(NtQueryInformationProcess(handle, ProcessBasicInformation, &process_info, sizeof(process_info), &return_len) < 0)
57 | throw std::runtime_error("NtQueryInformationProcess failed");
58 |
59 | if(!ReadProcessMemory(handle, process_info.PebBaseAddress, &process_peb, sizeof(process_peb), nullptr) ||
60 | !ReadProcessMemory(handle, process_peb.ProcessParameters, &process_parameters, sizeof(process_parameters), nullptr) ||
61 | !ReadProcessMemory(handle, process_parameters.CommandLine.Buffer, buffer, process_parameters.CommandLine.Length, nullptr))
62 | throw std::runtime_error("ReadProcessMemory failed");
63 |
64 | printf("CommandLine: %ws\n", buffer);
65 |
66 | CloseHandle(handle);
67 | } catch(const unsupported_version& ex) {
68 | fprintf(stderr, ex.what());
69 | fprintf(stderr, "\n");
70 | fprintf(stderr, "Supported (tested) versions are:\n");
71 | fprintf(stderr, " - Windows 7 SP1 (6.1.7601)\n");
72 | fprintf(stderr, " - Windows 8 (6.2.9200)\n");
73 | fprintf(stderr, " - Windows 8.1 (6.3.9600)\n");
74 | fprintf(stderr, " - Windows 10 TH1 (10.0.10240)\n");
75 | fprintf(stderr, " - Windows 10 TH2 (10.0.10586)\n");
76 | fprintf(stderr, " - Windows 10 AU (10.0.14393)\n");
77 | fprintf(stderr, " - Windows 10 CU (10.0.15063)\n");
78 |
79 | } catch(const std::exception& ex) {
80 | fprintf(stderr, ex.what());
81 | fprintf(stderr, "\nGetLastError: %X\n", GetLastError());
82 | }
83 |
84 | getc(stdin);
85 | return 0;
86 | }
--------------------------------------------------------------------------------
/HandleMaster/src/process.cpp:
--------------------------------------------------------------------------------
1 | #include "process.hpp"
2 | #include "windefs.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "sup.h"
9 | #include "dyn_data.hpp"
10 | #include "drivers/cpuz/cpuz_driver.hpp"
11 |
12 | PHANDLE_TABLE_ENTRY ExpLookupHandleTableEntryWin7(PHANDLE_TABLE HandleTable, ULONGLONG Handle)
13 | {
14 | ULONGLONG v2; // r8@2
15 | ULONGLONG v3; // rcx@2
16 | ULONGLONG v4; // r8@2
17 | ULONGLONG result; // rax@4
18 | ULONGLONG v6; // [sp+8h] [bp+8h]@1
19 | ULONGLONG table = (ULONGLONG)HandleTable;
20 |
21 | v6 = Handle;
22 | v6 = Handle & 0xFFFFFFFC;
23 | if(v6 >= *(DWORD*)(table + 92)) {
24 | result = 0i64;
25 | } else {
26 | v2 = (*(ULONGLONG*)table);
27 | v3 = (*(ULONGLONG*)table) & 3i64;
28 | v4 = v2 - (ULONG)v3;
29 | if((ULONG)v3) {
30 | if((DWORD)v3 == 1)
31 | result = process::read((((Handle - (Handle & 0x3FF)) >> 7) + v4)) + 4 * (Handle & 0x3FF);
32 | else
33 | result = process::read((PVOID)(process::read((PVOID)(((((Handle - (Handle & 0x3FF)) >> 7) - (((Handle - (Handle & 0x3FF)) >> 7) & 0xFFF)) >> 9) + v4)) + (((Handle - (Handle & 0x3FF)) >> 7) & 0xFFF))) + 4 * (Handle & 0x3FF);
34 | } else {
35 | result = v4 + 4 * Handle;
36 | }
37 | }
38 | return (PHANDLE_TABLE_ENTRY)result;
39 | }
40 |
41 | PHANDLE_TABLE_ENTRY ExpLookupHandleTableEntry(PHANDLE_TABLE HandleTable, ULONGLONG Handle)
42 | {
43 | ULONGLONG v2; // rdx@1
44 | LONGLONG v3; // r8@2
45 | ULONGLONG result; // rax@4
46 | ULONGLONG v5;
47 |
48 | ULONGLONG a1 = (ULONGLONG)HandleTable;
49 |
50 | v2 = Handle & 0xFFFFFFFFFFFFFFFCui64;
51 | if(v2 >= *(DWORD*)a1) {
52 | result = 0i64;
53 | } else {
54 | v3 = *(ULONGLONG*)(a1 + 8);
55 | if(*(ULONGLONG*)(a1 + 8) & 3) {
56 | if((*(DWORD*)(a1 + 8) & 3) == 1) {
57 | v5 = process::read(v3 + 8 * (v2 >> 10) - 1);
58 | result = v5 + 4 * (v2 & 0x3FF);
59 | } else {
60 | v5 = process::read(process::read(v3 + 8 * (v2 >> 19) - 2) + 8 * ((v2 >> 10) & 0x1FF));
61 | result = v5 + 4 * (v2 & 0x3FF);
62 | }
63 | } else {
64 | result = v3 + 4 * v2;
65 | }
66 | }
67 | return (PHANDLE_TABLE_ENTRY)result;
68 | }
69 |
70 | namespace process
71 | {
72 | struct process_context
73 | {
74 | std::uint32_t pid;
75 | std::uint64_t dir_base;
76 | std::uint64_t kernel_entry;
77 | };
78 |
79 | std::stack context_stack;
80 | process_context* cur_context = nullptr;
81 |
82 | static std::uint8_t* find_kernel_proc(const char* name)
83 | {
84 | static HMODULE ntoskrnl = LoadLibraryW(L"ntoskrnl.exe");
85 | static ULONG64 krnl_base = (ULONG64)SupGetKernelBase(nullptr);
86 |
87 | if(!krnl_base)
88 | throw std::runtime_error{ "Could not find the system base." };
89 |
90 | if(!ntoskrnl)
91 | throw std::runtime_error{ "Failed to load ntoskrnl.exe" };
92 |
93 | auto fn = (std::uint64_t)GetProcAddress(ntoskrnl, name);
94 |
95 | if(!fn) return nullptr;
96 |
97 | return (uint8_t*)(fn - (std::uint64_t)ntoskrnl + krnl_base);
98 | }
99 |
100 | static process_context find_process_info(std::uint32_t pid)
101 | {
102 | process_context info;
103 | info.pid = 0;
104 |
105 | auto& cpuz = cpuz_driver::instance();
106 |
107 | if(cpuz.ensure_loaded()) {
108 | // 1. Get PsInitialSystemProcess;
109 | // 2. Iterate _EPROCESS list until UniqueProcessId == pid;
110 | // 3. Read _KPROCESS:DirectoryTableBase;
111 | // 4. Profit.
112 |
113 | // Get the pointer to the system process
114 | // This is a pointer to a EPROCESS object
115 | auto peprocess = find_kernel_proc("PsInitialSystemProcess");
116 | auto ntos_entry = cpuz.read_system_address(peprocess);
117 |
118 | auto list_head = ntos_entry + dyn_data::offset_process_links;
119 | auto last_link = cpuz.read_system_address(list_head + sizeof(PVOID));
120 | auto cur_link = list_head;
121 |
122 | // Iterate the kernel's linked list of processes
123 | do {
124 | auto entry = (std::uint64_t)cur_link - dyn_data::offset_process_links;
125 |
126 | auto unique_pid = cpuz.read_system_address(entry + dyn_data::offset_process_id);
127 |
128 | // PID is a match
129 | // Read the directory table base for this process so we can use it later
130 | // as well as the address for this EPROCESS entry
131 | if(unique_pid == pid) {
132 | info.pid = pid;
133 | info.dir_base = cpuz.read_system_address(entry + dyn_data::offset_directorytable);
134 | info.kernel_entry = entry;
135 | break;
136 | }
137 |
138 | // Go to next process
139 | cur_link = cpuz.read_system_address(cur_link);
140 | } while(cur_link != last_link);
141 | }
142 | return info;
143 | }
144 |
145 | std::uint32_t find(const wchar_t* proc)
146 | {
147 | auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
148 | auto pe = PROCESSENTRY32W{ sizeof(PROCESSENTRY32W) };
149 |
150 | if(Process32First(snapshot, &pe)) {
151 | do {
152 | if(!_wcsicmp(proc, pe.szExeFile)) {
153 | CloseHandle(snapshot);
154 | return pe.th32ProcessID;
155 | }
156 | } while(Process32Next(snapshot, &pe));
157 | }
158 | CloseHandle(snapshot);
159 | return 0;
160 | }
161 |
162 | bool attach(std::uint32_t pid)
163 | {
164 | auto info = find_process_info(pid);
165 |
166 | if(info.pid != 0) {
167 | context_stack.push(info);
168 | cur_context = &context_stack.top();
169 | return true;
170 | }
171 | return false;
172 | }
173 |
174 | void detach()
175 | {
176 | context_stack.pop();
177 | if(context_stack.size() > 0)
178 | cur_context = &context_stack.top();
179 | else
180 | cur_context = nullptr;
181 | }
182 |
183 | bool read(PVOID base, PVOID buf, size_t len)
184 | {
185 | if(cur_context == nullptr)
186 | throw std::runtime_error{ "Not attached to a process." };
187 |
188 | auto& cpuz = cpuz_driver::instance();
189 |
190 | auto phys = cpuz.translate_linear_address(cur_context->dir_base, base);
191 |
192 | if(!phys)
193 | return false;
194 |
195 | return cpuz.read_physical_address(phys, buf, len);
196 | }
197 |
198 | bool write(PVOID base, PVOID buf, size_t len)
199 | {
200 | if(cur_context == nullptr)
201 | throw std::runtime_error{ "Not attached to a process." };
202 |
203 | auto& cpuz = cpuz_driver::instance();
204 |
205 | auto phys = cpuz.translate_linear_address(cur_context->dir_base, base);
206 |
207 | if(!phys)
208 | return false;
209 |
210 | return cpuz.write_physical_address(phys, buf, len);
211 | }
212 |
213 | bool grant_handle_access(HANDLE handle, ACCESS_MASK access_rights)
214 | {
215 | //
216 | // Make sure we are attached to a process
217 | //
218 | if(cur_context == nullptr)
219 | throw std::runtime_error{ "Not attached to a process." };
220 |
221 | auto handle_table_addr = read(PVOID(cur_context->kernel_entry + dyn_data::offset_object_table));
222 | auto handle_table = read(handle_table_addr);
223 | auto entry_addr = PHANDLE_TABLE_ENTRY{ nullptr };
224 |
225 | if(dyn_data::os_version == win7_sp1) {
226 | entry_addr = ExpLookupHandleTableEntryWin7(&handle_table, (ULONGLONG)handle);
227 | if(!entry_addr)
228 | return false;
229 | } else {
230 | entry_addr = ExpLookupHandleTableEntry(&handle_table, (ULONGLONG)handle);
231 | if(!entry_addr)
232 | return false;
233 | }
234 |
235 | auto entry = read(entry_addr);
236 | entry.GrantedAccess = access_rights;
237 | return write(entry_addr, entry);
238 | }
239 | }
--------------------------------------------------------------------------------
/HandleMaster/src/process.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "windefs.h"
4 | #include
5 | #include
6 |
7 | namespace process
8 | {
9 | std::uint32_t find(const wchar_t* proc);
10 |
11 | bool attach(std::uint32_t pid);
12 | void detach();
13 |
14 | bool grant_handle_access(HANDLE handle, ACCESS_MASK access_rights);
15 |
16 | bool read(PVOID base, PVOID buf, size_t len);
17 | bool write(PVOID base, PVOID buf, size_t len);
18 |
19 | template
20 | T read(U base)
21 | {
22 | T temp = T{};
23 | read((PVOID)base, &temp, sizeof(T));
24 | return temp;
25 | }
26 | template
27 | bool write(U base, T value)
28 | {
29 | return write((PVOID)base, &value, sizeof(T));
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/HandleMaster/src/scm.c:
--------------------------------------------------------------------------------
1 | #include "scm.h"
2 |
3 | #include
4 |
5 | BOOL ScmCreateService(
6 | _Out_ PHANDLE ServiceHandle,
7 | _In_ LPCWSTR ServiceName,
8 | _In_opt_ LPCWSTR DisplayName,
9 | _In_ LPCWSTR BinPath,
10 | _In_ ACCESS_MASK DesiredAccess,
11 | _In_ ULONG ServiceType,
12 | _In_ ULONG StartType,
13 | _In_ ULONG ErrorControl
14 | )
15 | {
16 | SC_HANDLE Scm;
17 | WCHAR QualifiedPath[MAX_PATH + 2];
18 |
19 | Scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
20 |
21 | if(!Scm)
22 | return FALSE;
23 |
24 | swprintf_s(QualifiedPath, MAX_PATH + 2, L"%ws", BinPath);
25 |
26 | *ServiceHandle = CreateServiceW(
27 | Scm,
28 | ServiceName, DisplayName,
29 | DesiredAccess,
30 | ServiceType, StartType,
31 | ErrorControl, QualifiedPath,
32 | NULL, NULL, NULL, NULL, NULL
33 | );
34 |
35 | CloseServiceHandle(Scm);
36 |
37 | return *ServiceHandle != NULL;
38 | }
39 |
40 | BOOL ScmDeleteService(
41 | _In_ HANDLE ServiceHandle
42 | )
43 | {
44 | return DeleteService(ServiceHandle);
45 | }
46 |
47 | BOOL ScmOpenServiceHandle(
48 | _Out_ PHANDLE ServiceHandle,
49 | _In_ LPCWSTR ServiceName,
50 | _In_ ACCESS_MASK DesiredAccess
51 | )
52 | {
53 | SC_HANDLE Scm;
54 |
55 | Scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
56 |
57 | if(!Scm)
58 | return FALSE;
59 |
60 | *ServiceHandle = OpenService(Scm, ServiceName, DesiredAccess);
61 |
62 | CloseServiceHandle(Scm);
63 |
64 | return *ServiceHandle != NULL;
65 | }
66 |
67 | BOOL ScmCloseServiceHandle(
68 | _In_ HANDLE ServiceHandle
69 | )
70 | {
71 | return CloseServiceHandle(ServiceHandle);
72 | }
73 |
74 | BOOL ScmStartService(
75 | _In_ HANDLE ServiceHandle
76 | )
77 | {
78 | return StartServiceW(ServiceHandle, 0, NULL);
79 | }
80 |
81 | BOOL ScmPauseService(
82 | _In_ HANDLE ServiceHandle
83 | )
84 | {
85 | SERVICE_STATUS ServiceStatus;
86 |
87 | return ControlService(ServiceHandle, SERVICE_CONTROL_PAUSE, &ServiceStatus);
88 | }
89 |
90 | BOOL ScmResumeService(
91 | _In_ HANDLE ServiceHandle
92 | )
93 | {
94 | SERVICE_STATUS ServiceStatus;
95 |
96 | return ControlService(ServiceHandle, SERVICE_CONTROL_CONTINUE, &ServiceStatus);
97 | }
98 |
99 | BOOL ScmStopService(
100 | _In_ HANDLE ServiceHandle
101 | )
102 | {
103 | SERVICE_STATUS ServiceStatus;
104 |
105 | return ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
106 | }
--------------------------------------------------------------------------------
/HandleMaster/src/scm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "windefs.h"
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 | #if 0
9 | }
10 | #endif
11 |
12 | BOOL ScmCreateService(
13 | _Out_ PHANDLE ServiceHandle,
14 | _In_ LPCWSTR ServiceName,
15 | _In_opt_ LPCWSTR DisplayName,
16 | _In_ LPCWSTR BinPath,
17 | _In_ ACCESS_MASK DesiredAccess,
18 | _In_ ULONG ServiceType,
19 | _In_ ULONG StartType,
20 | _In_ ULONG ErrorControl
21 | );
22 |
23 | BOOL ScmDeleteService(
24 | _In_ HANDLE ServiceHandle
25 | );
26 |
27 | BOOL ScmOpenServiceHandle(
28 | _Out_ PHANDLE ServiceHandle,
29 | _In_ LPCWSTR ServiceName,
30 | _In_ ACCESS_MASK DesiredAccess
31 | );
32 |
33 | BOOL ScmCloseServiceHandle(
34 | _In_ HANDLE ServiceHandle
35 | );
36 |
37 | BOOL ScmStartService(
38 | _In_ HANDLE ServiceHandle
39 | );
40 |
41 | BOOL ScmPauseService(
42 | _In_ HANDLE ServiceHandle
43 | );
44 |
45 | BOOL ScmResumeService(
46 | _In_ HANDLE ServiceHandle
47 | );
48 |
49 | BOOL ScmStopService(
50 | _In_ HANDLE ServiceHandle
51 | );
52 |
53 | #if 0
54 | {
55 | #endif
56 | #ifdef __cplusplus
57 | }
58 | #endif
--------------------------------------------------------------------------------
/HandleMaster/src/sup.c:
--------------------------------------------------------------------------------
1 | #include "sup.h"
2 |
3 | #include
4 | #include
5 |
6 | typedef struct _RTL_PROCESS_MODULE_INFORMATION
7 | {
8 | HANDLE Section;
9 | PVOID MappedBase;
10 | PVOID ImageBase;
11 | ULONG ImageSize;
12 | ULONG Flags;
13 | USHORT LoadOrderIndex;
14 | USHORT InitOrderIndex;
15 | USHORT LoadCount;
16 | USHORT OffsetToFileName;
17 | UCHAR FullPathName[256];
18 | } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
19 |
20 | typedef struct _RTL_PROCESS_MODULES
21 | {
22 | ULONG NumberOfModules;
23 | RTL_PROCESS_MODULE_INFORMATION Modules[1];
24 | } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
25 |
26 |
27 | BOOL SupFileExists(
28 | _In_ LPCWSTR FilePath
29 | )
30 | {
31 | NTSTATUS Status;
32 | HANDLE FileHandle;
33 | UNICODE_STRING NtFileName;
34 | OBJECT_ATTRIBUTES ObjAttr;
35 | IO_STATUS_BLOCK IoStatus;
36 |
37 | RtlInitUnicodeString(&NtFileName, (LPWSTR)FilePath);
38 | InitializeObjectAttributes(&ObjAttr, &NtFileName, 0, NULL, NULL);
39 |
40 | Status = NtCreateFile(
41 | &FileHandle,
42 | SYNCHRONIZE,
43 | &ObjAttr,
44 | &IoStatus,
45 | NULL,
46 | FILE_ATTRIBUTE_NORMAL,
47 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
48 | FILE_OPEN,
49 | FILE_NON_DIRECTORY_FILE,
50 | NULL, 0);
51 |
52 | if(!NT_SUCCESS(Status)) {
53 | return FALSE;
54 | }
55 |
56 | NtClose(FileHandle);
57 |
58 | return TRUE;
59 | }
60 |
61 | BOOL SupWriteResourceToDisk(
62 | _In_ LPCWSTR FilePath,
63 | _In_opt_ HMODULE Module,
64 | _In_ LPCWSTR ResourceName,
65 | _In_ LPCWSTR ResourceType
66 | )
67 | {
68 | HANDLE File;
69 | HRSRC ResInfo;
70 | PVOID ResData;
71 | ULONG ResSize;
72 | ULONG BytesWritten;
73 |
74 | ResInfo = FindResourceW(Module, ResourceName, ResourceType);
75 |
76 | if(!ResInfo)
77 | return FALSE;
78 |
79 | File = SupCreateFile(FilePath, GENERIC_WRITE | SYNCHRONIZE, 0, CREATE_ALWAYS);
80 |
81 | if(File == INVALID_HANDLE_VALUE)
82 | return FALSE;
83 |
84 | ResData = LoadResource(Module, ResInfo);
85 | ResData = LockResource(ResData);
86 | ResSize = SizeofResource(Module, ResInfo);
87 |
88 | BOOL Result = WriteFile(File, ResData, ResSize, &BytesWritten, NULL);
89 |
90 | CloseHandle(File);
91 |
92 | return Result;
93 | }
94 |
95 | HANDLE SupCreateFile(
96 | _In_ LPCWSTR FilePath,
97 | _In_ ACCESS_MASK DesiredAccess,
98 | _In_ ULONG ShareMode,
99 | _In_ ULONG CreateDisposition
100 | )
101 | {
102 | NTSTATUS Status;
103 | HANDLE FileHandle;
104 | UNICODE_STRING NtFileName;
105 | OBJECT_ATTRIBUTES ObjAttr;
106 | IO_STATUS_BLOCK IoStatus;
107 |
108 | RtlInitUnicodeString(&NtFileName, (LPWSTR)FilePath);
109 | InitializeObjectAttributes(&ObjAttr, &NtFileName, 0, NULL, NULL);
110 |
111 | Status = NtCreateFile(
112 | &FileHandle,
113 | DesiredAccess,
114 | &ObjAttr,
115 | &IoStatus,
116 | NULL,
117 | FILE_ATTRIBUTE_NORMAL,
118 | ShareMode,
119 | CreateDisposition,
120 | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
121 | NULL, 0);
122 |
123 | if(!NT_SUCCESS(Status))
124 | FileHandle = INVALID_HANDLE_VALUE;
125 |
126 | return FileHandle;
127 | }
128 |
129 | BOOL SupLookupErrorMessage(
130 | _In_ ULONG ErrorCode,
131 | _Out_ LPSTR Buffer,
132 | _In_ ULONG BufferSize
133 | )
134 | {
135 | if(!FormatMessageA(
136 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
137 | NULL,
138 | ErrorCode,
139 | 0,
140 | Buffer,
141 | BufferSize,
142 | NULL)) {
143 | return sprintf_s(Buffer, BufferSize, "%d", ErrorCode) > 0;
144 | }
145 |
146 | return TRUE;
147 | }
148 |
149 | LPVOID SupGetKernelBase(
150 | _Out_opt_ PSIZE_T KernelSize
151 | )
152 | {
153 | NTSTATUS status;
154 | PVOID buffer;
155 | ULONG bufferSize = 2048;
156 |
157 | buffer = malloc(bufferSize);
158 |
159 | status = NtQuerySystemInformation(
160 | 11/*SystemModuleInformation*/,
161 | buffer,
162 | bufferSize,
163 | &bufferSize
164 | );
165 |
166 | if(status == STATUS_INFO_LENGTH_MISMATCH) {
167 | free(buffer);
168 | buffer = malloc(bufferSize);
169 |
170 | status = NtQuerySystemInformation(
171 | 11/*SystemModuleInformation*/,
172 | buffer,
173 | bufferSize,
174 | &bufferSize
175 | );
176 | }
177 |
178 | if(!NT_SUCCESS(status))
179 | return NULL;
180 |
181 | if(KernelSize)
182 | *KernelSize = (SIZE_T)((PRTL_PROCESS_MODULES)buffer)->Modules[0].ImageSize;
183 |
184 | return ((PRTL_PROCESS_MODULES)buffer)->Modules[0].ImageBase;
185 | }
--------------------------------------------------------------------------------
/HandleMaster/src/sup.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "windefs.h"
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 | #if 0
9 | }
10 | #endif
11 |
12 | /**
13 | * \brief Check if the specified file exists.
14 | *
15 | * \param[in] FilePath NT Path to the file.
16 | *
17 | * \returns If the file exists, the return value is nonzero.
18 | * If the file could not be found, the return value is 0.
19 | * To get extended error information, call \c GetLastError.
20 | */
21 | BOOL SupFileExists(
22 | _In_ LPCWSTR FilePath
23 | );
24 |
25 | /**
26 | * \brief Write a resource file to disk.
27 | *
28 | * \param[in] FilePath NT Path to the file.
29 | * \param[in] Module The module that contains the resource.
30 | * Use \c NULL to specify the main process module.
31 | * \param[in] ResourceName The resource name.
32 | * \param[in] ResourceType The resource type.
33 | *
34 | * \returns If the function succeeds, the return value is nonzero.
35 | * If the function fails, the return value is 0.
36 | * To get extended error information, call \c GetLastError.
37 | */
38 | BOOL SupWriteResourceToDisk(
39 | _In_ LPCWSTR FilePath,
40 | _In_opt_ HMODULE Module,
41 | _In_ LPCWSTR ResourceName,
42 | _In_ LPCWSTR ResourceType
43 | );
44 |
45 | /**
46 | * \brief Creates or opens a file.
47 | *
48 | * A wrapper around the Win32 \c NtCreateFile API.
49 | * For more information see https://msdn.microsoft.com/en-us/library/bb432380(v=vs.85).aspx
50 | *
51 | * \param[in] FilePath NT Path to the file.
52 | * \param[in] DesiredAccess Desired access rights.
53 | * \param[in] ShareMode The requested sharing mode of the file.
54 | * \param[in] CreateDisposition An action to take on a file or device that exists or does not exist.
55 | *
56 | * \returns If the function succeeds, the return value is an open handle to the specified file.
57 | * If the function fails, the return value is INVALID_HANDLE_VALUE.
58 | * To get extended error information, call GetLastError.
59 | */
60 | HANDLE SupCreateFile(
61 | _In_ LPCWSTR FilePath,
62 | _In_ ACCESS_MASK DesiredAccess,
63 | _In_ ULONG ShareMode,
64 | _In_ ULONG CreateDisposition
65 | );
66 |
67 | /**
68 | * \brief Translate a Win32 error code to its respective message.
69 | *
70 | * \param[in] ErrorCode The Win32 error code.
71 | * \param[out] Buffer Buffer to store the message.
72 | * \param[in] BufferSize Max buffer size.
73 | *
74 | * \remarks If the function cannot find the message for the provided error
75 | * the error code is converted to text and stored on the buffer
76 | * instead of the message.
77 | *
78 | * \returns If the function succeeds, the return value is nonzero.
79 | * If the function fails, the return value is 0.
80 | */
81 | BOOL SupLookupErrorMessage(
82 | _In_ ULONG ErrorCode,
83 | _Out_ LPSTR Buffer,
84 | _In_ ULONG BufferSize
85 | );
86 |
87 | /**
88 | * \brief Retrieves the kernel base for the current session.
89 | *
90 | * \param[out] KernelSize The size of the kernel image.
91 | *
92 | * \returns If the function succeeds, the return value is the base address for the ntos kernel.
93 | * If the function fails, the return value is 0.
94 | * To get extended error information, call \c GetLastError.
95 | */
96 | LPVOID SupGetKernelBase(
97 | _Out_opt_ PSIZE_T KernelSize
98 | );
99 |
100 | #if 0
101 | {
102 | #endif
103 | #ifdef __cplusplus
104 | }
105 | #endif
106 |
--------------------------------------------------------------------------------
/HandleMaster/src/windefs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WIN32_LEAN_AND_MEAN
4 | #define NO_STRICT
5 | #define NOMINMAX
6 | #include
7 | #define WIN32_NO_STATUS
8 | #include
9 | #include
10 |
11 | #ifndef _WIN64
12 | #error "x64 only please"
13 | #endif
14 |
15 | typedef struct _EPROCESS *PEPROCESS;
16 | typedef struct _HANDLE_TABLE_ENTRY_INFO *PHANDLE_TABLE_ENTRY_INFO;
17 | typedef PVOID EX_PUSH_LOCK;
18 | typedef struct _HANDLE_TABLE* PHANDLE_TABLE;
19 |
20 | typedef struct _HANDLE_TABLE_ENTRY
21 | {
22 | //This struct is incomplete, but we dont really care about the other fields
23 | ULONGLONG Value;
24 | ULONGLONG GrantedAccess : 25;
25 | } HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
26 |
27 | typedef struct _HANDLE_TABLE
28 | {
29 | CHAR fill[100];
30 | } HANDLE_TABLE, *PHANDLE_TABLE;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 MarkHC
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.md:
--------------------------------------------------------------------------------
1 | # HandleMaster
2 |
3 | Vulnerable kernel drivers aren't a new thing. They allow regular uses to perform tasks that should be impossible from ring3. More specifically, the [CPU-Z](http://www.cpuid.com/softwares/cpu-z.html) driver allows users to read and write directly to physical memory.
4 |
5 | HandleMaster exploits that to perform some [DKOM](https://en.wikipedia.org/wiki/Direct_kernel_object_manipulation) and change granted access rights for handles.
6 |
7 | The idea is that you can open a handle with low access and then elevate its access rights later on when you want to use it.
8 |
9 | This bypasses some Anti-Cheats that use ObRegisterCallbacks to strip access rights from handles at creation time *cough* BattleEye *cough*
10 |
11 | ## Supported Windows Versions:
12 |
13 | - Windows 7 SP1 (6.1.7601)
14 | - Windows 8 (6.2.9200)
15 | - Windows 8.1 (6.3.9600)
16 | - Windows 10 TH1 (10.0.10240)
17 | - Windows 10 TH2 (10.0.10586)
18 | - Windows 10 Anniversary Update (10.0.14393)
19 | - Windows 10 Creators Update (10.0.15063)
20 |
21 | Any problems please let me know :)
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------