If you google around about how to build an osx kext you will find very few results, a few email messages saying not to bother or that it it impossible.
So what’s all the voodoo about. A few defines, some linker options, some compiler options. Also a special info.c file and Info.plist.
Note: if you want to sign your kernel module you will need to apply to apple for a special kernel module code signing certificate.
Setup basic cmake project. We need 3.8 or newer to use BUNDLE_EXTENSION for the .kext bundle type.
cmake_minimum_required (VERSION 3.8) project (example)
Setup some variables for later. These are both optional if you use the default system sdk or you don’t want to code sign.
set(CODE_SIGN_ID "Developer ID Application: Your Name. (XYZZYYZYZY)") set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/)
Add a debug preprocessor def. This is optional.
if(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DDEBUG)
endif()
Add the special preprocessor defines to access internal kernel structures.
add_definitions(
-DKERNEL
-DKERNEL_PRIVATE
-DDRIVER_PRIVATE
-DAPPLE
-DNeXT
)
Add include directories for osx kernel headers and private headers.
include_directories(
${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/PrivateHeaders
${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/Headers
)
Add an executable bundle target.
add_executable(
${PROJECT_NAME}
MACOSX_BUNDLE
example.c
example_info.c
Info.plist
)
Set the target bundle extension to “kext” and the plist file.
set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE_EXTENSION kext MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/Info.plist)
Set a million compile options. These were taken from a minimal xcode project.
Note: The -mmacosx-version-min=10.10 can be removed or changed to support older versions of OSX.
add_compile_options(${PROJECT_NAME}
-x c -arch x86_64 -fmessage-length=0
-fdiagnostics-show-note-include-stack
-fmacro-backtrace-limit=0 -nostdinc
-std=gnu99 -fmodules -gmodules
-Wnon-modular-include-in-framework-module
-Werror=non-modular-include-in-framework-module
-fno-builtin -Wno-trigraphs -msoft-float -O0 -fno-common
-mkernel -Wno-missing-field-initializers -Wno-missing-prototypes
-Werror=return-type -Wdocumentation -Wunreachable-code
-Werror=deprecated-objc-isa-usage -Werror=objc-root-class
-Wno-missing-braces -Wparentheses -Wswitch -Wunused-function
-Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value
-Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas
-Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion
-Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32
-Wpointer-sign -Wno-newline-eof
-fasm-blocks -fstrict-aliasing -Wdeprecated-declarations
-mmacosx-version-min=10.10 -Wno-sign-conversion
-Winfinite-recursion -iquote
)
Add the libraries required for the kernel module and linker options.
Note: The -mmacosx-version-min=10.10 can be removed or changed to support older versions of OSX.
target_link_libraries(${PROJECT_NAME}
"-lkmodc++"
"-lkmod"
"-lcc_kext"
"-arch x86_64"
"-mmacosx-version-min=10.10"
"-nostdlib"
"-Xlinker -object_path_lto"
"-Xlinker -export_dynamic"
"-Xlinker -kext"
)
Add a custom target to sign the kernel module. This can be skipped if code signing isn’t needed.
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMENT "Code Signing Kext With: ${CODE_SIGN_ID}"
VERBATIM
COMMAND
/usr/bin/codesign -s "${CODE_SIGN_ID}" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.kext"
)
The example.c file:
#include <sys/kernel_types.h>
#include <sys/systm.h>
kern_return_t example_start(kmod_info_t * ki, void *d) {
printf("Loaded example\n");
return KERN_SUCCESS;
}
kern_return_t example_stop(kmod_info_t *ki, void *d) {
printf("example unloading.\n");
return KERN_SUCCESS;
}
The example_info.c File. This is usually generated by xcode during the build process.
It just sets the main entry points to example_start and example_stop
#include <mach/mach_types.h>
extern kern_return_t _start(kmod_info_t *ki, void *data);
extern kern_return_t _stop(kmod_info_t *ki, void *data);
__private_extern__ kern_return_t example_start(kmod_info_t *ki, void *data);
__private_extern__ kern_return_t example_stop(kmod_info_t *ki, void *data);
__attribute__((visibility("default"))) KMOD_EXPLICIT_DECL(com.example, "1.0.0d1", _start, _stop)
__private_extern__ kmod_start_func_t *_realmain = example_start;
__private_extern__ kmod_stop_func_t *_antimain = example_stop;
__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;
The complete cmake file.
cmake_minimum_required (VERSION 3.8)
project (example)
set(CODE_SIGN_ID "Developer ID Application: Your Name. (XYZZYYZYZY)")
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/)
if(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DDEBUG)
endif()
add_definitions(
-DKERNEL
-DKERNEL_PRIVATE
-DDRIVER_PRIVATE
-DAPPLE
-DNeXT
)
include_directories(
${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/PrivateHeaders
${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/Headers
)
add_executable(
${PROJECT_NAME}
MACOSX_BUNDLE
example.c
example_info.c
Info.plist
)
set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE_EXTENSION kext MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/Info.plist)
add_compile_options(${PROJECT_NAME}
-x c -arch x86_64 -fmessage-length=0
-fdiagnostics-show-note-include-stack
-fmacro-backtrace-limit=0 -nostdinc
-std=gnu99 -fmodules -gmodules
-Wnon-modular-include-in-framework-module
-Werror=non-modular-include-in-framework-module
-fno-builtin -Wno-trigraphs -msoft-float -O0 -fno-common
-mkernel -Wno-missing-field-initializers -Wno-missing-prototypes
-Werror=return-type -Wdocumentation -Wunreachable-code
-Werror=deprecated-objc-isa-usage -Werror=objc-root-class
-Wno-missing-braces -Wparentheses -Wswitch -Wunused-function
-Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value
-Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas
-Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion
-Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32
-Wpointer-sign -Wno-newline-eof
-fasm-blocks -fstrict-aliasing -Wdeprecated-declarations
-mmacosx-version-min=10.11 -Wno-sign-conversion
-Winfinite-recursion -iquote
)
# delete this to not code sign
target_link_libraries(${PROJECT_NAME}
"-lkmodc++"
"-lkmod"
"-lcc_kext"
"-arch x86_64"
"-mmacosx-version-min=10.11"
"-nostdlib"
"-Xlinker -object_path_lto"
"-Xlinker -export_dynamic"
"-Xlinker -kext"
)
The magic Info.plist file. All references to “example” will need to match the binary and com.example items.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>BuildMachineOSBuild</key> <string>15G31</string> <key>CFBundleDevelopmentRegion</key> <string>en</string> <key>CFBundleExecutable</key> <string>example</string> <key>CFBundleIdentifier</key> <string>com.example</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>example</string> <key>CFBundlePackageType</key> <string>KEXT</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleSupportedPlatforms</key> <array> <string>MacOSX</string> </array> <key>CFBundleVersion</key> <string>1</string> <key>DTCompiler</key> <string>com.apple.compilers.llvm.clang.1_0</string> <key>DTPlatformBuild</key> <string>8A218a</string> <key>DTPlatformVersion</key> <string>GM</string> <key>DTSDKBuild</key> <string>16A300</string> <key>DTSDKName</key> <string>macosx10.12</string> <key>DTXcode</key> <string>0800</string> <key>DTXcodeBuild</key> <string>8A218a</string> <key>NSHumanReadableCopyright</key> <string>Copyright © 2017 Someone. All rights reserved.</string> <key>OSBundleLibraries</key> <dict> <key>com.apple.kpi.bsd</key> <string>8.0.0</string> <key>com.apple.kpi.libkern</key> <string>8.0.0</string> <key>com.apple.kpi.mach</key> <string>8.0.0</string> </dict> </dict> </plist>
GitHub Repository with the example.