├── .editorconfig ├── .gitignore ├── CFGExceptions.sln ├── CFGExceptions ├── CFGExceptions.vcxproj ├── CFGExceptions.vcxproj.filters └── main.cpp └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # Matches multiple files with brace expansion notation 4 | [*.{cpp,c,h}] 5 | indent_style = tab 6 | indent_size = 4 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /.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 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /CFGExceptions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CFGExceptions", "CFGExceptions\CFGExceptions.vcxproj", "{84B99443-896F-48A3-8F2E-9B9524B3AE46}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {84B99443-896F-48A3-8F2E-9B9524B3AE46}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {84B99443-896F-48A3-8F2E-9B9524B3AE46}.Debug|Win32.Build.0 = Debug|Win32 16 | {84B99443-896F-48A3-8F2E-9B9524B3AE46}.Release|Win32.ActiveCfg = Release|Win32 17 | {84B99443-896F-48A3-8F2E-9B9524B3AE46}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /CFGExceptions/CFGExceptions.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {84B99443-896F-48A3-8F2E-9B9524B3AE46} 15 | Win32Proj 16 | CFGExceptions 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level4 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | true 56 | 57 | 58 | Console 59 | true 60 | 61 | 62 | 63 | 64 | Level3 65 | 66 | 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 71 | true 72 | 73 | 74 | Console 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /CFGExceptions/CFGExceptions.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 | -------------------------------------------------------------------------------- /CFGExceptions/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NTDLL ("ntdll.dll") 6 | #define KERNELBASE ("kernelbase.dll") 7 | #define NTSETCONTEXTTHREAD ("NtSetContextThread") 8 | #define NTSETINFORMATIONVIRTUALMEMORY ("NtSetInformationVirtualMemory") 9 | #define SETPROCESSVALIDCALLTARGETS ("SetProcessValidCallTargets") 10 | 11 | #define TARGET_PROCESS_NAME (L"mspaint.exe") 12 | 13 | #define CFG_CALL_TARGET_VALID (0x00000001) 14 | 15 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 16 | 17 | typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS 18 | { 19 | VmPrefetchInformation, 20 | VmPagePriorityInformation, 21 | VmCfgCallTargetInformation 22 | } VIRTUAL_MEMORY_INFORMATION_CLASS; 23 | 24 | typedef struct _MEMORY_RANGE_ENTRY 25 | { 26 | PVOID VirtualAddress; 27 | SIZE_T NumberOfBytes; 28 | } MEMORY_RANGE_ENTRY, *PMEMORY_RANGE_ENTRY; 29 | 30 | typedef struct _CFG_CALL_TARGET_INFO 31 | { 32 | ULONG_PTR Offset; 33 | ULONG_PTR Flags; 34 | } CFG_CALL_TARGET_INFO, *PCFG_CALL_TARGET_INFO; 35 | 36 | typedef struct _VM_INFORMATION 37 | { 38 | DWORD dwNumberOfOffsets; 39 | PVOID dwMustBeZero; 40 | PDWORD pdwOutput; 41 | PCFG_CALL_TARGET_INFO ptOffsets; 42 | } VM_INFORMATION, *PVM_INFORMATION; 43 | 44 | typedef NTSTATUS(NTAPI *_NtSetInformationVirtualMemory)( 45 | HANDLE hProcess, 46 | VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass, 47 | ULONG_PTR NumberOfEntries, 48 | PMEMORY_RANGE_ENTRY VirtualAddresses, 49 | PVOID VmInformation, 50 | ULONG VmInformationLength 51 | ); 52 | 53 | typedef BOOL (WINAPI *_SetProcessValidCallTargets)( 54 | HANDLE hProcess, 55 | PVOID VirtualAddress, 56 | SIZE_T RegionSize, 57 | ULONG NumberOfOffsets, 58 | PCFG_CALL_TARGET_INFO OffsetInformation 59 | ); 60 | 61 | typedef enum _ESTATUS 62 | { 63 | ESTATUS_INVALID = -1, 64 | ESTATUS_SUCCESS = 0, 65 | 66 | ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETMODULEHANDLEA_FAILED = 0x100, 67 | ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETPROCADDRESS_FAILED, 68 | 69 | ESTATUS_GETMEMORYALLOCATIONBASEANDREGIONSIZE_VIRTUALQUERY_FAILED, 70 | 71 | ESTATUS_OPENPROCESSBYNAME_OPENPROCESS_ERROR, 72 | 73 | ESTATUS_GETPROCESSIDBYNAME_CREATETOOLHELP32SNAPSHOT_ERROR, 74 | ESTATUS_GETPROCESSIDBYNAME_PROCESS32FIRST_ERROR, 75 | ESTATUS_GETPROCESSIDBYNAME_PROCESS_NOT_FOUND, 76 | 77 | ESTATUS_ADDCFGEXCEPTIONUNDOCUMENTEDAPI_NTSETINFORMATIONVIRTUALMEMORY_FAILED, 78 | 79 | ESTATUS_ADDCFGEXCEPTIONDOCUMENTEDAPI_SETPROCESSVALIDCALLTARGETS_FAILED, 80 | } ESTATUS, *PESTATUS; 81 | 82 | #define ESTATUS_FAILED(eStatus) (ESTATUS_SUCCESS != eStatus) 83 | 84 | ESTATUS GetFunctionAddressFromDll( 85 | PSTR pszDllName, 86 | PSTR pszFunctionName, 87 | PVOID *ppvFunctionAddress 88 | ) 89 | { 90 | HMODULE hModule = NULL; 91 | PVOID pvFunctionAddress = NULL; 92 | ESTATUS eReturn = ESTATUS_INVALID; 93 | 94 | hModule = GetModuleHandleA(pszDllName); 95 | if (NULL == hModule) 96 | { 97 | eReturn = ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETMODULEHANDLEA_FAILED; 98 | goto lblCleanup; 99 | } 100 | 101 | pvFunctionAddress = GetProcAddress(hModule, pszFunctionName); 102 | if (NULL == pvFunctionAddress) 103 | { 104 | eReturn = ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETPROCADDRESS_FAILED; 105 | goto lblCleanup; 106 | } 107 | 108 | *ppvFunctionAddress = pvFunctionAddress; 109 | eReturn = ESTATUS_SUCCESS; 110 | 111 | lblCleanup: 112 | return eReturn; 113 | } 114 | 115 | 116 | ESTATUS GetMemoryAllocationBaseAndRegionSize( 117 | PVOID pvAddress, 118 | PVOID *ppvAllocationBase, 119 | PSIZE_T pstRegionSize 120 | ) 121 | { 122 | SIZE_T stErr = 0; 123 | ESTATUS eReturn = ESTATUS_INVALID; 124 | MEMORY_BASIC_INFORMATION tMemoryBasicInformation = { 0 }; 125 | 126 | stErr = VirtualQuery( 127 | pvAddress, 128 | &tMemoryBasicInformation, 129 | sizeof(tMemoryBasicInformation) 130 | ); 131 | if (0 == stErr) 132 | { 133 | eReturn = ESTATUS_GETMEMORYALLOCATIONBASEANDREGIONSIZE_VIRTUALQUERY_FAILED; 134 | goto lblCleanup; 135 | } 136 | 137 | *ppvAllocationBase = tMemoryBasicInformation.AllocationBase; 138 | *pstRegionSize = tMemoryBasicInformation.RegionSize; 139 | eReturn = ESTATUS_SUCCESS; 140 | 141 | lblCleanup: 142 | return eReturn; 143 | } 144 | 145 | 146 | ESTATUS GetProcessIdByName( 147 | LPWSTR pszProcessName, 148 | PDWORD pdwProcessId 149 | ) 150 | { 151 | PROCESSENTRY32 pe = { 0 }; 152 | DWORD dwProcessId = 0; 153 | HANDLE hSnapshot = NULL; 154 | ESTATUS eReturn = ESTATUS_INVALID; 155 | 156 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 157 | if (NULL == hSnapshot) 158 | { 159 | eReturn = ESTATUS_GETPROCESSIDBYNAME_CREATETOOLHELP32SNAPSHOT_ERROR; 160 | printf("[*] CreateToolhelp32Snapshot error. GLE: %d.\n\n\n", GetLastError()); 161 | goto lblCleanup; 162 | } 163 | 164 | pe.dwSize = sizeof(PROCESSENTRY32); 165 | if (FALSE == Process32First(hSnapshot, &pe)) 166 | { 167 | eReturn = ESTATUS_GETPROCESSIDBYNAME_PROCESS32FIRST_ERROR; 168 | printf("[*] Process32First error. GLE: %d.\n\n\n", GetLastError()); 169 | goto lblCleanup; 170 | } 171 | 172 | do 173 | { 174 | if (NULL != wcsstr(pe.szExeFile, pszProcessName)) 175 | { 176 | dwProcessId = pe.th32ProcessID; 177 | break; 178 | } 179 | } while (Process32Next(hSnapshot, &pe)); 180 | 181 | if (0 == dwProcessId) 182 | { 183 | printf("[*] Process '%S' could not be found.\n\n\n", pszProcessName); 184 | eReturn = ESTATUS_GETPROCESSIDBYNAME_PROCESS_NOT_FOUND; 185 | goto lblCleanup; 186 | } 187 | 188 | printf("[*] Found process '%S'. PID: %d (0x%X).\n\n\n", pszProcessName, dwProcessId, dwProcessId); 189 | *pdwProcessId = dwProcessId; 190 | eReturn = ESTATUS_SUCCESS; 191 | 192 | lblCleanup: 193 | if (NULL != hSnapshot) 194 | { 195 | CloseHandle(hSnapshot); 196 | hSnapshot = NULL; 197 | } 198 | 199 | return eReturn; 200 | 201 | } 202 | 203 | ESTATUS OpenProcessByName( 204 | LPWSTR pszProcessName, 205 | PHANDLE phProcess 206 | ) 207 | { 208 | DWORD dwPid = 0; 209 | HANDLE hProcess = NULL; 210 | ESTATUS eReturn = ESTATUS_INVALID; 211 | 212 | eReturn = GetProcessIdByName(pszProcessName, &dwPid); 213 | if (ESTATUS_FAILED(eReturn)) 214 | { 215 | goto lblCleanup; 216 | } 217 | 218 | hProcess = OpenProcess( 219 | PROCESS_ALL_ACCESS, 220 | FALSE, 221 | dwPid 222 | ); 223 | if (NULL == hProcess) 224 | { 225 | eReturn = ESTATUS_OPENPROCESSBYNAME_OPENPROCESS_ERROR; 226 | printf("[*] OpenProcess error. GLE: %d.\n\n\n", GetLastError()); 227 | goto lblCleanup; 228 | } 229 | 230 | printf("[*] Opened process's handle: %d (0x%X).\n\n\n", hProcess, hProcess); 231 | *phProcess = hProcess; 232 | eReturn = ESTATUS_SUCCESS; 233 | 234 | lblCleanup: 235 | 236 | return eReturn; 237 | } 238 | 239 | ESTATUS AddCfgExceptionUndocumentedApi(HANDLE hProcess, PVOID pvAddress) 240 | { 241 | DWORD dwOutput = 0; 242 | NTSTATUS ntStatus = 0; 243 | SIZE_T stRegionSize = 0; 244 | VM_INFORMATION tVmInformation = { 0 }; 245 | PVOID pvAllocationBase = NULL; 246 | ESTATUS eReturn = ESTATUS_INVALID; 247 | MEMORY_RANGE_ENTRY tVirtualAddresses = { 0 }; 248 | CFG_CALL_TARGET_INFO tCfgCallTargetInfo = { 0 }; 249 | _NtSetInformationVirtualMemory pfnNtSetInformationVirtualMemory = NULL; 250 | 251 | // Get the address of ntdll!NtSetInformationVirtualMemory 252 | eReturn = GetFunctionAddressFromDll( 253 | NTDLL, 254 | NTSETINFORMATIONVIRTUALMEMORY, 255 | (PVOID *) &pfnNtSetInformationVirtualMemory 256 | ); 257 | if (ESTATUS_FAILED(eReturn)) 258 | { 259 | goto lblCleanup; 260 | } 261 | 262 | // Get memory allocation base and region size by calling VirtualProtect. 263 | eReturn = GetMemoryAllocationBaseAndRegionSize( 264 | pvAddress, 265 | &pvAllocationBase, 266 | &stRegionSize 267 | ); 268 | if (ESTATUS_FAILED(eReturn)) 269 | { 270 | goto lblCleanup; 271 | } 272 | 273 | tCfgCallTargetInfo.Flags = CFG_CALL_TARGET_VALID; 274 | tCfgCallTargetInfo.Offset = (ULONG_PTR)pvAddress - (ULONG_PTR)pvAllocationBase; 275 | 276 | tVirtualAddresses.NumberOfBytes = stRegionSize; 277 | tVirtualAddresses.VirtualAddress = pvAllocationBase; 278 | tVmInformation.dwNumberOfOffsets = 0x1; 279 | tVmInformation.dwMustBeZero = 0x0; 280 | tVmInformation.pdwOutput = &dwOutput; 281 | tVmInformation.ptOffsets = &tCfgCallTargetInfo; 282 | 283 | printf("[*] Adding a CFG exception for 0x%X using NtSetInformationVirtualMemory.\n\n\n", pvAddress); 284 | ntStatus = pfnNtSetInformationVirtualMemory( 285 | hProcess, 286 | VmCfgCallTargetInformation, 287 | 1, 288 | &tVirtualAddresses, 289 | &tVmInformation, 290 | 0x10 291 | ); 292 | if (STATUS_SUCCESS != ntStatus) 293 | { 294 | eReturn = ESTATUS_ADDCFGEXCEPTIONUNDOCUMENTEDAPI_NTSETINFORMATIONVIRTUALMEMORY_FAILED; 295 | goto lblCleanup; 296 | } 297 | 298 | printf("[*] Exception added successfully.\n\n\n"); 299 | eReturn = ESTATUS_SUCCESS; 300 | 301 | lblCleanup: 302 | return eReturn; 303 | } 304 | 305 | ESTATUS AddCfgExceptionDocumentedApi(HANDLE hProcess, PVOID pvAddress) 306 | { 307 | BOOL bReturn = FALSE; 308 | SIZE_T stRegionSize = NULL; 309 | PVOID pvAllocationBase = NULL; 310 | ESTATUS eReturn = ESTATUS_INVALID; 311 | CFG_CALL_TARGET_INFO tCfgCallTargetInfo = { 0 }; 312 | _SetProcessValidCallTargets pfnSetProcessValidCallTargets = NULL; 313 | 314 | // Get the address of KernelBase!SetProcessValidCallTargets 315 | eReturn = GetFunctionAddressFromDll( 316 | KERNELBASE, 317 | SETPROCESSVALIDCALLTARGETS, 318 | (PVOID *) &pfnSetProcessValidCallTargets 319 | ); 320 | if (ESTATUS_FAILED(eReturn)) 321 | { 322 | goto lblCleanup; 323 | } 324 | 325 | // Get memory allocation base and region size by calling VirtualProtect. 326 | eReturn = GetMemoryAllocationBaseAndRegionSize( 327 | pvAddress, 328 | &pvAllocationBase, 329 | &stRegionSize 330 | ); 331 | if (ESTATUS_FAILED(eReturn)) 332 | { 333 | goto lblCleanup; 334 | } 335 | 336 | tCfgCallTargetInfo.Flags = CFG_CALL_TARGET_VALID; 337 | tCfgCallTargetInfo.Offset = (ULONG_PTR)pvAddress - (ULONG_PTR)pvAllocationBase; 338 | 339 | printf("[*] Adding a CFG exception for 0x%X using SetProcessValidCallTargets.\n\n\n", pvAddress); 340 | bReturn = pfnSetProcessValidCallTargets( 341 | hProcess, 342 | pvAllocationBase, 343 | stRegionSize, 344 | 0x1, 345 | &tCfgCallTargetInfo 346 | ); 347 | if (FALSE == bReturn) 348 | { 349 | eReturn = ESTATUS_ADDCFGEXCEPTIONDOCUMENTEDAPI_SETPROCESSVALIDCALLTARGETS_FAILED; 350 | goto lblCleanup; 351 | } 352 | 353 | printf("[*] Exception added successfully.\n\n\n"); 354 | eReturn = ESTATUS_SUCCESS; 355 | 356 | lblCleanup: 357 | return eReturn; 358 | } 359 | 360 | int main() 361 | { 362 | HANDLE hProcess = NULL; 363 | ESTATUS eReturn = ESTATUS_INVALID; 364 | PVOID pvAddressToAddCfgExceptionTo = NULL; 365 | 366 | // Get the address of ntdll!NtSetContextThread 367 | eReturn = GetFunctionAddressFromDll( 368 | NTDLL, 369 | NTSETCONTEXTTHREAD, 370 | &pvAddressToAddCfgExceptionTo 371 | ); 372 | if (ESTATUS_FAILED(eReturn)) 373 | { 374 | goto lblCleanup; 375 | } 376 | 377 | eReturn = OpenProcessByName(TARGET_PROCESS_NAME, &hProcess); 378 | if (ESTATUS_FAILED(eReturn)) 379 | { 380 | goto lblCleanup; 381 | } 382 | 383 | // Add a CFG exception using ntdll!NtSetInformationVirtualMemory 384 | eReturn = AddCfgExceptionUndocumentedApi( 385 | hProcess, 386 | pvAddressToAddCfgExceptionTo 387 | ); 388 | if (ESTATUS_FAILED(eReturn)) 389 | { 390 | goto lblCleanup; 391 | } 392 | 393 | // Add a CFG exception using KernelBase!SetProcessValidCallTargets 394 | eReturn = AddCfgExceptionDocumentedApi( 395 | hProcess, 396 | pvAddressToAddCfgExceptionTo 397 | ); 398 | if (ESTATUS_FAILED(eReturn)) 399 | { 400 | goto lblCleanup; 401 | } 402 | 403 | eReturn = ESTATUS_SUCCESS; 404 | 405 | lblCleanup: 406 | if (NULL != hProcess) 407 | { 408 | CloseHandle(hProcess); 409 | hProcess = NULL; 410 | } 411 | 412 | return eReturn; 413 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CFGExceptions 2 | Adding exceptions to Microsoft's Control Flow Guard (CFG) 3 | --------------------------------------------------------------------------------