├── .gitignore ├── LICENSE ├── build.sh ├── log.sh ├── pacmandc.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── pacmandc ├── Info.plist ├── kernel.development.symbols.h ├── pacmandc.cpp ├── pacmandc.hpp ├── win.s └── win_c.c /.gitignore: -------------------------------------------------------------------------------- 1 | DerivedData/ 2 | build/ 3 | .vscode 4 | pacmandc.xcodeproj/project.xcworkspace/xcuserdata/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Joseph Ravichandran, Weon Taek Na, Jay Lang, Mengjia Yan 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 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | xcodebuild -arch arm64e -configuration Debug build 3 | -------------------------------------------------------------------------------- /log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | log stream --predicate 'eventMessage contains "[PacmanKit]"' 3 | -------------------------------------------------------------------------------- /pacmandc.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7C411C7028958C4D00D0832B /* win.s in Sources */ = {isa = PBXBuildFile; fileRef = 7C411C6F28958C4D00D0832B /* win.s */; }; 11 | 7C504B4E2871722900CBB387 /* pacmandc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 7C504B4D2871722900CBB387 /* pacmandc.hpp */; }; 12 | 7C504B502871722900CBB387 /* pacmandc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C504B4F2871722900CBB387 /* pacmandc.cpp */; }; 13 | 7CA18706289D6AD300C6FC27 /* win_c.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CA18705289D6AD300C6FC27 /* win_c.c */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | 7C411C6F28958C4D00D0832B /* win.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = win.s; sourceTree = ""; }; 18 | 7C504B4A2871722900CBB387 /* pacmandc.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = pacmandc.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | 7C504B4D2871722900CBB387 /* pacmandc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = pacmandc.hpp; sourceTree = ""; }; 20 | 7C504B4F2871722900CBB387 /* pacmandc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = pacmandc.cpp; sourceTree = ""; }; 21 | 7C504B512871722900CBB387 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | 7CA18705289D6AD300C6FC27 /* win_c.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = win_c.c; sourceTree = ""; }; 23 | 7CD18F8E287A4D7400D17FFD /* kernel.development.symbols.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kernel.development.symbols.h; sourceTree = ""; }; 24 | /* End PBXFileReference section */ 25 | 26 | /* Begin PBXFrameworksBuildPhase section */ 27 | 7C504B472871722900CBB387 /* Frameworks */ = { 28 | isa = PBXFrameworksBuildPhase; 29 | buildActionMask = 2147483647; 30 | files = ( 31 | ); 32 | runOnlyForDeploymentPostprocessing = 0; 33 | }; 34 | /* End PBXFrameworksBuildPhase section */ 35 | 36 | /* Begin PBXGroup section */ 37 | 7C504B402871722900CBB387 = { 38 | isa = PBXGroup; 39 | children = ( 40 | 7C504B4C2871722900CBB387 /* pacmandc */, 41 | 7C504B4B2871722900CBB387 /* Products */, 42 | ); 43 | sourceTree = ""; 44 | }; 45 | 7C504B4B2871722900CBB387 /* Products */ = { 46 | isa = PBXGroup; 47 | children = ( 48 | 7C504B4A2871722900CBB387 /* pacmandc.kext */, 49 | ); 50 | name = Products; 51 | sourceTree = ""; 52 | }; 53 | 7C504B4C2871722900CBB387 /* pacmandc */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 7C504B4D2871722900CBB387 /* pacmandc.hpp */, 57 | 7C411C6F28958C4D00D0832B /* win.s */, 58 | 7C504B4F2871722900CBB387 /* pacmandc.cpp */, 59 | 7CA18705289D6AD300C6FC27 /* win_c.c */, 60 | 7CD18F8E287A4D7400D17FFD /* kernel.development.symbols.h */, 61 | 7C504B512871722900CBB387 /* Info.plist */, 62 | ); 63 | path = pacmandc; 64 | sourceTree = ""; 65 | }; 66 | /* End PBXGroup section */ 67 | 68 | /* Begin PBXHeadersBuildPhase section */ 69 | 7C504B452871722900CBB387 /* Headers */ = { 70 | isa = PBXHeadersBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | 7C504B4E2871722900CBB387 /* pacmandc.hpp in Headers */, 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | /* End PBXHeadersBuildPhase section */ 78 | 79 | /* Begin PBXNativeTarget section */ 80 | 7C504B492871722900CBB387 /* pacmandc */ = { 81 | isa = PBXNativeTarget; 82 | buildConfigurationList = 7C504B542871722900CBB387 /* Build configuration list for PBXNativeTarget "pacmandc" */; 83 | buildPhases = ( 84 | 7C504B452871722900CBB387 /* Headers */, 85 | 7C504B462871722900CBB387 /* Sources */, 86 | 7C504B472871722900CBB387 /* Frameworks */, 87 | 7C504B482871722900CBB387 /* Resources */, 88 | ); 89 | buildRules = ( 90 | ); 91 | dependencies = ( 92 | ); 93 | name = pacmandc; 94 | productName = pacmandc; 95 | productReference = 7C504B4A2871722900CBB387 /* pacmandc.kext */; 96 | productType = "com.apple.product-type.kernel-extension"; 97 | }; 98 | /* End PBXNativeTarget section */ 99 | 100 | /* Begin PBXProject section */ 101 | 7C504B412871722900CBB387 /* Project object */ = { 102 | isa = PBXProject; 103 | attributes = { 104 | BuildIndependentTargetsInParallel = 1; 105 | LastUpgradeCheck = 1340; 106 | TargetAttributes = { 107 | 7C504B492871722900CBB387 = { 108 | CreatedOnToolsVersion = 13.4.1; 109 | }; 110 | }; 111 | }; 112 | buildConfigurationList = 7C504B442871722900CBB387 /* Build configuration list for PBXProject "pacmandc" */; 113 | compatibilityVersion = "Xcode 13.0"; 114 | developmentRegion = en; 115 | hasScannedForEncodings = 0; 116 | knownRegions = ( 117 | en, 118 | Base, 119 | ); 120 | mainGroup = 7C504B402871722900CBB387; 121 | productRefGroup = 7C504B4B2871722900CBB387 /* Products */; 122 | projectDirPath = ""; 123 | projectRoot = ""; 124 | targets = ( 125 | 7C504B492871722900CBB387 /* pacmandc */, 126 | ); 127 | }; 128 | /* End PBXProject section */ 129 | 130 | /* Begin PBXResourcesBuildPhase section */ 131 | 7C504B482871722900CBB387 /* Resources */ = { 132 | isa = PBXResourcesBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXResourcesBuildPhase section */ 139 | 140 | /* Begin PBXSourcesBuildPhase section */ 141 | 7C504B462871722900CBB387 /* Sources */ = { 142 | isa = PBXSourcesBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | 7CA18706289D6AD300C6FC27 /* win_c.c in Sources */, 146 | 7C411C7028958C4D00D0832B /* win.s in Sources */, 147 | 7C504B502871722900CBB387 /* pacmandc.cpp in Sources */, 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXSourcesBuildPhase section */ 152 | 153 | /* Begin XCBuildConfiguration section */ 154 | 7C504B522871722900CBB387 /* Debug */ = { 155 | isa = XCBuildConfiguration; 156 | buildSettings = { 157 | ALWAYS_SEARCH_USER_PATHS = NO; 158 | CLANG_ANALYZER_NONNULL = YES; 159 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 160 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 161 | CLANG_ENABLE_MODULES = YES; 162 | CLANG_ENABLE_OBJC_ARC = YES; 163 | CLANG_ENABLE_OBJC_WEAK = YES; 164 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 165 | CLANG_WARN_BOOL_CONVERSION = YES; 166 | CLANG_WARN_COMMA = YES; 167 | CLANG_WARN_CONSTANT_CONVERSION = YES; 168 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 169 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 170 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 171 | CLANG_WARN_EMPTY_BODY = YES; 172 | CLANG_WARN_ENUM_CONVERSION = YES; 173 | CLANG_WARN_INFINITE_RECURSION = YES; 174 | CLANG_WARN_INT_CONVERSION = YES; 175 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 176 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 177 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 178 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 179 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 180 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 181 | CLANG_WARN_STRICT_PROTOTYPES = YES; 182 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 183 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 184 | CLANG_WARN_UNREACHABLE_CODE = YES; 185 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 186 | COPY_PHASE_STRIP = NO; 187 | DEBUG_INFORMATION_FORMAT = dwarf; 188 | ENABLE_STRICT_OBJC_MSGSEND = YES; 189 | ENABLE_TESTABILITY = YES; 190 | GCC_C_LANGUAGE_STANDARD = gnu11; 191 | GCC_DYNAMIC_NO_PIC = NO; 192 | GCC_NO_COMMON_BLOCKS = YES; 193 | GCC_OPTIMIZATION_LEVEL = 0; 194 | GCC_PREPROCESSOR_DEFINITIONS = ( 195 | "DEBUG=1", 196 | "$(inherited)", 197 | ); 198 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 199 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 200 | GCC_WARN_UNDECLARED_SELECTOR = YES; 201 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 202 | GCC_WARN_UNUSED_FUNCTION = YES; 203 | GCC_WARN_UNUSED_VARIABLE = YES; 204 | MACOSX_DEPLOYMENT_TARGET = 12.2; 205 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 206 | MTL_FAST_MATH = YES; 207 | ONLY_ACTIVE_ARCH = YES; 208 | SDKROOT = macosx; 209 | }; 210 | name = Debug; 211 | }; 212 | 7C504B532871722900CBB387 /* Release */ = { 213 | isa = XCBuildConfiguration; 214 | buildSettings = { 215 | ALWAYS_SEARCH_USER_PATHS = NO; 216 | CLANG_ANALYZER_NONNULL = YES; 217 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 218 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 219 | CLANG_ENABLE_MODULES = YES; 220 | CLANG_ENABLE_OBJC_ARC = YES; 221 | CLANG_ENABLE_OBJC_WEAK = YES; 222 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 223 | CLANG_WARN_BOOL_CONVERSION = YES; 224 | CLANG_WARN_COMMA = YES; 225 | CLANG_WARN_CONSTANT_CONVERSION = YES; 226 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 227 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 228 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 229 | CLANG_WARN_EMPTY_BODY = YES; 230 | CLANG_WARN_ENUM_CONVERSION = YES; 231 | CLANG_WARN_INFINITE_RECURSION = YES; 232 | CLANG_WARN_INT_CONVERSION = YES; 233 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 234 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 235 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 237 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 238 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 239 | CLANG_WARN_STRICT_PROTOTYPES = YES; 240 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 241 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 242 | CLANG_WARN_UNREACHABLE_CODE = YES; 243 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 244 | COPY_PHASE_STRIP = NO; 245 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 246 | ENABLE_NS_ASSERTIONS = NO; 247 | ENABLE_STRICT_OBJC_MSGSEND = YES; 248 | GCC_C_LANGUAGE_STANDARD = gnu11; 249 | GCC_NO_COMMON_BLOCKS = YES; 250 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 251 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 252 | GCC_WARN_UNDECLARED_SELECTOR = YES; 253 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 254 | GCC_WARN_UNUSED_FUNCTION = YES; 255 | GCC_WARN_UNUSED_VARIABLE = YES; 256 | MACOSX_DEPLOYMENT_TARGET = 12.2; 257 | MTL_ENABLE_DEBUG_INFO = NO; 258 | MTL_FAST_MATH = YES; 259 | ONLY_ACTIVE_ARCH = YES; 260 | SDKROOT = macosx; 261 | }; 262 | name = Release; 263 | }; 264 | 7C504B552871722900CBB387 /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ARCHS = ( 268 | "$(ARCHS_STANDARD)", 269 | arm64e, 270 | ); 271 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; 272 | CODE_SIGN_IDENTITY = "-"; 273 | CODE_SIGN_STYLE = Automatic; 274 | COMBINE_HIDPI_IMAGES = YES; 275 | CURRENT_PROJECT_VERSION = 1.0.0d1; 276 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 277 | GENERATE_INFOPLIST_FILE = YES; 278 | INFOPLIST_FILE = pacmandc/Info.plist; 279 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 280 | MACOSX_DEPLOYMENT_TARGET = 12.3; 281 | MARKETING_VERSION = 1.0; 282 | MODULE_NAME = mit.pacmandc; 283 | MODULE_VERSION = 1.0.0d1; 284 | ONLY_ACTIVE_ARCH = YES; 285 | PRODUCT_BUNDLE_IDENTIFIER = mit.pacmankit; 286 | PRODUCT_NAME = "$(TARGET_NAME)"; 287 | RUN_CLANG_STATIC_ANALYZER = YES; 288 | SWIFT_EMIT_LOC_STRINGS = YES; 289 | WRAPPER_EXTENSION = kext; 290 | }; 291 | name = Debug; 292 | }; 293 | 7C504B562871722900CBB387 /* Release */ = { 294 | isa = XCBuildConfiguration; 295 | buildSettings = { 296 | ARCHS = ( 297 | "$(ARCHS_STANDARD)", 298 | arm64e, 299 | ); 300 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; 301 | CODE_SIGN_IDENTITY = "-"; 302 | CODE_SIGN_STYLE = Automatic; 303 | COMBINE_HIDPI_IMAGES = YES; 304 | CURRENT_PROJECT_VERSION = 1.0.0d1; 305 | GENERATE_INFOPLIST_FILE = YES; 306 | INFOPLIST_FILE = pacmandc/Info.plist; 307 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 308 | MACOSX_DEPLOYMENT_TARGET = 12.3; 309 | MARKETING_VERSION = 1.0; 310 | MODULE_NAME = mit.pacmandc; 311 | MODULE_VERSION = 1.0.0d1; 312 | ONLY_ACTIVE_ARCH = YES; 313 | PRODUCT_BUNDLE_IDENTIFIER = mit.pacmankit; 314 | PRODUCT_NAME = "$(TARGET_NAME)"; 315 | RUN_CLANG_STATIC_ANALYZER = YES; 316 | SWIFT_EMIT_LOC_STRINGS = YES; 317 | WRAPPER_EXTENSION = kext; 318 | }; 319 | name = Release; 320 | }; 321 | /* End XCBuildConfiguration section */ 322 | 323 | /* Begin XCConfigurationList section */ 324 | 7C504B442871722900CBB387 /* Build configuration list for PBXProject "pacmandc" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | 7C504B522871722900CBB387 /* Debug */, 328 | 7C504B532871722900CBB387 /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | 7C504B542871722900CBB387 /* Build configuration list for PBXNativeTarget "pacmandc" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | 7C504B552871722900CBB387 /* Debug */, 337 | 7C504B562871722900CBB387 /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | /* End XCConfigurationList section */ 343 | }; 344 | rootObject = 7C504B412871722900CBB387 /* Project object */; 345 | } 346 | -------------------------------------------------------------------------------- /pacmandc.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /pacmandc.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pacmandc/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IOKitPersonalities 6 | 7 | PacmanKit 8 | 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | IOClass 12 | PacmanKit 13 | IOKitDebug 14 | 65535 15 | IOMatchCategory 16 | PacmanKit 17 | IOProviderClass 18 | IOResources 19 | IOResourceMatch 20 | IOKit 21 | IOUserClientClass 22 | PacmanUser 23 | 24 | 25 | OSBundleLibraries 26 | 27 | com.apple.kpi.bsd 28 | 21.5 29 | com.apple.kpi.iokit 30 | 21.5 31 | com.apple.kpi.libkern 32 | 21.5 33 | com.apple.kpi.mach 34 | 21.5 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /pacmandc/kernel.development.symbols.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef kernel_development_symbols_h 3 | #define kernel_development_symbols_h 4 | 5 | // What offset from the mach-o header is 6 | // os_release in your kernelcache? 7 | 8 | // You can find this out by making a core dump and 9 | // checking within lldb. 10 | 11 | // This is what it is for me on MacOS 12.4 T8101, but it might be different for you! 12 | 13 | #define OFFSET_OS_RELEASE ((0x9B6874)) 14 | 15 | #error "Before installing PacmanKit, verify that the OFFSET_OS_RELEASE variable is correct for your environment!" 16 | 17 | #endif /* kernel_development_symbols_h */ 18 | -------------------------------------------------------------------------------- /pacmandc/pacmandc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PacmanKit 3 | * Kernel support for the PACMAN DEF CON 30 talk. 4 | * Joseph Ravichandran 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "pacmandc.hpp" 14 | 15 | #define LOG_PREFIX "[PacmanKit]" 16 | 17 | OSDefineMetaClassAndStructors(PacmanKit, IOService) 18 | OSDefineMetaClassAndStructors(PacmanUser, IOUserClient) 19 | 20 | #define LIMIT __static_data[0] 21 | __attribute__((aligned((0x4000)))) static uint64_t __static_data[0x4000] = {0x10}; 22 | 23 | // Dispatch table for the PacmanKit IOUserClient (PacmanUser) 24 | const IOExternalMethodDispatch PacmanUser::Methods[kPacmanClientNumMethods] = { 25 | {KernelBaseLeak, 0, 0, 1, 0,}, 26 | {ReadMemoryUnsafe, 1, 0, 1, 0,}, 27 | {WriteMemory, 2, 0, 0, 0,}, 28 | {KernelVirt2Phys, 1, 0, 1, 0,}, 29 | {UserVirt2Phys, 1, 0, 1, 0,}, 30 | {IOUserClientLeak, 0, 0, 1, 0,}, 31 | {GimmeMemory, 0, 0, 1, 0}, 32 | {FreeMemory, 0, 0, 0, 0}, 33 | {TellMeRegs, 0, 0, 2, 0}, 34 | {ReadMemoryForTiming, 2, 0, 1, 0}, 35 | {ExecMemoryForTiming, 2, 0, 1, 0}, 36 | {LeakMethod, 0, 0, 3, 0}, 37 | {ReadForSpectre, 2, 0, 0, 0}, 38 | {ExecForSpectre, 2, 0, 0, 0}, 39 | {CallServiceRoutine, 6, 0, 1, 0}, 40 | {ForgeSignData, 2, 0, 1, 0}, 41 | {ForgeAuthData, 2, 0, 1, 0}, 42 | {ForgeSignInst, 2, 0, 1, 0}, 43 | {ForgeAuthInst, 2, 0, 1, 0}, 44 | {LeakCurProc, 0, 0, 1, 0}, 45 | }; 46 | 47 | // Loads `addr`, returns the number of cycles required to access it. 48 | uint64_t time_access(uint64_t addr) { 49 | uint64_t val_out; 50 | uint64_t t1, t2; 51 | asm volatile( 52 | "dsb sy\n" 53 | "isb\n" 54 | "mrs %[t1], S3_2_c15_c0_0\n" 55 | "isb\n" 56 | "ldr %[val_out], [%[addr]]\n" 57 | "isb\n" 58 | "mrs %[t2], S3_2_c15_c0_0\n" 59 | "isb\n" 60 | "dsb sy\n" 61 | : [val_out]"=r"(val_out), [t1]"=r"(t1), [t2]"=r"(t2) 62 | : [addr]"r"(addr) 63 | ); 64 | return t2 - t1; 65 | } 66 | 67 | // Executes `addr`, returns the number of cycles required to access it. 68 | uint64_t time_execute(uint64_t addr) { 69 | uint64_t t1, t2; 70 | asm volatile( 71 | "dsb sy\n" 72 | "isb\n" 73 | "mrs %[t1], S3_2_c15_c0_0\n" 74 | "isb\n" 75 | "blr %[addr]\n" 76 | "isb\n" 77 | "mrs %[t2], S3_2_c15_c0_0\n" 78 | "isb\n" 79 | "dsb sy\n" 80 | : [t1]"=r"(t1), [t2]"=r"(t2) 81 | : [addr]"r"(addr) 82 | : "lr" 83 | ); 84 | return t2 - t1; 85 | } 86 | 87 | // Returns the kernel base address (will need to be updated whenever the kernelcache changes) 88 | IOReturn KernelBaseLeak(OSObject *target, void *reference, IOExternalMethodArguments *args) { 89 | IOReturn ret = kIOReturnSuccess; 90 | 91 | uint64_t os_rel_ptr = (uint64_t)&os_release | PAC_BITMASK; 92 | uint64_t kernel_base = os_rel_ptr - OFFSET_OS_RELEASE; 93 | args->scalarOutput[0] = kernel_base; 94 | 95 | return ret; 96 | } 97 | 98 | // Read a quadword of kernel memory through an IOMemoryDescriptor to ensure it is safe to do so 99 | // This API is deprecated and unavailable via the IOUserClient 100 | IOReturn ReadMemorySafe(OSObject *target, void *reference, IOExternalMethodArguments *args) { 101 | IOReturn ret = kIOReturnSuccess; 102 | IOByteCount bytes_read; 103 | bool prepare_called = false; 104 | mach_vm_address_t targetAddr = (mach_vm_address_t)args->scalarInput[0]; 105 | mach_vm_size_t bytes_to_read = 8; 106 | uint64_t read_val = 0; 107 | 108 | args->scalarOutput[0] = 0; 109 | 110 | IOMemoryDescriptor *descriptor = IOMemoryDescriptor::withAddressRange(targetAddr, bytes_to_read, kIODirectionOut, kernel_task); 111 | 112 | if (NULL == descriptor) { 113 | ret = kIOReturnError; 114 | goto out; 115 | } 116 | 117 | { 118 | ret = descriptor->prepare(); 119 | if (ret != kIOReturnSuccess) goto out; 120 | prepare_called = true; 121 | } 122 | 123 | bytes_read = descriptor->readBytes(0, &read_val, sizeof(read_val)); 124 | if (bytes_read != sizeof(read_val)) { 125 | ret = kIOReturnError; 126 | } 127 | args->scalarOutput[0] = read_val; 128 | 129 | out: 130 | if (NULL != descriptor) { 131 | if (prepare_called) descriptor->complete(); 132 | descriptor->release(); 133 | descriptor = NULL; 134 | } 135 | 136 | return ret; 137 | } 138 | 139 | // Read a quadword of kernel memory without checking the pointer at all 140 | // This is what happens when the PacmanRead externalMethod is called 141 | IOReturn ReadMemoryUnsafe(OSObject *target, void *reference, IOExternalMethodArguments *args) { 142 | uint64_t val_out, addr; 143 | addr = args->scalarInput[0] | PAC_BITMASK; 144 | asm volatile( 145 | "ldr %[val_out], [%[addr]]\n" 146 | : [val_out]"=r"(val_out) 147 | : [addr]"r"(addr) 148 | ); 149 | args->scalarOutput[0] = val_out; 150 | return kIOReturnSuccess; 151 | } 152 | 153 | // Write a quadword of kernel memory 154 | IOReturn WriteMemory(OSObject *target, void *reference, IOExternalMethodArguments *args) { 155 | IOReturn ret = kIOReturnSuccess; 156 | IOByteCount bytes_written; 157 | bool prepare_called = false; 158 | mach_vm_address_t targetAddr = (mach_vm_address_t)args->scalarInput[0]; 159 | mach_vm_size_t bytes_to_write = 8; 160 | uint64_t write_val = args->scalarInput[1]; 161 | 162 | IOMemoryDescriptor *descriptor = IOMemoryDescriptor::withAddressRange(targetAddr, bytes_to_write, kIODirectionIn, kernel_task); 163 | 164 | if (NULL == descriptor) { 165 | ret = kIOReturnError; 166 | goto out; 167 | } 168 | 169 | { 170 | ret = descriptor->prepare(); 171 | if (ret != kIOReturnSuccess) goto out; 172 | prepare_called = true; 173 | } 174 | 175 | bytes_written = descriptor->writeBytes(0, &write_val, sizeof(write_val)); 176 | if (bytes_written != sizeof(write_val)) { 177 | ret = kIOReturnError; 178 | } 179 | 180 | out: 181 | if (NULL != descriptor) { 182 | if (prepare_called) descriptor->complete(); 183 | descriptor->release(); 184 | descriptor = NULL; 185 | } 186 | 187 | return ret; 188 | } 189 | 190 | // Translate a kernel virtual address to a physical address 191 | IOReturn KernelVirt2Phys(OSObject *target, void *reference, IOExternalMethodArguments *args) { 192 | IOReturn ret = kIOReturnSuccess; 193 | bool prepare_called = false; 194 | mach_vm_address_t targetAddr = (mach_vm_address_t)args->scalarInput[0]; 195 | mach_vm_size_t bytes_to_read = 8; 196 | 197 | args->scalarOutput[0] = 0; 198 | 199 | IOMemoryDescriptor *descriptor = IOMemoryDescriptor::withAddressRange(targetAddr, bytes_to_read, kIODirectionOut, kernel_task); 200 | 201 | if (NULL == descriptor) { 202 | ret = kIOReturnError; 203 | goto out; 204 | } 205 | 206 | { 207 | ret = descriptor->prepare(); 208 | if (ret != kIOReturnSuccess) goto out; 209 | prepare_called = true; 210 | } 211 | 212 | args->scalarOutput[0] = descriptor->getPhysicalAddress();; 213 | 214 | out: 215 | if (NULL != descriptor) { 216 | if (prepare_called) descriptor->complete(); 217 | descriptor->release(); 218 | descriptor = NULL; 219 | } 220 | 221 | return ret; 222 | } 223 | 224 | // Translate a user virtual address to a physical address 225 | IOReturn UserVirt2Phys(OSObject *target, void *reference, IOExternalMethodArguments *args) { 226 | IOReturn ret = kIOReturnSuccess; 227 | bool prepare_called = false; 228 | mach_vm_address_t targetAddr = (mach_vm_address_t)args->scalarInput[0]; 229 | mach_vm_size_t bytes_to_read = 8; 230 | 231 | args->scalarOutput[0] = 0; 232 | 233 | // Or could just use current_task() instead of storing the task port in the IOUserClient 234 | IOMemoryDescriptor *descriptor = IOMemoryDescriptor::withAddressRange(targetAddr, bytes_to_read, kIODirectionOut, ((PacmanUser *)target)->task); 235 | 236 | if (NULL == descriptor) { 237 | ret = kIOReturnError; 238 | goto out; 239 | } 240 | 241 | { 242 | ret = descriptor->prepare(); 243 | if (ret != kIOReturnSuccess) goto out; 244 | prepare_called = true; 245 | } 246 | 247 | args->scalarOutput[0] = descriptor->getPhysicalAddress();; 248 | 249 | out: 250 | if (NULL != descriptor) { 251 | if (prepare_called) { 252 | descriptor->complete(); 253 | } 254 | descriptor->release(); 255 | descriptor = NULL; 256 | } 257 | 258 | return ret; 259 | } 260 | 261 | // Leak the address of this IOUserClient 262 | IOReturn IOUserClientLeak(OSObject *target, void *reference, IOExternalMethodArguments *args) { 263 | args->scalarOutput[0] = ((uint64_t)target) | PAC_BITMASK; 264 | return kIOReturnSuccess; 265 | } 266 | 267 | // Return a pointer to a chunk of kernel memory 268 | // This is SUPER not thread safe 269 | #define M1_PAGE_SZ ((0x4000ULL)) 270 | #define KERN_MMAP_SIZE ((0xC000 * (M1_PAGE_SZ))) 271 | static uint8_t *kern_mmap_region = NULL; 272 | IOReturn GimmeMemory(OSObject *target, void *reference, IOExternalMethodArguments *args) { 273 | if (NULL == kern_mmap_region) { 274 | kern_mmap_region = (uint8_t *)IOMallocAligned(KERN_MMAP_SIZE, M1_PAGE_SZ); 275 | 276 | if (NULL == kern_mmap_region) { 277 | return kIOReturnError; 278 | } 279 | 280 | memset(kern_mmap_region, 0x41, KERN_MMAP_SIZE); 281 | } 282 | args->scalarOutput[0] = (uint64_t)kern_mmap_region; 283 | return kIOReturnSuccess; 284 | } 285 | 286 | // Free memory allocated by GimmeMemory 287 | // This is SUPER not thread-safe 288 | IOReturn FreeMemory(OSObject *target, void *reference, IOExternalMethodArguments *args) { 289 | if (NULL != kern_mmap_region) { 290 | IOFreeAligned(kern_mmap_region, KERN_MMAP_SIZE); 291 | kern_mmap_region = NULL; 292 | } 293 | return kIOReturnSuccess; 294 | } 295 | 296 | // Return the value of some EL1-only registers 297 | IOReturn TellMeRegs(OSObject *target, void *reference, IOExternalMethodArguments *args) { 298 | args->scalarOutput[0] = SREG_READ(SREG_PMCR0); 299 | args->scalarOutput[1] = SREG_READ("CNTKCTL_EL1"); 300 | return kIOReturnSuccess; 301 | } 302 | 303 | // Do an unchecked read when args[1] is true (nothing when it is false) 304 | // This should be used for simulating a speculative LDR 305 | // Returns the number of CYCLES to access the address! 306 | IOReturn ReadMemoryForTiming(OSObject *target, void *reference, IOExternalMethodArguments *args) { 307 | if (args->scalarInput[1]) { 308 | args->scalarOutput[0] = time_access((args->scalarInput[0] | PAC_BITMASK)); 309 | // args->scalarOutput[0] = *((uint64_t *)(args->scalarInput[0] | PAC_BITMASK)); 310 | } 311 | return kIOReturnSuccess; 312 | } 313 | 314 | // Do an unchecked exec when args[1] is true (nothing when it is false) 315 | // This should be used for simulating a speculative BLR 316 | // Returns the number of CYCLES to exec the address! 317 | IOReturn ExecMemoryForTiming(OSObject *target, void *reference, IOExternalMethodArguments *args) { 318 | if (args->scalarInput[1]) { 319 | args->scalarOutput[0] = time_execute((args->scalarInput[0] | PAC_BITMASK)); 320 | } 321 | return kIOReturnSuccess; 322 | } 323 | 324 | // Leaks the address of retpoline region and LIMIT 325 | IOReturn LeakMethod(OSObject *target, void *reference, IOExternalMethodArguments *args) { 326 | args->scalarOutput[0] = ((uint64_t)(&retpoline)) | PAC_BITMASK; 327 | args->scalarOutput[1] = ((uint64_t)(&LIMIT)) | PAC_BITMASK; 328 | args->scalarOutput[2] = 0x4343434343434ULL; // Don't use this! 329 | return kIOReturnSuccess; 330 | } 331 | 332 | // Read args[0] if args[1] is less than the LIMIT global varaible, do nothing otherwise 333 | IOReturn ReadForSpectre(OSObject *target, void *reference, IOExternalMethodArguments *args) { 334 | uint64_t val_out, addr, flush_me; 335 | // flush_me = ((uint64_t)(&LIMIT)) | PAC_BITMASK; 336 | // asm volatile( 337 | // "dc civac, %[flush_me]\n" 338 | // : 339 | // : [flush_me]"r"(flush_me) 340 | // ); 341 | if (args->scalarInput[1] < LIMIT) { 342 | addr = args->scalarInput[0]; 343 | asm volatile( 344 | "ldr %[val_out], [%[addr]]\n" 345 | : [val_out]"=r"(val_out) 346 | : [addr]"r"(addr) 347 | ); 348 | } 349 | return kIOReturnSuccess; 350 | } 351 | 352 | // Exec args[0] if args[1] is less than the LIMIT global varaible, do nothing otherwise 353 | IOReturn ExecForSpectre(OSObject *target, void *reference, IOExternalMethodArguments *args) { 354 | uint64_t addr; 355 | if (args->scalarInput[1] < LIMIT) { 356 | addr = args->scalarInput[0]; 357 | asm volatile( 358 | "blr %[addr]\n" 359 | : 360 | : [addr]"r"(addr) 361 | : "lr" 362 | ); 363 | } 364 | return kIOReturnSuccess; 365 | } 366 | 367 | // Defer to the PacmanKitService class 368 | IOReturn CallServiceRoutine(OSObject *target, void *reference, IOExternalMethodArguments *args) __attribute__((aligned(0x80))) { 369 | // uint64_t outval; 370 | // uint64_t flush_me = ((uint64_t)(&LIMIT)) | PAC_BITMASK; 371 | // asm volatile( 372 | // "dc civac, %[flush_me]\n" 373 | // : 374 | // : [flush_me]"r"(flush_me) 375 | // ); 376 | if (args->scalarInput[0] < LIMIT) { 377 | // return ((PacmanUser *)target)->helper.externalMethod(); 378 | 379 | // The no-blraa way: 380 | asm volatile( 381 | "ldr x16, [%[helper]]\n" 382 | "mov x17, %[helper]\n" 383 | "movk x17, #0xd986, lsl #48\n" 384 | "autda x16, x17\n" 385 | "ldr x8, [x16]\n" 386 | "mov x9, x16\n" 387 | "mov x17, x9\n" 388 | "movk x17, #0xa7d5, lsl #48\n" 389 | "autia x8, x17\n" 390 | "blr x8" 391 | : 392 | : [helper]"r"(&((PacmanUser *)target)->helper) 393 | : "x8", "x9", "x16", "x17", "lr" 394 | ); 395 | 396 | // The exact C++ way: 397 | // asm volatile( 398 | // "ldr x16, [%[helper]]\n" 399 | // "mov x17, %[helper]\n" 400 | // "movk x17, #0xd986, lsl #48\n" 401 | // "autda x16, x17\n" 402 | // "ldr x8, [x16]\n" 403 | // "mov x9, x16\n" 404 | // "mov x17, x9\n" 405 | // "movk x17, #0xa7d5, lsl #48\n" 406 | // "blraa x8, x17\n" 407 | // : 408 | // : [helper]"r"(&((PacmanUser *)target)->helper) 409 | // : "x8", "x9", "x16", "x17", "lr" 410 | // ); 411 | // IOLog(LOG_PREFIX "outval is 0x%llX\n", outval); 412 | } 413 | return kIOReturnSuccess; 414 | } 415 | 416 | // pacda with arbitrary salt 417 | IOReturn ForgeSignData(OSObject *target, void *reference, IOExternalMethodArguments *args) { 418 | args->scalarOutput[0] = pac_sign_data(args->scalarInput[0], args->scalarInput[1]); 419 | return kIOReturnSuccess; 420 | } 421 | 422 | // autda with arbitrary salt 423 | IOReturn ForgeAuthData(OSObject *target, void *reference, IOExternalMethodArguments *args) { 424 | args->scalarOutput[0] = pac_auth_data(args->scalarInput[0], args->scalarInput[1]); 425 | return kIOReturnSuccess; 426 | } 427 | 428 | // pacia with arbitrary salt 429 | IOReturn ForgeSignInst(OSObject *target, void *reference, IOExternalMethodArguments *args) { 430 | args->scalarOutput[0] = pac_sign_inst(args->scalarInput[0], args->scalarInput[1]); 431 | return kIOReturnSuccess; 432 | } 433 | 434 | // autia with arbitrary salt 435 | IOReturn ForgeAuthInst(OSObject *target, void *reference, IOExternalMethodArguments *args) { 436 | args->scalarOutput[0] = pac_auth_inst(args->scalarInput[0], args->scalarInput[1]); 437 | return kIOReturnSuccess; 438 | } 439 | 440 | // Reveal the current proc pointer 441 | IOReturn LeakCurProc(OSObject *target, void *reference, IOExternalMethodArguments *args) { 442 | args->scalarOutput[0] = (uint64_t)current_proc() | PAC_BITMASK; 443 | return kIOReturnSuccess; 444 | } 445 | 446 | IOReturn PacmanKitService::externalMethod() { 447 | // IOLog(LOG_PREFIX "PacmanKitService call (0x%llX, 0x%llX, 0x%llX, 0x%llX, 0x%llX, 0x%llX)", arg1, arg2, arg3, arg4, arg5, arg6); 448 | return kIOReturnSuccess; 449 | } 450 | 451 | bool PacmanKit::start(IOService *provider) { 452 | bool ret; 453 | 454 | ret = IOService::start(provider); 455 | if (!ret) { 456 | IOService::stop(provider); 457 | return false; 458 | } 459 | 460 | registerService(); 461 | return ret; 462 | } 463 | 464 | bool PacmanUser::initWithTask(task_t owningTask, void * securityToken, UInt32 type) { 465 | if (!owningTask) return false; 466 | if (!IOUserClient::initWithTask(owningTask, securityToken, type)) return false; 467 | this->task = owningTask; 468 | return true; 469 | } 470 | 471 | IOReturn PacmanUser::clientClose() { 472 | terminate(); 473 | return kIOReturnSuccess; 474 | } 475 | 476 | IOReturn PacmanUser::externalMethod(uint32_t selector, 477 | IOExternalMethodArguments * args, 478 | IOExternalMethodDispatch * dispatch, 479 | OSObject * target, 480 | void * reference) { 481 | if (selector >= kPacmanClientNumMethods) { 482 | return kIOReturnUnsupported; 483 | } 484 | return IOUserClient::externalMethod(selector, args, (IOExternalMethodDispatch *)&Methods[selector], this, NULL); 485 | } 486 | -------------------------------------------------------------------------------- /pacmandc/pacmandc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PacmanKit 3 | * Kernel support for the PACMAN DEF CON 30 talk. 4 | */ 5 | 6 | #ifndef PACMAN_DC_H 7 | #define PACMAN_DC_H 8 | 9 | #include 10 | #include 11 | #include "kernel.development.symbols.h" 12 | 13 | // The important registers for PMC 14 | // See osfmk/arm64/kpc.c 15 | #define SREG_PMCR0 "S3_1_c15_c0_0" 16 | #define SREG_PMCR1 "S3_1_c15_c1_0" 17 | #define SREG_PMC0 "S3_2_c15_c0_0" 18 | #define SREG_PMC1 "S3_2_c15_c1_0" 19 | 20 | /* 21 | * SREG_WRITE 22 | * See osfmk/arm64/kpc.c 23 | * Write into an MSR using an instruction barrier afterwords 24 | * MSR[SR] <- V 25 | */ 26 | #define SREG_WRITE(SR, V) \ 27 | __asm__ volatile("msr " SR ", %0 \r\n isb \r\n" : : "r"((uint64_t)V)) 28 | 29 | /* 30 | * SREG_READ 31 | * See osfmk/arm64/kpc.c 32 | * Read from an MSR without any instruction barriers 33 | * Returns MSR[SR] 34 | */ 35 | #define SREG_READ(SR) \ 36 | ({ \ 37 | uint64_t VAL = 0; \ 38 | __asm__ volatile("mrs %0, " SR " \r\n" : "=r"(VAL)); \ 39 | VAL; \ 40 | }) 41 | 42 | // OR with this to remove a PAC for kernel pointers 43 | #define PAC_BITMASK ((0xFFFF800000000000ULL)) 44 | 45 | /* 46 | * pac_sign_inst 47 | * Performs PACIA (sign instruction pointer with A key) on addr using 48 | * salt given by salt. 49 | * 50 | * Returns the signed pointer 51 | */ 52 | __attribute__((always_inline)) static inline uint64_t pac_sign_inst(uint64_t addr, uint64_t salt) { 53 | uint64_t result = addr; 54 | asm volatile( 55 | "pacia %[result], %[salt] \n\r" \ 56 | : [result]"+r"(result) 57 | : [salt]"r"(salt) 58 | : 59 | ); 60 | return result; 61 | } 62 | 63 | /* 64 | * pac_auth_inst 65 | * Performs AUTIA (authenticate instruction pointer with A key) on addr using 66 | * salt given by salt. 67 | * 68 | * Returns the signed pointer 69 | */ 70 | __attribute__((always_inline)) static inline uint64_t pac_auth_inst(uint64_t addr, uint64_t salt) { 71 | uint64_t result = addr; 72 | asm volatile( 73 | "autia %[result], %[salt] \n\r" 74 | : [result]"+r"(result) 75 | : [salt]"r"(salt) 76 | : 77 | ); 78 | return result; 79 | } 80 | 81 | /* 82 | * pac_sign_data 83 | * Performs PACDA (sign data pointer with A key) on addr using 84 | * salt given by salt. 85 | * 86 | * Returns the signed pointer 87 | */ 88 | __attribute__((always_inline)) static inline uint64_t pac_sign_data(uint64_t addr, uint64_t salt) { 89 | uint64_t result = addr; 90 | asm volatile( 91 | "pacda %[result], %[salt] \n\r" \ 92 | : [result]"+r"(result) 93 | : [salt]"r"(salt) 94 | : 95 | ); 96 | return result; 97 | } 98 | 99 | /* 100 | * pac_auth_data 101 | * Performs AUTDA (authenticate data pointer with A key) on addr using 102 | * salt given by salt. 103 | * 104 | * Returns the signed pointer 105 | */ 106 | __attribute__((always_inline)) static inline uint64_t pac_auth_data(uint64_t addr, uint64_t salt) { 107 | uint64_t result = addr; 108 | asm volatile( 109 | "autda %[result], %[salt] \n\r" 110 | : [result]"+r"(result) 111 | : [salt]"r"(salt) 112 | : 113 | ); 114 | return result; 115 | } 116 | 117 | enum PacmanKitOption { 118 | PacmanKernelBase, 119 | PacmanRead, 120 | PacmanWrite, 121 | PacmanKernelVirt2Phys, 122 | PacmanUserVirt2Phys, 123 | PacmanIOUserClientLeak, 124 | PacmanGimmeMemory, 125 | PacmanFreeMemory, 126 | PacmanTellMeRegs, 127 | PacmanReadForTiming, 128 | PacmanExecForTiming, 129 | PacmanLeakMethod, 130 | PacmanReadForSpectre, 131 | PacmanExecForSpectre, 132 | PacmanCallServiceRoutine, 133 | PacmanSignData, 134 | PacmanAuthData, 135 | PacmanSignInst, 136 | PacmanAuthInst, 137 | PacmanLeakProc, 138 | }; 139 | 140 | typedef uint64_t u64; 141 | 142 | /* Client Service class. This is used as a server for extra PacmanKit method calls (`PacmanCallServiceRoutine`). */ 143 | class PacmanKitService { 144 | public: 145 | /* Handle PacmanCallServiceRoutine externalMethod calls for PacmanUser. */ 146 | /* This is the target of our PACMAN attack. */ 147 | virtual IOReturn externalMethod(); 148 | }; 149 | 150 | const size_t kPacmanClientNumMethods = 20; 151 | 152 | /* 153 | * The IOClass for PACMAN. This is the driver's main class. 154 | * 155 | * We use 'IOResources' for the IOProviderClass (in Info.plist) as that is a generic IOKit service. 156 | * We set 'IOResourceMatch' to 'IOKit' to specify that this driver should be loaded whenever IOKit is ready. 157 | */ 158 | class PacmanKit : public IOService { 159 | OSDeclareDefaultStructors(PacmanKit) 160 | virtual bool start(IOService *provider) override; 161 | }; 162 | 163 | /* 164 | * The IOUserClientClass for PACMAN. This is the IOUserClient that interacts with userspace. 165 | */ 166 | class PacmanUser : public IOUserClient { 167 | OSDeclareDefaultStructors(PacmanUser) 168 | 169 | public: 170 | task_t task; 171 | const static IOExternalMethodDispatch Methods[]; 172 | PacmanKitService helper; 173 | 174 | bool initWithTask( 175 | task_t owningTask, void * securityToken, UInt32 type 176 | ) override; 177 | 178 | IOReturn externalMethod( 179 | uint32_t selector, 180 | IOExternalMethodArguments * args, 181 | IOExternalMethodDispatch * dispatch, 182 | OSObject * target, 183 | void * reference 184 | ) override; 185 | 186 | IOReturn clientClose() override; 187 | }; 188 | 189 | /* PacmanUser API */ 190 | IOReturn KernelBaseLeak(OSObject *target, void *reference, IOExternalMethodArguments *args); 191 | IOReturn ReadMemorySafe(OSObject *target, void *reference, IOExternalMethodArguments *args); 192 | IOReturn ReadMemoryUnsafe(OSObject *target, void *reference, IOExternalMethodArguments *args); 193 | IOReturn WriteMemory(OSObject *target, void *reference, IOExternalMethodArguments *args); 194 | IOReturn KernelVirt2Phys(OSObject *target, void *reference, IOExternalMethodArguments *args); 195 | IOReturn UserVirt2Phys(OSObject *target, void *reference, IOExternalMethodArguments *args); 196 | IOReturn IOUserClientLeak(OSObject *target, void *reference, IOExternalMethodArguments *args); 197 | IOReturn GimmeMemory(OSObject *target, void *reference, IOExternalMethodArguments *args); 198 | IOReturn FreeMemory(OSObject *target, void *reference, IOExternalMethodArguments *args); 199 | IOReturn TellMeRegs(OSObject *target, void *reference, IOExternalMethodArguments *args); 200 | IOReturn ReadMemoryForTiming(OSObject *target, void *reference, IOExternalMethodArguments *args); 201 | IOReturn ExecMemoryForTiming(OSObject *target, void *reference, IOExternalMethodArguments *args); 202 | IOReturn LeakMethod(OSObject *target, void *reference, IOExternalMethodArguments *args); 203 | IOReturn ReadForSpectre(OSObject *target, void *reference, IOExternalMethodArguments *args); 204 | IOReturn ExecForSpectre(OSObject *target, void *reference, IOExternalMethodArguments *args); 205 | IOReturn CallServiceRoutine(OSObject *target, void *reference, IOExternalMethodArguments *args); 206 | IOReturn ForgeSignData(OSObject *target, void *reference, IOExternalMethodArguments *args); 207 | IOReturn ForgeAuthData(OSObject *target, void *reference, IOExternalMethodArguments *args); 208 | IOReturn ForgeSignInst(OSObject *target, void *reference, IOExternalMethodArguments *args); 209 | IOReturn ForgeAuthInst(OSObject *target, void *reference, IOExternalMethodArguments *args); 210 | IOReturn LeakCurProc(OSObject *target, void *reference, IOExternalMethodArguments *args); 211 | 212 | /* Helper routines */ 213 | static void do_nothing(void); 214 | static void win(void); 215 | 216 | extern "C" void retpoline(void); 217 | 218 | extern "C" void win_c(void); 219 | 220 | #endif // PACMAN_DC_H 221 | -------------------------------------------------------------------------------- /pacmandc/win.s: -------------------------------------------------------------------------------- 1 | 2 | // This may be a bit of a misnomer, this is a giant trampoline made of retpolines 3 | // but this is not the same thing as the Spectre v1 mitigation in Linux of the same name 4 | .global _retpoline 5 | 6 | .extern _win_c 7 | 8 | //pub const RET_INST : u32 = 0xd65f03c0; 9 | //pub const NOP_INST : u32 = 0xd503201f; 10 | 11 | .align 21 12 | _retpoline: 13 | .fill 0x1000,4,0xD503201F 14 | b _win_c 15 | -------------------------------------------------------------------------------- /pacmandc/win_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LOG_PREFIX "[PacmanKit]" 4 | 5 | void win_c(void) { 6 | os_log(OS_LOG_DEFAULT, LOG_PREFIX "You won!\n"); 7 | } 8 | --------------------------------------------------------------------------------