{"id":53,"date":"2017-09-25T04:58:24","date_gmt":"2017-09-25T04:58:24","guid":{"rendered":"http:\/\/www.goodbits.ca\/?p=53"},"modified":"2017-12-11T16:41:15","modified_gmt":"2017-12-11T16:41:15","slug":"building-an-apple-osx-kernel-module-with-cmake-cc","status":"publish","type":"post","link":"http:\/\/www.goodbits.ca\/index.php\/2017\/09\/25\/building-an-apple-osx-kernel-module-with-cmake-cc\/","title":{"rendered":"Building an Apple OSX Kernel Module With CMake &#8211; C\/C++"},"content":{"rendered":"<p>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.<\/p>\n<p>So what&#8217;s all the voodoo about. \u00a0A few defines, some linker options, some compiler options. Also a special info.c file and Info.plist.<\/p>\n<p>Note: if you want to sign your kernel module you will need to apply to apple for a special kernel module code signing certificate.<\/p>\n<p>Setup basic cmake project. We need 3.8 or newer to use\u00a0BUNDLE_EXTENSION for the .kext bundle type.<\/p>\n<pre class=\"lang:default decode:true\">cmake_minimum_required (VERSION 3.8)\r\n\r\nproject (example)<\/pre>\n<p>Setup some variables for later. These are both optional if you use the default system sdk or you don&#8217;t want to code sign.<\/p>\n<pre class=\"lang:default decode:true\">set(CODE_SIGN_ID \"Developer ID Application: Your Name. (XYZZYYZYZY)\")\r\nset(CMAKE_OSX_SYSROOT \/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/MacOSX.platform\/Developer\/SDKs\/MacOSX10.10.sdk\/)\r\n<\/pre>\n<p>Add a debug preprocessor def. This is optional.<\/p>\n<pre class=\"lang:default decode:true \">if(CMAKE_BUILD_TYPE MATCHES Debug)\r\n        add_definitions(-DDEBUG)\r\nendif()<\/pre>\n<p>Add the special preprocessor defines to access internal kernel structures.<\/p>\n<pre class=\"lang:default decode:true \">add_definitions(\r\n        -DKERNEL\r\n        -DKERNEL_PRIVATE\r\n        -DDRIVER_PRIVATE\r\n        -DAPPLE\r\n        -DNeXT\r\n)<\/pre>\n<p>Add include directories for osx kernel headers and private headers.<\/p>\n<pre class=\"lang:default decode:true\">include_directories(\r\n        ${CMAKE_OSX_SYSROOT}\/System\/Library\/Frameworks\/Kernel.framework\/PrivateHeaders\r\n        ${CMAKE_OSX_SYSROOT}\/System\/Library\/Frameworks\/Kernel.framework\/Headers\r\n)<\/pre>\n<p>Add an executable bundle target.<\/p>\n<pre class=\"lang:default decode:true\">add_executable(\r\n        ${PROJECT_NAME}\r\n        MACOSX_BUNDLE\r\n        example.c\r\n        example_info.c\r\n        Info.plist\r\n)<\/pre>\n<p>Set the target bundle extension to &#8220;kext&#8221; and the plist file.<\/p>\n<pre class=\"lang:default decode:true \">set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE_EXTENSION kext MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}\/Info.plist)<\/pre>\n<p>Set a million compile options. \u00a0These were taken from a minimal xcode project.<\/p>\n<p>Note: The\u00a0-mmacosx-version-min=10.10 can be removed or changed to support older versions of OSX.<\/p>\n<pre class=\"lang:default decode:true\">add_compile_options(${PROJECT_NAME}\r\n        -x c -arch x86_64 -fmessage-length=0\r\n        -fdiagnostics-show-note-include-stack\r\n        -fmacro-backtrace-limit=0 -nostdinc\r\n        -std=gnu99 -fmodules -gmodules\r\n        -Wnon-modular-include-in-framework-module\r\n        -Werror=non-modular-include-in-framework-module\r\n        -fno-builtin -Wno-trigraphs -msoft-float -O0 -fno-common\r\n        -mkernel -Wno-missing-field-initializers -Wno-missing-prototypes\r\n        -Werror=return-type -Wdocumentation -Wunreachable-code\r\n        -Werror=deprecated-objc-isa-usage -Werror=objc-root-class\r\n        -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function\r\n        -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value\r\n        -Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas\r\n        -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion\r\n        -Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32\r\n        -Wpointer-sign -Wno-newline-eof\r\n        -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations\r\n        -mmacosx-version-min=10.10 -Wno-sign-conversion\r\n        -Winfinite-recursion -iquote\r\n)<\/pre>\n<p>&nbsp;<\/p>\n<p>Add the libraries required for the kernel module and linker options.<\/p>\n<p>Note: The\u00a0-mmacosx-version-min=10.10 can be removed or changed to support older versions of OSX.<\/p>\n<pre class=\"lang:default decode:true\">target_link_libraries(${PROJECT_NAME}\r\n        \"-lkmodc++\"\r\n        \"-lkmod\"\r\n        \"-lcc_kext\"\r\n        \"-arch x86_64\"\r\n        \"-mmacosx-version-min=10.10\"\r\n        \"-nostdlib\"\r\n        \"-Xlinker -object_path_lto\"\r\n        \"-Xlinker -export_dynamic\"\r\n        \"-Xlinker -kext\"\r\n)<\/pre>\n<p>Add a custom target to sign the kernel module. \u00a0This can be skipped if code signing isn&#8217;t needed.<\/p>\n<pre class=\"lang:default decode:true \">add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD\r\n        COMMENT \"Code Signing Kext With: ${CODE_SIGN_ID}\"\r\n        VERBATIM\r\n        COMMAND\r\n        \/usr\/bin\/codesign -s \"${CODE_SIGN_ID}\" \"${CMAKE_CURRENT_BINARY_DIR}\/${PROJECT_NAME}.kext\"\r\n)<\/pre>\n<p>The example.c file:<\/p>\n<pre class=\"lang:c decode:true\">#include &lt;sys\/kernel_types.h&gt;\r\n#include &lt;sys\/systm.h&gt;\r\n\r\nkern_return_t example_start(kmod_info_t * ki, void *d) {\r\n        printf(\"Loaded example\\n\");\r\n        return KERN_SUCCESS;\r\n}\r\n\r\nkern_return_t example_stop(kmod_info_t *ki, void *d) {\r\n        printf(\"example unloading.\\n\");\r\n        return KERN_SUCCESS;\r\n}<\/pre>\n<p>The example_info.c File. \u00a0This is usually generated by xcode during the build process.<\/p>\n<p>It just sets the main entry points to example_start and example_stop<\/p>\n<pre class=\"lang:c decode:true\">#include &lt;mach\/mach_types.h&gt;\r\n\r\nextern kern_return_t _start(kmod_info_t *ki, void *data);\r\nextern kern_return_t _stop(kmod_info_t *ki, void *data);\r\n__private_extern__ kern_return_t example_start(kmod_info_t *ki, void *data);\r\n__private_extern__ kern_return_t example_stop(kmod_info_t *ki, void *data);\r\n\r\n__attribute__((visibility(\"default\"))) KMOD_EXPLICIT_DECL(com.example, \"1.0.0d1\", _start, _stop)\r\n__private_extern__ kmod_start_func_t *_realmain = example_start;\r\n__private_extern__ kmod_stop_func_t *_antimain = example_stop;\r\n__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;<\/pre>\n<p>&nbsp;<\/p>\n<p>The complete cmake file.<\/p>\n<pre class=\"lang:default decode:true \">cmake_minimum_required (VERSION 3.8)\r\n\r\nproject (example)\r\n\r\nset(CODE_SIGN_ID \"Developer ID Application: Your Name. (XYZZYYZYZY)\")\r\nset(CMAKE_OSX_SYSROOT \/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/MacOSX.platform\/Developer\/SDKs\/MacOSX10.11.sdk\/)\r\n\r\n\r\nif(CMAKE_BUILD_TYPE MATCHES Debug)\r\n\tadd_definitions(-DDEBUG)\r\nendif()\r\n\r\nadd_definitions(\r\n\t-DKERNEL\r\n\t-DKERNEL_PRIVATE\r\n\t-DDRIVER_PRIVATE\r\n\t-DAPPLE\r\n\t-DNeXT\r\n)\r\n\r\ninclude_directories(\r\n\t${CMAKE_OSX_SYSROOT}\/System\/Library\/Frameworks\/Kernel.framework\/PrivateHeaders\r\n\t${CMAKE_OSX_SYSROOT}\/System\/Library\/Frameworks\/Kernel.framework\/Headers\r\n)\r\n\r\nadd_executable(\r\n\t${PROJECT_NAME}\r\n\tMACOSX_BUNDLE\r\n\texample.c\r\n\texample_info.c\r\n\tInfo.plist\r\n)\r\n\r\nset_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE_EXTENSION kext MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}\/Info.plist)\r\n\r\n\r\nadd_compile_options(${PROJECT_NAME}\r\n\t-x c -arch x86_64 -fmessage-length=0\r\n\t-fdiagnostics-show-note-include-stack\r\n\t-fmacro-backtrace-limit=0 -nostdinc\r\n\t-std=gnu99 -fmodules -gmodules\r\n\t-Wnon-modular-include-in-framework-module\r\n\t-Werror=non-modular-include-in-framework-module\r\n\t-fno-builtin -Wno-trigraphs -msoft-float -O0 -fno-common\r\n\t-mkernel -Wno-missing-field-initializers -Wno-missing-prototypes\r\n\t-Werror=return-type -Wdocumentation -Wunreachable-code\r\n\t-Werror=deprecated-objc-isa-usage -Werror=objc-root-class\r\n\t-Wno-missing-braces -Wparentheses -Wswitch -Wunused-function\r\n\t-Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value\r\n\t-Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas\r\n\t-Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion\r\n\t-Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32\r\n\t-Wpointer-sign -Wno-newline-eof\r\n\t-fasm-blocks -fstrict-aliasing -Wdeprecated-declarations\r\n\t-mmacosx-version-min=10.11 -Wno-sign-conversion\r\n\t-Winfinite-recursion -iquote\r\n)\r\n\r\n# delete this to not code sign\r\ntarget_link_libraries(${PROJECT_NAME} \r\n\t\"-lkmodc++\"\r\n\t\"-lkmod\"\r\n\t\"-lcc_kext\"\r\n\t\"-arch x86_64\"\r\n\t\"-mmacosx-version-min=10.11\"\r\n\t\"-nostdlib\"\r\n\t\"-Xlinker -object_path_lto\"\r\n\t\"-Xlinker -export_dynamic\"\r\n\t\"-Xlinker -kext\"\r\n)\r\n<\/pre>\n<p>The magic Info.plist file. \u00a0All references to &#8220;example&#8221; will need to match the binary and com.example items.<\/p>\n<pre class=\"lang:default decode:true\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;!DOCTYPE plist PUBLIC \"-\/\/Apple\/\/DTD PLIST 1.0\/\/EN\" \"http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd\"&gt;\r\n&lt;plist version=\"1.0\"&gt;\r\n&lt;dict&gt;\r\n\t&lt;key&gt;BuildMachineOSBuild&lt;\/key&gt;\r\n\t&lt;string&gt;15G31&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleDevelopmentRegion&lt;\/key&gt;\r\n\t&lt;string&gt;en&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleExecutable&lt;\/key&gt;\r\n\t&lt;string&gt;example&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleIdentifier&lt;\/key&gt;\r\n\t&lt;string&gt;com.example&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleInfoDictionaryVersion&lt;\/key&gt;\r\n\t&lt;string&gt;6.0&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleName&lt;\/key&gt;\r\n\t&lt;string&gt;example&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundlePackageType&lt;\/key&gt;\r\n\t&lt;string&gt;KEXT&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleShortVersionString&lt;\/key&gt;\r\n\t&lt;string&gt;1.0&lt;\/string&gt;\r\n\t&lt;key&gt;CFBundleSupportedPlatforms&lt;\/key&gt;\r\n\t&lt;array&gt;\r\n\t\t&lt;string&gt;MacOSX&lt;\/string&gt;\r\n\t&lt;\/array&gt;\r\n\t&lt;key&gt;CFBundleVersion&lt;\/key&gt;\r\n\t&lt;string&gt;1&lt;\/string&gt;\r\n\t&lt;key&gt;DTCompiler&lt;\/key&gt;\r\n\t&lt;string&gt;com.apple.compilers.llvm.clang.1_0&lt;\/string&gt;\r\n\t&lt;key&gt;DTPlatformBuild&lt;\/key&gt;\r\n\t&lt;string&gt;8A218a&lt;\/string&gt;\r\n\t&lt;key&gt;DTPlatformVersion&lt;\/key&gt;\r\n\t&lt;string&gt;GM&lt;\/string&gt;\r\n\t&lt;key&gt;DTSDKBuild&lt;\/key&gt;\r\n\t&lt;string&gt;16A300&lt;\/string&gt;\r\n\t&lt;key&gt;DTSDKName&lt;\/key&gt;\r\n\t&lt;string&gt;macosx10.12&lt;\/string&gt;\r\n\t&lt;key&gt;DTXcode&lt;\/key&gt;\r\n\t&lt;string&gt;0800&lt;\/string&gt;\r\n\t&lt;key&gt;DTXcodeBuild&lt;\/key&gt;\r\n\t&lt;string&gt;8A218a&lt;\/string&gt;\r\n\t&lt;key&gt;NSHumanReadableCopyright&lt;\/key&gt;\r\n\t&lt;string&gt;Copyright \u00a9 2017 Someone. All rights reserved.&lt;\/string&gt;\r\n\t&lt;key&gt;OSBundleLibraries&lt;\/key&gt;\r\n\t&lt;dict&gt;\r\n\t\t&lt;key&gt;com.apple.kpi.bsd&lt;\/key&gt;\r\n\t\t&lt;string&gt;8.0.0&lt;\/string&gt;\r\n\t\t&lt;key&gt;com.apple.kpi.libkern&lt;\/key&gt;\r\n\t\t&lt;string&gt;8.0.0&lt;\/string&gt;\r\n\t\t&lt;key&gt;com.apple.kpi.mach&lt;\/key&gt;\r\n\t\t&lt;string&gt;8.0.0&lt;\/string&gt;\r\n\t&lt;\/dict&gt;\r\n&lt;\/dict&gt;\r\n&lt;\/plist&gt;\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/github.com\/zzzjim\/goodbits-osx-kernel-module\/\">GitHub Repository with the example.<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;s all the voodoo about. \u00a0A few defines, some linker options, some compiler options. Also a special info.c file and Info.plist. Note: if you &hellip; <a href=\"http:\/\/www.goodbits.ca\/index.php\/2017\/09\/25\/building-an-apple-osx-kernel-module-with-cmake-cc\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Building an Apple OSX Kernel Module With CMake &#8211; C\/C++<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,17],"tags":[],"class_list":["post-53","post","type-post","status-publish","format-standard","hentry","category-kernel","category-mac"],"_links":{"self":[{"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/posts\/53","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/comments?post=53"}],"version-history":[{"count":7,"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/posts\/53\/revisions"}],"predecessor-version":[{"id":61,"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/posts\/53\/revisions\/61"}],"wp:attachment":[{"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/media?parent=53"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/categories?post=53"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodbits.ca\/index.php\/wp-json\/wp\/v2\/tags?post=53"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}