├── loader-test ├── loader.1 └── main.c ├── loader.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── loader ├── loader.c ├── loader.h ├── objc1_runtime.h ├── objc2_runtime.h ├── objc_lexer.c ├── objc_lexer.h ├── objc_runtime.c ├── objc_runtime.h ├── runtime_base.c ├── runtime_base.h ├── runtime_base.s ├── type_register.h └── util.h /loader-test/loader.1: -------------------------------------------------------------------------------- 1 | .\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. 2 | .\"See Also: 3 | .\"man mdoc.samples for a complete listing of options 4 | .\"man mdoc for the short list of editing options 5 | .\"/usr/share/misc/mdoc.template 6 | .Dd 2/17/14 \" DATE 7 | .Dt loader 1 \" Program name and manual section number 8 | .Os Darwin 9 | .Sh NAME \" Section Header - required - don't modify 10 | .Nm loader, 11 | .\" The following lines are read in generating the apropos(man -k) database. Use only key 12 | .\" words here as the database is built based on the words here and in the .ND line. 13 | .Nm Other_name_for_same_program(), 14 | .Nm Yet another name for the same program. 15 | .\" Use .Nm macro to designate other names for the documented program. 16 | .Nd This line parsed for whatis database. 17 | .Sh SYNOPSIS \" Section Header - required - don't modify 18 | .Nm 19 | .Op Fl abcd \" [-abcd] 20 | .Op Fl a Ar path \" [-a path] 21 | .Op Ar file \" [file] 22 | .Op Ar \" [file ...] 23 | .Ar arg0 \" Underlined argument - use .Ar anywhere to underline 24 | arg2 ... \" Arguments 25 | .Sh DESCRIPTION \" Section Header - required - don't modify 26 | Use the .Nm macro to refer to your program throughout the man page like such: 27 | .Nm 28 | Underlining is accomplished with the .Ar macro like this: 29 | .Ar underlined text . 30 | .Pp \" Inserts a space 31 | A list of items with descriptions: 32 | .Bl -tag -width -indent \" Begins a tagged list 33 | .It item a \" Each item preceded by .It macro 34 | Description of item a 35 | .It item b 36 | Description of item b 37 | .El \" Ends the list 38 | .Pp 39 | A list of flags and their descriptions: 40 | .Bl -tag -width -indent \" Differs from above in tag removed 41 | .It Fl a \"-a flag as a list item 42 | Description of -a flag 43 | .It Fl b 44 | Description of -b flag 45 | .El \" Ends the list 46 | .Pp 47 | .\" .Sh ENVIRONMENT \" May not be needed 48 | .\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 49 | .\" .It Ev ENV_VAR_1 50 | .\" Description of ENV_VAR_1 51 | .\" .It Ev ENV_VAR_2 52 | .\" Description of ENV_VAR_2 53 | .\" .El 54 | .Sh FILES \" File used or created by the topic of the man page 55 | .Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact 56 | .It Pa /usr/share/file_name 57 | FILE_1 description 58 | .It Pa /Users/joeuser/Library/really_long_file_name 59 | FILE_2 description 60 | .El \" Ends the list 61 | .\" .Sh DIAGNOSTICS \" May not be needed 62 | .\" .Bl -diag 63 | .\" .It Diagnostic Tag 64 | .\" Diagnostic informtion here. 65 | .\" .It Diagnostic Tag 66 | .\" Diagnostic informtion here. 67 | .\" .El 68 | .Sh SEE ALSO 69 | .\" List links in ascending order by section, alphabetically within a section. 70 | .\" Please do not reference files that do not exist without filing a bug report 71 | .Xr a 1 , 72 | .Xr b 1 , 73 | .Xr c 1 , 74 | .Xr a 2 , 75 | .Xr b 2 , 76 | .Xr a 3 , 77 | .Xr b 3 78 | .\" .Sh BUGS \" Document known, unremedied bugs 79 | .\" .Sh HISTORY \" Document history if command behaves in a unique manner -------------------------------------------------------------------------------- /loader-test/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // loader 4 | // 5 | // Created by Sam Marshall on 2/17/14. 6 | // Copyright (c) 2014 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | 14 | // insert code here... 15 | printf("%i\n",sizeof(char[16])); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /loader.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 221E01F918B2A9C90005F6A0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 221E01F818B2A9C90005F6A0 /* main.c */; }; 11 | 221E01FB18B2A9C90005F6A0 /* loader.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 221E01FA18B2A9C90005F6A0 /* loader.1 */; }; 12 | 221E022C18B2AF4F0005F6A0 /* loader.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E020A18B2AA3E0005F6A0 /* loader.h */; }; 13 | 221E023118B2B6D60005F6A0 /* loader.c in Sources */ = {isa = PBXBuildFile; fileRef = 221E023018B2B6D60005F6A0 /* loader.c */; }; 14 | 221E023E18B2E9880005F6A0 /* objc_lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 221E023418B2E9880005F6A0 /* objc_lexer.c */; }; 15 | 221E023F18B2E9880005F6A0 /* objc_lexer.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E023518B2E9880005F6A0 /* objc_lexer.h */; }; 16 | 221E024018B2E9880005F6A0 /* objc_runtime.c in Sources */ = {isa = PBXBuildFile; fileRef = 221E023618B2E9880005F6A0 /* objc_runtime.c */; }; 17 | 221E024118B2E9880005F6A0 /* objc_runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E023718B2E9880005F6A0 /* objc_runtime.h */; }; 18 | 221E024218B2E9880005F6A0 /* objc1_runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E023818B2E9880005F6A0 /* objc1_runtime.h */; }; 19 | 221E024318B2E9880005F6A0 /* objc2_runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E023918B2E9880005F6A0 /* objc2_runtime.h */; }; 20 | 221E024418B2E9880005F6A0 /* runtime_base.c in Sources */ = {isa = PBXBuildFile; fileRef = 221E023A18B2E9880005F6A0 /* runtime_base.c */; }; 21 | 221E024518B2E9880005F6A0 /* runtime_base.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E023B18B2E9880005F6A0 /* runtime_base.h */; }; 22 | 221E024618B2E9880005F6A0 /* runtime_base.s in Sources */ = {isa = PBXBuildFile; fileRef = 221E023C18B2E9880005F6A0 /* runtime_base.s */; }; 23 | 221E024718B2E9880005F6A0 /* type_register.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E023D18B2E9880005F6A0 /* type_register.h */; }; 24 | 221E024818B2EA840005F6A0 /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 221E022F18B2B4800005F6A0 /* util.h */; }; 25 | 221E024A18B2EB420005F6A0 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 221E024918B2EB420005F6A0 /* libobjc.dylib */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXCopyFilesBuildPhase section */ 29 | 221E01F318B2A9C90005F6A0 /* CopyFiles */ = { 30 | isa = PBXCopyFilesBuildPhase; 31 | buildActionMask = 2147483647; 32 | dstPath = /usr/share/man/man1/; 33 | dstSubfolderSpec = 0; 34 | files = ( 35 | 221E01FB18B2A9C90005F6A0 /* loader.1 in CopyFiles */, 36 | ); 37 | runOnlyForDeploymentPostprocessing = 1; 38 | }; 39 | /* End PBXCopyFilesBuildPhase section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 221E01F518B2A9C90005F6A0 /* loader-test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "loader-test"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 221E01F818B2A9C90005F6A0 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 44 | 221E01FA18B2A9C90005F6A0 /* loader.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = loader.1; sourceTree = ""; }; 45 | 221E020518B2A9FE0005F6A0 /* libloader.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libloader.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 221E020A18B2AA3E0005F6A0 /* loader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = loader.h; sourceTree = ""; }; 47 | 221E022F18B2B4800005F6A0 /* util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; 48 | 221E023018B2B6D60005F6A0 /* loader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = loader.c; sourceTree = ""; }; 49 | 221E023418B2E9880005F6A0 /* objc_lexer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = objc_lexer.c; sourceTree = ""; }; 50 | 221E023518B2E9880005F6A0 /* objc_lexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objc_lexer.h; sourceTree = ""; }; 51 | 221E023618B2E9880005F6A0 /* objc_runtime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = objc_runtime.c; sourceTree = ""; }; 52 | 221E023718B2E9880005F6A0 /* objc_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objc_runtime.h; sourceTree = ""; }; 53 | 221E023818B2E9880005F6A0 /* objc1_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objc1_runtime.h; sourceTree = ""; }; 54 | 221E023918B2E9880005F6A0 /* objc2_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objc2_runtime.h; sourceTree = ""; }; 55 | 221E023A18B2E9880005F6A0 /* runtime_base.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = runtime_base.c; sourceTree = ""; }; 56 | 221E023B18B2E9880005F6A0 /* runtime_base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runtime_base.h; sourceTree = ""; }; 57 | 221E023C18B2E9880005F6A0 /* runtime_base.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = runtime_base.s; sourceTree = ""; }; 58 | 221E023D18B2E9880005F6A0 /* type_register.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type_register.h; sourceTree = ""; }; 59 | 221E024918B2EB420005F6A0 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = usr/lib/libobjc.dylib; sourceTree = SDKROOT; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 221E01F218B2A9C90005F6A0 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 221E020218B2A9FE0005F6A0 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | 221E024A18B2EB420005F6A0 /* libobjc.dylib in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | 221E01EC18B2A9C90005F6A0 = { 82 | isa = PBXGroup; 83 | children = ( 84 | 221E024918B2EB420005F6A0 /* libobjc.dylib */, 85 | 221E020918B2AA0F0005F6A0 /* loader */, 86 | 221E01F718B2A9C90005F6A0 /* loader-test */, 87 | 221E01F618B2A9C90005F6A0 /* Products */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | 221E01F618B2A9C90005F6A0 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 221E01F518B2A9C90005F6A0 /* loader-test */, 95 | 221E020518B2A9FE0005F6A0 /* libloader.dylib */, 96 | ); 97 | name = Products; 98 | sourceTree = ""; 99 | }; 100 | 221E01F718B2A9C90005F6A0 /* loader-test */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 221E01F818B2A9C90005F6A0 /* main.c */, 104 | 221E01FA18B2A9C90005F6A0 /* loader.1 */, 105 | ); 106 | path = "loader-test"; 107 | sourceTree = ""; 108 | }; 109 | 221E020918B2AA0F0005F6A0 /* loader */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 221E022F18B2B4800005F6A0 /* util.h */, 113 | 221E020A18B2AA3E0005F6A0 /* loader.h */, 114 | 221E023018B2B6D60005F6A0 /* loader.c */, 115 | 221E023518B2E9880005F6A0 /* objc_lexer.h */, 116 | 221E023418B2E9880005F6A0 /* objc_lexer.c */, 117 | 221E023718B2E9880005F6A0 /* objc_runtime.h */, 118 | 221E023818B2E9880005F6A0 /* objc1_runtime.h */, 119 | 221E023918B2E9880005F6A0 /* objc2_runtime.h */, 120 | 221E023618B2E9880005F6A0 /* objc_runtime.c */, 121 | 221E023D18B2E9880005F6A0 /* type_register.h */, 122 | 221E023B18B2E9880005F6A0 /* runtime_base.h */, 123 | 221E023A18B2E9880005F6A0 /* runtime_base.c */, 124 | 221E023C18B2E9880005F6A0 /* runtime_base.s */, 125 | ); 126 | path = loader; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXHeadersBuildPhase section */ 132 | 221E020318B2A9FE0005F6A0 /* Headers */ = { 133 | isa = PBXHeadersBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 221E024818B2EA840005F6A0 /* util.h in Headers */, 137 | 221E024518B2E9880005F6A0 /* runtime_base.h in Headers */, 138 | 221E022C18B2AF4F0005F6A0 /* loader.h in Headers */, 139 | 221E023F18B2E9880005F6A0 /* objc_lexer.h in Headers */, 140 | 221E024718B2E9880005F6A0 /* type_register.h in Headers */, 141 | 221E024118B2E9880005F6A0 /* objc_runtime.h in Headers */, 142 | 221E024218B2E9880005F6A0 /* objc1_runtime.h in Headers */, 143 | 221E024318B2E9880005F6A0 /* objc2_runtime.h in Headers */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXHeadersBuildPhase section */ 148 | 149 | /* Begin PBXNativeTarget section */ 150 | 221E01F418B2A9C90005F6A0 /* loader-test */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = 221E01FE18B2A9C90005F6A0 /* Build configuration list for PBXNativeTarget "loader-test" */; 153 | buildPhases = ( 154 | 221E01F118B2A9C90005F6A0 /* Sources */, 155 | 221E01F218B2A9C90005F6A0 /* Frameworks */, 156 | 221E01F318B2A9C90005F6A0 /* CopyFiles */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = "loader-test"; 163 | productName = loader; 164 | productReference = 221E01F518B2A9C90005F6A0 /* loader-test */; 165 | productType = "com.apple.product-type.tool"; 166 | }; 167 | 221E020418B2A9FE0005F6A0 /* loader */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = 221E020618B2A9FE0005F6A0 /* Build configuration list for PBXNativeTarget "loader" */; 170 | buildPhases = ( 171 | 221E020118B2A9FE0005F6A0 /* Sources */, 172 | 221E020218B2A9FE0005F6A0 /* Frameworks */, 173 | 221E020318B2A9FE0005F6A0 /* Headers */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = loader; 180 | productName = loader; 181 | productReference = 221E020518B2A9FE0005F6A0 /* libloader.dylib */; 182 | productType = "com.apple.product-type.library.dynamic"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | 221E01ED18B2A9C90005F6A0 /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | LastUpgradeCheck = 0510; 191 | ORGANIZATIONNAME = "Sam Marshall"; 192 | }; 193 | buildConfigurationList = 221E01F018B2A9C90005F6A0 /* Build configuration list for PBXProject "loader" */; 194 | compatibilityVersion = "Xcode 3.2"; 195 | developmentRegion = English; 196 | hasScannedForEncodings = 0; 197 | knownRegions = ( 198 | en, 199 | ); 200 | mainGroup = 221E01EC18B2A9C90005F6A0; 201 | productRefGroup = 221E01F618B2A9C90005F6A0 /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 221E01F418B2A9C90005F6A0 /* loader-test */, 206 | 221E020418B2A9FE0005F6A0 /* loader */, 207 | ); 208 | }; 209 | /* End PBXProject section */ 210 | 211 | /* Begin PBXSourcesBuildPhase section */ 212 | 221E01F118B2A9C90005F6A0 /* Sources */ = { 213 | isa = PBXSourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 221E01F918B2A9C90005F6A0 /* main.c in Sources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | 221E020118B2A9FE0005F6A0 /* Sources */ = { 221 | isa = PBXSourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | 221E023E18B2E9880005F6A0 /* objc_lexer.c in Sources */, 225 | 221E024418B2E9880005F6A0 /* runtime_base.c in Sources */, 226 | 221E024018B2E9880005F6A0 /* objc_runtime.c in Sources */, 227 | 221E023118B2B6D60005F6A0 /* loader.c in Sources */, 228 | 221E024618B2E9880005F6A0 /* runtime_base.s in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin XCBuildConfiguration section */ 235 | 221E01FC18B2A9C90005F6A0 /* Debug */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_OBJC_ARC = YES; 242 | CLANG_WARN_BOOL_CONVERSION = YES; 243 | CLANG_WARN_CONSTANT_CONVERSION = YES; 244 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 245 | CLANG_WARN_EMPTY_BODY = YES; 246 | CLANG_WARN_ENUM_CONVERSION = YES; 247 | CLANG_WARN_INT_CONVERSION = YES; 248 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 249 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 250 | COPY_PHASE_STRIP = NO; 251 | GCC_C_LANGUAGE_STANDARD = gnu99; 252 | GCC_DYNAMIC_NO_PIC = NO; 253 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 254 | GCC_OPTIMIZATION_LEVEL = 0; 255 | GCC_PREPROCESSOR_DEFINITIONS = ( 256 | "DEBUG=1", 257 | "$(inherited)", 258 | ); 259 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 260 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 261 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 262 | GCC_WARN_UNDECLARED_SELECTOR = YES; 263 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 264 | GCC_WARN_UNUSED_FUNCTION = YES; 265 | GCC_WARN_UNUSED_VARIABLE = YES; 266 | MACOSX_DEPLOYMENT_TARGET = 10.9; 267 | ONLY_ACTIVE_ARCH = YES; 268 | SDKROOT = macosx; 269 | }; 270 | name = Debug; 271 | }; 272 | 221E01FD18B2A9C90005F6A0 /* Release */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 277 | CLANG_CXX_LIBRARY = "libc++"; 278 | CLANG_ENABLE_OBJC_ARC = YES; 279 | CLANG_WARN_BOOL_CONVERSION = YES; 280 | CLANG_WARN_CONSTANT_CONVERSION = YES; 281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN_ENUM_CONVERSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | COPY_PHASE_STRIP = YES; 288 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 289 | ENABLE_NS_ASSERTIONS = NO; 290 | GCC_C_LANGUAGE_STANDARD = gnu99; 291 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | MACOSX_DEPLOYMENT_TARGET = 10.9; 299 | SDKROOT = macosx; 300 | }; 301 | name = Release; 302 | }; 303 | 221E01FF18B2A9C90005F6A0 /* Debug */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | LIBRARY_SEARCH_PATHS = ( 307 | "$(inherited)", 308 | "$(PROJECT_DIR)", 309 | ); 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | }; 312 | name = Debug; 313 | }; 314 | 221E020018B2A9C90005F6A0 /* Release */ = { 315 | isa = XCBuildConfiguration; 316 | buildSettings = { 317 | LIBRARY_SEARCH_PATHS = ( 318 | "$(inherited)", 319 | "$(PROJECT_DIR)", 320 | ); 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | }; 323 | name = Release; 324 | }; 325 | 221E020718B2A9FE0005F6A0 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | EXECUTABLE_PREFIX = lib; 329 | GCC_PREPROCESSOR_DEFINITIONS = ( 330 | "DEBUG=1", 331 | "$(inherited)", 332 | ); 333 | LIBRARY_SEARCH_PATHS = ( 334 | "$(inherited)", 335 | "$(PROJECT_DIR)", 336 | ); 337 | ONLY_ACTIVE_ARCH = NO; 338 | PRODUCT_NAME = "$(TARGET_NAME)"; 339 | }; 340 | name = Debug; 341 | }; 342 | 221E020818B2A9FE0005F6A0 /* Release */ = { 343 | isa = XCBuildConfiguration; 344 | buildSettings = { 345 | EXECUTABLE_PREFIX = lib; 346 | LIBRARY_SEARCH_PATHS = ( 347 | "$(inherited)", 348 | "$(PROJECT_DIR)", 349 | ); 350 | PRODUCT_NAME = "$(TARGET_NAME)"; 351 | }; 352 | name = Release; 353 | }; 354 | /* End XCBuildConfiguration section */ 355 | 356 | /* Begin XCConfigurationList section */ 357 | 221E01F018B2A9C90005F6A0 /* Build configuration list for PBXProject "loader" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | 221E01FC18B2A9C90005F6A0 /* Debug */, 361 | 221E01FD18B2A9C90005F6A0 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | 221E01FE18B2A9C90005F6A0 /* Build configuration list for PBXNativeTarget "loader-test" */ = { 367 | isa = XCConfigurationList; 368 | buildConfigurations = ( 369 | 221E01FF18B2A9C90005F6A0 /* Debug */, 370 | 221E020018B2A9C90005F6A0 /* Release */, 371 | ); 372 | defaultConfigurationIsVisible = 0; 373 | }; 374 | 221E020618B2A9FE0005F6A0 /* Build configuration list for PBXNativeTarget "loader" */ = { 375 | isa = XCConfigurationList; 376 | buildConfigurations = ( 377 | 221E020718B2A9FE0005F6A0 /* Debug */, 378 | 221E020818B2A9FE0005F6A0 /* Release */, 379 | ); 380 | defaultConfigurationIsVisible = 0; 381 | }; 382 | /* End XCConfigurationList section */ 383 | }; 384 | rootObject = 221E01ED18B2A9C90005F6A0 /* Project object */; 385 | } 386 | -------------------------------------------------------------------------------- /loader.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /loader/loader.c: -------------------------------------------------------------------------------- 1 | // 2 | // loader.c 3 | // loader 4 | // 5 | // Created by Sam Marshall on 2/17/14. 6 | // Copyright (c) 2014 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_loader_c 10 | #define loader_loader_c 11 | 12 | #pragma mark - 13 | #pragma mark #include 14 | #include "loader.h" 15 | #include 16 | #include 17 | #include 18 | 19 | #pragma mark - 20 | #pragma mark Private Types 21 | 22 | #define kStubName "__sdmst_stub_" 23 | 24 | #pragma mark - 25 | #pragma mark Private Functions 26 | 27 | bool SDMIsBinaryLoaded(char *path, struct loader_binary * binary) { 28 | bool isLoaded = false; 29 | uint32_t count = _dyld_image_count(); 30 | for (uint32_t index = 0; index < count; index++) { 31 | const char *image_name = _dyld_get_image_name(index); 32 | if (strncmp(image_name, path, strlen(image_name)) == 0) { 33 | isLoaded = true; 34 | binary->image_index = index; 35 | binary->header = PtrCast(_dyld_get_image_header(index), struct loader_generic_header *); 36 | break; 37 | } 38 | } 39 | return isLoaded; 40 | } 41 | 42 | struct loader_map * SDMCreateBinaryMap(struct loader_generic_header * header) { 43 | struct loader_map *map = calloc(1, sizeof(struct loader_map)); 44 | map->segment_map = calloc(1, sizeof(struct loader_segment_map)); 45 | 46 | map->symbol_table = calloc(1, sizeof(struct loader_symtab)); 47 | 48 | map->dependency_map = calloc(1, sizeof(struct loader_dependency_map)); 49 | map->dependency_map->dependency = calloc(1, sizeof(uintptr_t)); 50 | map->dependency_map->count = 0; 51 | 52 | bool is64Bit = SDMBinaryIs64Bit(header); 53 | struct loader_loadcmd *loadCmd = (struct loader_loadcmd *)PtrAdd(header, (is64Bit ? sizeof(struct loader_64_header) : sizeof(struct loader_32_header))); 54 | for (uint32_t command_index = 0; command_index < header->ncmds; command_index++) { 55 | switch (loadCmd->cmd) { 56 | case LC_SYMTAB: { 57 | map->symbol_table->symtab = PtrCast(loadCmd, uintptr_t*); 58 | break; 59 | }; 60 | case LC_SEGMENT: 61 | case LC_SEGMENT_64: { 62 | struct loader_segment *segment = PtrCast(loadCmd, struct loader_segment *); 63 | if ((map->segment_map->text == NULL) && !strncmp(SEG_TEXT,segment->segname,sizeof(segment->segname))) { 64 | map->segment_map->text = segment; 65 | } 66 | if ((map->segment_map->link == NULL) && !strncmp(SEG_LINKEDIT,segment->segname,sizeof(segment->segname))) { 67 | map->segment_map->link = segment; 68 | } 69 | if ((map->segment_map->objc == NULL) && !strncmp((is64Bit ? SEG_DATA : SEG_OBJC), segment->segname, sizeof(segment->segname))) { 70 | map->segment_map->objc = segment; 71 | } 72 | break; 73 | }; 74 | case LC_LOAD_DYLIB: { 75 | map->dependency_map->dependency = realloc(map->dependency_map->dependency, sizeof(uintptr_t)*(map->dependency_map->count+1)); 76 | map->dependency_map->dependency[map->dependency_map->count] = *PtrCast(loadCmd, uintptr_t*); 77 | map->dependency_map->count++; 78 | break; 79 | }; 80 | case LC_FUNCTION_STARTS: { 81 | map->function_start = PtrCast(loadCmd, struct loader_function_start *); 82 | break; 83 | }; 84 | default: { 85 | break; 86 | }; 87 | } 88 | loadCmd = (struct loader_loadcmd *)PtrAdd(loadCmd, loadCmd->cmdsize); 89 | } 90 | return map; 91 | } 92 | 93 | uint64_t SDMComputeFslide(struct loader_segment_map * segment_map, bool is64Bit) { 94 | uint64_t fslide = 0; 95 | if (is64Bit) { 96 | struct loader_segment_64 *text_segment = PtrCast(segment_map->text, struct loader_segment_64 *); 97 | struct loader_segment_64 *link_segment = PtrCast(segment_map->link, struct loader_segment_64 *); 98 | fslide = (uint64_t)(link_segment->data.position.addr - text_segment->data.position.addr) - link_segment->data.fileoff; 99 | } else { 100 | struct loader_segment_32 *text_segment = PtrCast(segment_map->text, struct loader_segment_32 *); 101 | struct loader_segment_32 *link_segment = PtrCast(segment_map->link, struct loader_segment_32 *); 102 | fslide = (uint64_t)(link_segment->data.position.addr - text_segment->data.position.addr) - link_segment->data.fileoff; 103 | } 104 | return fslide; 105 | } 106 | 107 | void SDMGenerateSymbols(struct loader_binary * binary) { 108 | uintptr_t symbol_address = 0; 109 | binary->map->symbol_table->symbol = calloc(1, sizeof(struct loader_symbol)); 110 | binary->map->symbol_table->count = 0; 111 | struct symtab_command * symtab_cmd = PtrCast(binary->map->symbol_table->symtab, struct symtab_command *); 112 | bool is64Bit = SDMBinaryIs64Bit(binary->header); 113 | uint64_t fslide = SDMComputeFslide(binary->map->segment_map, is64Bit); 114 | struct loader_generic_nlist *entry = (struct loader_generic_nlist *)PtrAdd(binary->header, (symtab_cmd->symoff + fslide)); 115 | for (uint32_t symbol_index = 0; symbol_index < symtab_cmd->nsyms; symbol_index++) { 116 | if (!(entry->n_type & N_STAB) && ((entry->n_type & N_TYPE) == N_SECT)) { 117 | char *strTable = PtrAdd(binary->header, (symtab_cmd->stroff + fslide)); 118 | if (is64Bit) { 119 | uint64_t *n_value = (uint64_t*)PtrAdd(entry, sizeof(struct loader_generic_nlist)); 120 | symbol_address = (uintptr_t)*n_value; 121 | } else { 122 | uint32_t *n_value = (uint32_t*)PtrAdd(entry, sizeof(struct loader_generic_nlist)); 123 | symbol_address = (uintptr_t)*n_value; 124 | } 125 | binary->map->symbol_table->symbol = realloc(binary->map->symbol_table->symbol, sizeof(struct loader_symbol)*(binary->map->symbol_table->count+0x1)); 126 | struct loader_symbol *symbol = (struct loader_symbol *)calloc(1, sizeof(struct loader_symbol)); 127 | if (symbol) { 128 | symbol->symbol_number = symbol_index; 129 | symbol->offset = (uintptr_t)PtrAdd(symbol_address, _dyld_get_image_vmaddr_slide(binary->image_index)); 130 | if (entry->n_un.n_strx && (entry->n_un.n_strx < symtab_cmd->strsize)) { 131 | symbol->symbol_name = PtrAdd(strTable, entry->n_un.n_strx); 132 | symbol->stub = false; 133 | } else { 134 | symbol->symbol_name = calloc(1 + strlen(kStubName) + ((binary->map->symbol_table->count==0) ? 1 : (uint32_t)log10(binary->map->symbol_table->count) + 0x1), sizeof(char)); 135 | sprintf(symbol->symbol_name, "%s%llu", kStubName, binary->map->symbol_table->count); 136 | symbol->stub = true; 137 | } 138 | memcpy(&(binary->map->symbol_table->symbol[binary->map->symbol_table->count]), symbol, sizeof(struct loader_symbol)); 139 | free(symbol); 140 | binary->map->symbol_table->count++; 141 | } 142 | } 143 | entry = (struct loader_generic_nlist *)PtrAdd(entry, (sizeof(struct loader_generic_nlist) + (is64Bit ? sizeof(uint64_t) : sizeof(uint32_t)))); 144 | } 145 | } 146 | 147 | bool SDMMapObjcClasses32(struct loader_binary * binary) { 148 | bool result = (binary->map->segment_map->objc ? true : false); 149 | if (result) { 150 | struct SDMSTObjc *objc_data = calloc(1, sizeof(struct SDMSTObjc)); 151 | struct loader_segment_32 *objc_segment = ((struct loader_segment_32 *)(binary->map->segment_map->objc)); 152 | uint32_t module_count = 0; 153 | struct loader_section_32 *section = (struct loader_section_32 *)PtrAdd(objc_segment, sizeof(struct loader_segment_32)); 154 | uint32_t section_count = objc_segment->info.nsects; 155 | struct SDMSTObjcModuleRaw *module = NULL; 156 | for (uint32_t index = 0; index < section_count; index++) { 157 | uint64_t mem_offset = _dyld_get_image_vmaddr_slide(binary->image_index); 158 | char *sectionName = Ptr(section->name.sectname); 159 | if (strncmp(sectionName, kObjc1ModuleInfo, sizeof(char[16])) == 0) { 160 | module = (struct SDMSTObjcModuleRaw *)PtrAdd(binary->header, section->info.offset); 161 | module_count = (section->position.size)/sizeof(struct SDMSTObjcModuleRaw); 162 | } 163 | if (strncmp(sectionName, kObjc1Class, sizeof(char[16])) == 0) { 164 | objc_data->classRange = CoreRangeCreate((uint32_t)((uint64_t)(section->position.addr)+(uint64_t)mem_offset), section->position.size); 165 | } 166 | if (strncmp(sectionName, kObjc1Category, sizeof(char[16])) == 0) { 167 | objc_data->catRange = CoreRangeCreate((uint32_t)((uint64_t)(section->position.addr)+(uint64_t)mem_offset), section->position.size); 168 | } 169 | if (strncmp(sectionName, kObjc1Protocol, sizeof(char[16])) == 0) { 170 | objc_data->protRange = CoreRangeCreate((uint32_t)((uint64_t)(section->position.addr)+(uint64_t)mem_offset), section->position.size); 171 | } 172 | if (strncmp(sectionName, kObjc1ClsMeth, sizeof(char[16])) == 0) { 173 | objc_data->clsMRange = CoreRangeCreate((uint32_t)((uint64_t)(section->position.addr)+(uint64_t)mem_offset), section->position.size); 174 | } 175 | if (strncmp(sectionName, kObjc1InstMeth, sizeof(char[16])) == 0) { 176 | objc_data->instMRange = CoreRangeCreate((uint32_t)((uint64_t)(section->position.addr)+(uint64_t)mem_offset), section->position.size); 177 | } 178 | section = (struct loader_section_32 *)PtrAdd(section, sizeof(struct loader_section_32)); 179 | } 180 | if (module_count) { 181 | objc_data->cls = calloc(1, sizeof(struct SDMSTObjcClass)); 182 | objc_data->clsCount = 0; 183 | uint64_t mem_offset = 0; 184 | for (uint32_t index = 0; index < module_count; index++) { 185 | struct SDMSTObjc1Symtab *symtab = (struct SDMSTObjc1Symtab *)PtrAdd(mem_offset, module[index].symtab); 186 | SDMSTObjc1CreateClassFromSymbol(objc_data, symtab); 187 | } 188 | } 189 | binary->objc = objc_data; 190 | } 191 | return result; 192 | } 193 | 194 | bool SDMMapObjcClasses64(struct loader_binary * binary) { 195 | bool result = (binary->map->segment_map->objc ? true : false); 196 | if (result) { 197 | struct SDMSTObjc *objc_data = calloc(1, sizeof(struct SDMSTObjc)); 198 | struct loader_segment_64 *objc_segment = ((struct loader_segment_64 *)(binary->map->segment_map->objc)); 199 | uint64_t mem_offset = _dyld_get_image_vmaddr_slide(binary->image_index) & k32BitMask; 200 | CoreRange data_range = CoreRangeCreate((uintptr_t)((uint64_t)(objc_segment->data.position.addr)+((uint64_t)mem_offset)),objc_segment->data.position.size); 201 | struct loader_section_64 *section = (struct loader_section_64 *)PtrAdd(objc_segment, sizeof(struct loader_section_64)); 202 | uint32_t section_count = objc_segment->info.nsects; 203 | for (uint32_t index = 0; index < section_count; index++) { 204 | char *section_name = Ptr(section->name.sectname); 205 | if (strncmp(section_name, kObjc2ClassList, sizeof(char[16])) == 0) { 206 | objc_data->clsCount = (uint32_t)((section->position.size)/sizeof(uint64_t)); 207 | break; 208 | } 209 | section = (struct loader_section_64 *)PtrAdd(section, sizeof(struct loader_section_64)); 210 | } 211 | if (objc_data->clsCount) { 212 | objc_data->cls = calloc(objc_data->clsCount, sizeof(struct SDMSTObjcClass)); 213 | for (uint32_t index = 0; index < objc_data->clsCount; index++) { 214 | uint64_t *classes = (uint64_t*)PtrAdd(section->position.addr, mem_offset); 215 | struct SDMSTObjc2Class *cls = (struct SDMSTObjc2Class *)PtrAdd(mem_offset, classes[index]); 216 | struct SDMSTObjcClass *objclass = SDMSTObjc2ClassCreateFromClass(cls, 0, data_range, mem_offset); 217 | memcpy(&(objc_data->cls[index]), objclass, sizeof(struct SDMSTObjcClass)); 218 | free(objclass); 219 | } 220 | } 221 | binary->objc = calloc(1, sizeof(struct SDMSTObjc)); 222 | memcpy(binary->objc, objc_segment, sizeof(SDMSTObjc)); 223 | free(objc_segment); 224 | } 225 | return result; 226 | } 227 | 228 | 229 | #pragma mark - 230 | #pragma mark Functions 231 | 232 | bool SDMBinaryIs64Bit(struct loader_generic_header *header) { 233 | bool isCPU64Bit = ((header->arch->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64); 234 | bool isMagic64Bit = (header->magic->magic == MH_MAGIC_64 || header->magic->magic == MH_CIGAM_64); 235 | return (isCPU64Bit && isMagic64Bit); 236 | } 237 | 238 | struct loader_binary * SDMLoadBinaryWithPath(char *path) { 239 | struct loader_binary *binary = calloc(1, sizeof(struct loader_binary)); 240 | bool inMemory = SDMIsBinaryLoaded(path, binary); 241 | if (inMemory) { 242 | binary->map = SDMCreateBinaryMap(binary->header); 243 | SDMGenerateSymbols(binary); 244 | bool loadedObjc = false; 245 | bool is64Bit = SDMBinaryIs64Bit(binary->header); 246 | if (is64Bit) { 247 | loadedObjc = SDMMapObjcClasses64(binary); 248 | } else { 249 | loadedObjc = SDMMapObjcClasses32(binary); 250 | } 251 | } else { 252 | SDMReleaseBinary(binary); 253 | binary = NULL; 254 | } 255 | return binary; 256 | } 257 | 258 | void SDMReleaseBinary(struct loader_binary *binary) { 259 | free(binary); 260 | } 261 | 262 | #endif -------------------------------------------------------------------------------- /loader/loader.h: -------------------------------------------------------------------------------- 1 | // 2 | // loader.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 2/17/14. 6 | // Copyright (c) 2014 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_loader_h 10 | #define loader_loader_h 11 | 12 | #pragma mark - 13 | #pragma mark #include 14 | #include 15 | #include 16 | #include "util.h" 17 | #include "objc_runtime.h" 18 | 19 | #pragma mark - 20 | #pragma mark Private Types 21 | 22 | struct loader_magic { 23 | uint32_t magic; 24 | } ATR_PACK; 25 | 26 | struct loader_arch { 27 | cpu_type_t cputype; 28 | cpu_subtype_t subtype; 29 | } ATR_PACK; 30 | 31 | struct loader_fat_header { 32 | struct loader_magic magic; 33 | uint32_t n_arch; 34 | } ATR_PACK; 35 | 36 | struct loader_generic_header { 37 | struct loader_magic magic; 38 | struct loader_arch arch; 39 | uint32_t filetype; 40 | uint32_t ncmds; 41 | uint32_t sizeofcmds; 42 | uint32_t flags; 43 | } ATR_PACK; 44 | 45 | struct loader_32_header { 46 | struct loader_generic_header info; 47 | } ATR_PACK; 48 | 49 | struct loader_64_header { 50 | struct loader_generic_header info; 51 | uint32_t reserved; 52 | } ATR_PACK; 53 | 54 | struct loader_loadcmd { 55 | uint32_t cmd; 56 | uint32_t cmdsize; 57 | } ATR_PACK; 58 | 59 | struct loader_64_position { 60 | uint64_t addr; 61 | uint64_t size; 62 | } ATR_PACK; 63 | 64 | struct loader_32_position { 65 | uint32_t addr; 66 | uint32_t size; 67 | } ATR_PACK; 68 | 69 | struct loader_segment { 70 | struct loader_loadcmd command; 71 | char segname[16]; 72 | } ATR_PACK; 73 | 74 | struct loader_segment_data_64 { 75 | struct loader_64_position position; 76 | uint64_t fileoff; 77 | } ATR_PACK; 78 | 79 | struct loader_segment_data_32 { 80 | struct loader_32_position position; 81 | uint32_t fileoff; 82 | } ATR_PACK; 83 | 84 | struct loader_segment_info { 85 | vm_prot_t maxprot; 86 | vm_prot_t initprot; 87 | uint32_t nsects; 88 | uint32_t flags; 89 | } ATR_PACK; 90 | 91 | struct loader_segment_64 { 92 | struct loader_segment segment; 93 | struct loader_segment_data_64 data; 94 | struct loader_segment_info info; 95 | } ATR_PACK; 96 | 97 | struct loader_segment_32 { 98 | struct loader_segment segment; 99 | struct loader_segment_data_32 data; 100 | struct loader_segment_info info; 101 | } ATR_PACK; 102 | 103 | struct loader_section_name { 104 | char sectname[16]; 105 | char segname[16]; 106 | } ATR_PACK; 107 | 108 | struct loader_section_info { 109 | uint32_t offset; 110 | uint32_t align; 111 | uint32_t reloff; 112 | uint32_t nreloc; 113 | uint32_t flags; 114 | uint32_t reserved1; 115 | uint32_t reserved2; 116 | } ATR_PACK; 117 | 118 | struct loader_section_64 { 119 | struct loader_section_name name; 120 | struct loader_64_position position; 121 | struct loader_section_info info; 122 | } ATR_PACK; 123 | 124 | struct loader_section_32 { 125 | struct loader_section_name name; 126 | struct loader_32_position position; 127 | struct loader_section_info info; 128 | } ATR_PACK; 129 | 130 | struct loader_generic_nlist { 131 | union { 132 | uint32_t n_strx; 133 | } n_un; 134 | uint8_t n_type; 135 | uint8_t n_sect; 136 | uint16_t n_desc; 137 | } ATR_PACK; 138 | 139 | #pragma mark - 140 | #pragma mark Public Types 141 | 142 | struct loader_segment_map { 143 | struct loader_segment *text; 144 | struct loader_segment *link; 145 | struct loader_segment *objc; 146 | } ATR_PACK; 147 | 148 | struct loader_symbol { 149 | uint32_t symbol_number; 150 | uintptr_t offset; 151 | char *symbol_name; 152 | bool stub; 153 | } ATR_PACK; 154 | 155 | struct loader_symtab { 156 | uintptr_t *symtab; 157 | struct loader_symbol *symbol; 158 | uint64_t count; 159 | } ATR_PACK; 160 | 161 | struct loader_dependency_map { 162 | uintptr_t *dependency; 163 | uint32_t count; 164 | } ATR_PACK; 165 | 166 | struct loader_function_start { 167 | struct loader_loadcmd loadcmd; 168 | struct loader_32_position position; 169 | } ATR_PACK; 170 | 171 | struct loader_map { 172 | struct loader_segment_map *segment_map; 173 | struct loader_symtab *symbol_table; 174 | struct loader_dependency_map *dependency_map; 175 | struct loader_function_start *function_start; 176 | } ATR_PACK; 177 | 178 | struct loader_binary { 179 | uint32_t image_index; 180 | struct loader_generic_header *header; 181 | struct loader_map *map; 182 | struct SDMSTObjc *objc; 183 | } ATR_PACK; 184 | 185 | #pragma mark - 186 | #pragma mark Functions 187 | 188 | bool SDMBinaryIs64Bit(struct loader_generic_header *header); 189 | 190 | struct loader_binary * SDMLoadBinaryWithPath(char *path); 191 | void SDMReleaseBinary(struct loader_binary *binary); 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /loader/objc1_runtime.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc1_runtime.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 11/2/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_objc1_runtime_h 10 | #define loader_objc1_runtime_h 11 | 12 | #define kObjc1CatClsMeth "__cat_cls_meth" 13 | #define kObjc1CatInstMeth "__cat_inst_meth" 14 | #define kObjc1StringObject "__string_object" 15 | #define kObjc1CStringObject "__cstring_object" 16 | #define kObjc1MessageRefs "__message_refs" 17 | #define kObjc1SelFixup "__sel_fixup" 18 | #define kObjc1ClsRefs "__cls_refs" 19 | #define kObjc1Class "__class" 20 | #define kObjc1MetaClass "__meta_class" 21 | #define kObjc1ClsMeth "__cls_meth" 22 | #define kObjc1InstMeth "__inst_meth" 23 | #define kObjc1Protocol "__protocol" 24 | #define kObjc1Category "__category" 25 | #define kObjc1ClassVars "__class_vars" 26 | #define kObjc1InstanceVars "__instance_vars" 27 | #define kObjc1ModuleInfo "__module_info" 28 | #define kObjc1Symbols "__symbols" 29 | 30 | struct SDMSTObjc1ClassMethodDescInfo { 31 | uint32_t count; 32 | } ATR_PACK SDMSTObjc1ClassMethodDescInfo; 33 | 34 | struct SDMSTObjc1ClassMethodInfo { 35 | uint32_t entrySize; 36 | uint32_t count; 37 | } ATR_PACK SDMSTObjc1ClassMethodInfo; 38 | 39 | struct SDMSTObjc1ClassIVarInfo { 40 | uint32_t count; 41 | } ATR_PACK SDMSTObjc1ClassIVarInfo; 42 | 43 | struct SDMSTObjc1ClassIVar { 44 | uint32_t name; 45 | uint32_t type; 46 | uint32_t offset; 47 | } ATR_PACK SDMSTObjc1ClassIVar; 48 | 49 | struct SDMSTObjc1ClassMethod { 50 | uint32_t name; 51 | uint32_t type; 52 | uint32_t imp; 53 | } ATR_PACK SDMSTObjc1ClassMethod; 54 | 55 | struct SDMSTObjc1Protocol { 56 | uint32_t isa; 57 | uint32_t name; 58 | uint32_t protocolList; 59 | uint32_t instanceMethodDesc; 60 | uint32_t classMethodDesc; 61 | } ATR_PACK SDMSTObjc1Protocol; 62 | 63 | struct SDMSTObjc1Category { 64 | uint32_t name; 65 | uint32_t className; 66 | uint32_t instanceMethods; 67 | uint32_t classMethods; 68 | uint32_t protocols; 69 | } ATR_PACK SDMSTObjc1Category; 70 | 71 | struct SDMSTObjc1Class { 72 | uint32_t isa; 73 | uint32_t superClass; 74 | uint32_t name; 75 | uint32_t version; 76 | uint32_t info; 77 | uint32_t instanceSize; 78 | uint32_t ivars; 79 | uint32_t methods; 80 | uint32_t cache; 81 | uint32_t protocols; 82 | } ATR_PACK SDMSTObjc1Class; 83 | 84 | struct SDMSTObjc1SymtabDefinition { 85 | uint32_t defintion; 86 | } ATR_PACK SDMSTObjc1SymtabDefinition; 87 | 88 | struct SDMSTObjc1Symtab { 89 | uint32_t selectorRefCount; 90 | uint32_t refs; 91 | uint16_t classCount; 92 | uint16_t catCount; 93 | } ATR_PACK SDMSTObjc1Symtab; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /loader/objc2_runtime.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc2_runtime.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 11/2/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_objc2_runtime_h 10 | #define loader_objc2_runtime_h 11 | 12 | #define kObjc2SelRef "__objc_selrefs" 13 | #define kObjc2MsgRefs "__objc_msgrefs" 14 | #define kObjc2ClassRefs "__objc_classrefs" 15 | #define kObjc2SuperRefs "__objc_superrefs" 16 | #define kObjc2ClassList "__objc_classlist" 17 | #define kObjc2NlClsList "__objc_nlclslist" 18 | #define kObjc2CatList "__objc_catlist" 19 | #define kObjc2NlCatList "__objc_nlcatlist" 20 | #define kObjc2ProtoList "__objc_protolist" 21 | #define kObjc2ProtoRefs "__objc_protorefs" 22 | 23 | struct SDMSTObjc2ClassMethodInfo { 24 | uint32_t entrySize; 25 | uint32_t count; 26 | } ATR_PACK SDMSTObjc2ClassMethodInfo; 27 | 28 | struct SDMSTObjc2ClassProtcolInfo { 29 | uint64_t count; 30 | } ATR_PACK SDMSTObjc2ClassProtcolInfo; 31 | 32 | struct SDMSTObjc2ClassIVarInfo { 33 | uint32_t entrySize; 34 | uint32_t count; 35 | } ATR_PACK SDMSTObjc2ClassIVarInfo; 36 | 37 | struct SDMSTObjc2ClassPropertyInfo { 38 | uint32_t entrySize; 39 | uint32_t count; 40 | } ATR_PACK SDMSTObjc2ClassPropertyInfo; 41 | 42 | struct SDMSTObjc2ClassMethod { 43 | uint64_t name; 44 | uint64_t type; 45 | uint64_t imp; 46 | } ATR_PACK SDMSTObjc2ClassMethod; 47 | 48 | struct SDMSTObjc2ClassProtocol { 49 | uint64_t offset; 50 | } ATR_PACK SDMSTObjc2ClassProtocol; 51 | 52 | struct SDMSTObjc2ClassIVar { 53 | uint64_t offset; 54 | uint64_t name; 55 | uint64_t type; 56 | uint32_t align; 57 | uint32_t size; 58 | } ATR_PACK SDMSTObjc2ClassIVar; 59 | 60 | struct SDMSTObjc2ClassProperty { 61 | char *name; 62 | char *attributes; 63 | } ATR_PACK SDMSTObjc2ClassProperty; 64 | 65 | struct SDMSTObjc2ClassData { 66 | uint32_t flags; 67 | uint32_t instanceStart; 68 | uint32_t instanceSize; 69 | uint32_t reserved; 70 | uint64_t iVarLayout; 71 | uint64_t name; //char* 72 | uint64_t method; //struct SDMSTObjc2ClassMethodInfo* 73 | uint64_t protocol; //struct SDMSTObjc2ClassProtcolInfo* 74 | uint64_t ivar; //struct SDMSTObjc2ClassIVarInfo* 75 | uint64_t weakIVarLayout; 76 | uint64_t property; //struct SDMSTObjc2ClassProperty* 77 | } ATR_PACK SDMSTObjc2ClassData; 78 | 79 | struct SDMSTObjc2Class { 80 | struct SDMSTObjc2Class *isa; 81 | uint64_t superCls; 82 | uint64_t cache; 83 | uint64_t vTable; 84 | struct SDMSTObjc2ClassData *data; 85 | } ATR_PACK SDMSTObjc2Class; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /loader/objc_lexer.c: -------------------------------------------------------------------------------- 1 | // 2 | // objc_lexer.c 3 | // loader 4 | // 5 | // Created by Sam Marshall on 11/3/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_objc_lexer_c 10 | #define loader_objc_lexer_c 11 | 12 | #include "objc_lexer.h" 13 | #include 14 | 15 | #define kObjcTypeEncodingCount 21 16 | 17 | static char* ObjcTypeEncoding[kObjcTypeEncodingCount] = { 18 | kObjcCharEncoding, 19 | kObjcIntEncoding, 20 | kObjcShortEncoding, 21 | kObjcLongEncoding, 22 | kObjcLLongEncoding, 23 | kObjcUCharEncoding, 24 | kObjcUIntEncoding, 25 | kObjcUShortEncoding, 26 | kObjcULongEncoding, 27 | kObjcULLongEncoding, 28 | kObjcFloatEncoding, 29 | kObjcDoubleEncoding, 30 | kObjcBoolEncoding, 31 | kObjcVoidEncoding, 32 | kObjcStringEncoding, 33 | kObjcIdEncoding, 34 | kObjcClassEncoding, 35 | kObjcSelEncoding, 36 | kObjcBitEncoding, 37 | kObjcPointerEncoding, 38 | kObjcUnknownEncoding 39 | }; 40 | 41 | static char* ObjcTypeEncodingNames[kObjcTypeEncodingCount] = { 42 | "char", 43 | "int", 44 | "short", 45 | "long", 46 | "long long", 47 | "unsigned char", 48 | "unsigned int", 49 | "unsigned short", 50 | "unsigned long", 51 | "unsigned long long", 52 | "float", 53 | "double", 54 | "bool", 55 | "void", 56 | "char*", 57 | "id", 58 | "Class", 59 | "SEL", 60 | "bitmask", 61 | "*", 62 | "UnknownType" 63 | }; 64 | 65 | #define kObjcContainerTypeEncodingCount 1 66 | 67 | static char *ObjcContainerTypeEncodingNames[kObjcContainerTypeEncodingCount] = { 68 | "struct" 69 | }; 70 | 71 | #define kObjcStackSizeCount 10 72 | 73 | static char *ObjcStackSize[kObjcStackSizeCount] = { 74 | "0", 75 | "1", 76 | "2", 77 | "3", 78 | "4", 79 | "5", 80 | "6", 81 | "7", 82 | "8", 83 | "9" 84 | }; 85 | 86 | CoreRange SDMSTObjcStackSize(char *type, uint64_t offset, uint64_t *stackSize); 87 | CoreRange SDMSTObjcGetRangeFromTokens(char *startToken, char *endToken, char *type, uint64_t offset); 88 | CoreRange SDMSTObjcGetStructContentsRange(char *type, uint64_t offset); 89 | CoreRange SDMSTObjcGetArrayContentsRange(char *type, uint64_t offset); 90 | CoreRange SDMSTObjcGetStructNameRange(char *contents, uint64_t offset); 91 | struct loader_objc_lexer_type* SDMSTMemberCountOfStructContents(char *structContents, CoreRange nameRange); 92 | uint32_t SDMSTParseToken(struct loader_objc_lexer_type *decode, char *type, uint64_t offset); 93 | 94 | CoreRange SDMSTObjcStackSize(char *type, uint64_t offset, uint64_t *stackSize) { 95 | uint64_t counter = 0; 96 | bool findStackSize = true; 97 | while (findStackSize) { 98 | findStackSize = false; 99 | for (uint32_t i = 0; i < kObjcStackSizeCount; i++) { 100 | if (strncmp(&(type[offset+counter]), ObjcStackSize[i], sizeof(char)) == 0) { 101 | counter++; 102 | findStackSize = true; 103 | break; 104 | } 105 | } 106 | } 107 | CoreRange stackRange = CoreRangeCreate((uintptr_t)offset, counter); 108 | char *stack = calloc((uint32_t)stackRange.length+1, sizeof(char)); 109 | memcpy(stack, &(type[offset]), (uint32_t)stackRange.length); 110 | *stackSize = (uint64_t)atoi(stack); 111 | free(stack); 112 | return stackRange; 113 | } 114 | 115 | char* SDMSTObjcPointersForToken(struct loader_objc_lexer_token *token) { 116 | char *pointers = calloc(1, sizeof(char)*(token->pointerCount+1)); 117 | if (token->pointerCount) { 118 | for (uint32_t i = 0; i < token->pointerCount; i++) { 119 | strcat(pointers, "*"); 120 | } 121 | } 122 | return pointers; 123 | } 124 | 125 | CoreRange SDMSTObjcGetTokenRangeFromOffset(char *type, uint64_t offset, char *token) { 126 | uint64_t counter = 0; 127 | while ((strncmp(&(type[offset+counter]), token, strlen(token)) != 0) && offset+counter < strlen(type)) { 128 | counter++; 129 | } 130 | return CoreRangeCreate((uintptr_t)offset, counter); 131 | } 132 | 133 | char* SDMSTObjcCreateMethodDescription(struct loader_objc_lexer_type *type, char *name) { 134 | uint32_t nameLength = 1; 135 | if (name) { 136 | nameLength += strlen(name); 137 | } 138 | else { 139 | name = ""; 140 | } 141 | char *description = calloc(4096, sizeof(char)); 142 | uint32_t counter = 0; 143 | uint32_t argCount = 0; 144 | for (uint32_t i = counter+3; i < type->tokenCount; i++) { 145 | argCount++; 146 | } 147 | if (counter != argCount) { 148 | if (type->token[0].typeName) { 149 | sprintf(description,"(%s %s)",type->token[0].type,type->token[0].typeName); 150 | } 151 | else { 152 | char *objc_type = type->token[0].type; 153 | if (strcmp(objc_type, ObjcTypeEncodingNames[SDMObjcLexerConvertTokenToIndex(ObjcCharEncoding)]) == 0) { 154 | if (strncmp("is", name, sizeof(char[2])) == 0 || strncmp("has", name, sizeof(char[3])) == 0) { 155 | objc_type = "BOOL"; 156 | } 157 | } 158 | sprintf(description,"(%s)",objc_type); 159 | } 160 | uint32_t offset = 0; 161 | while (counter < argCount) { 162 | if (offset) { 163 | description = realloc(description, sizeof(char)*(strlen(description)+2)); 164 | sprintf(description,"%s ",description); 165 | } 166 | CoreRange methodArgRange = SDMSTObjcGetTokenRangeFromOffset(name, offset, kObjcSelEncoding); 167 | char *argName = calloc(1, sizeof(char)*((uint32_t)methodArgRange.length+1)); 168 | memcpy(argName, &(name[offset]), (uint32_t)methodArgRange.length); 169 | char *argType = (type->token[counter+3].typeName != NULL && (strncmp(type->token[counter+3].typeName, "?", sizeof(char)) != 0) ? type->token[counter+3].typeName : type->token[counter+3].type); 170 | char *pointers = SDMSTObjcPointersForToken(&(type->token[counter+3])); 171 | uint32_t formatLength = (uint32_t)(8+strlen(argName)+strlen(argType)+GetDigitsOfNumber(counter)+strlen(pointers)); 172 | char *formatName = calloc(1, sizeof(char)*formatLength); 173 | sprintf(formatName,"%s:(%s%s)_arg%01i",argName,argType,pointers,counter); 174 | description = realloc(description, sizeof(char)*(strlen(description)+formatLength)); 175 | memcpy(&(description[strlen(description)]), formatName, formatLength); 176 | free(formatName); 177 | free(argName); 178 | free(pointers); 179 | offset = offset + (uint32_t)methodArgRange.length + 1; 180 | counter++; 181 | } 182 | } 183 | else { 184 | if (type->token[0].typeName) { 185 | sprintf(description,"(%s %s)%s",type->token[0].type,type->token[0].typeName,name); 186 | } 187 | else { 188 | char *objc_type = type->token[0].type; 189 | if (strcmp(objc_type, ObjcTypeEncodingNames[SDMObjcLexerConvertTokenToIndex(ObjcCharEncoding)]) == 0) { 190 | if (strncmp("is", name, sizeof(char[2])) == 0 || strncmp("has", name, sizeof(char[3])) == 0) { 191 | objc_type = "BOOL"; 192 | } 193 | } 194 | sprintf(description,"(%s)%s",objc_type,name); 195 | } 196 | } 197 | description = realloc(description, sizeof(char)*(strlen(description)+2)); 198 | sprintf(description,"%s;",description); 199 | return description; 200 | } 201 | 202 | CoreRange SDMSTObjcGetRangeFromTokens(char *startToken, char *endToken, char *type, uint64_t offset) { 203 | uint64_t stack = 1; 204 | uint64_t counter = 0; 205 | while (stack != 0) { 206 | if (strncmp(&(type[offset+counter]), startToken, sizeof(char)) == 0) { 207 | stack++; 208 | } 209 | if (strncmp(&(type[offset+counter]), endToken, sizeof(char)) == 0) { 210 | stack--; 211 | } 212 | counter++; 213 | } 214 | counter--; 215 | return CoreRangeCreate((uintptr_t)offset, counter); 216 | 217 | } 218 | 219 | CoreRange SDMSTObjcGetStructContentsRange(char *type, uint64_t offset) { 220 | return SDMSTObjcGetRangeFromTokens(kObjcStructTokenStart, kObjcStructTokenEnd, type, offset); 221 | } 222 | 223 | CoreRange SDMSTObjcGetArrayContentsRange(char *type, uint64_t offset) { 224 | return SDMSTObjcGetRangeFromTokens(kObjcArrayTokenStart, kObjcArrayTokenEnd, type, offset); 225 | } 226 | 227 | CoreRange SDMSTObjcGetStructNameRange(char *contents, uint64_t offset) { 228 | return SDMSTObjcGetTokenRangeFromOffset(contents, offset, kObjcStructDefinitionToken); 229 | } 230 | 231 | struct loader_objc_lexer_type* SDMSTMemberCountOfStructContents(char *structContents, CoreRange nameRange) { 232 | return SDMSTObjcDecodeTypeWithLength(structContents, nameRange.length); 233 | } 234 | 235 | uint32_t SDMSTParseToken(struct loader_objc_lexer_type *decode, char *type, uint64_t offset) { 236 | uint32_t parsedLength = 1; 237 | uint32_t index = k32BitMask; 238 | for (uint32_t i = 0; i < kObjcTypeEncodingCount; i++) { 239 | if (strncmp(&(type[offset]), ObjcTypeEncoding[i], sizeof(char)) == 0) { 240 | index = i; 241 | break; 242 | } 243 | } 244 | if (index != k32BitMask && index < kObjcTypeEncodingCount) { 245 | decode->token[decode->tokenCount].typeClass = SDMObjcLexerConvertIndexToToken(index); 246 | decode->token[decode->tokenCount].type = ObjcTypeEncodingNames[index]; 247 | //if (decode->token[decode->tokenCount].typeName == 0) { 248 | decode->token[decode->tokenCount].typeName = 0; 249 | //} 250 | switch (decode->token[decode->tokenCount].typeClass) { 251 | case ObjcCharEncoding: { 252 | decode->tokenCount++; 253 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 254 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 255 | break; 256 | }; 257 | case ObjcIntEncoding: { 258 | decode->tokenCount++; 259 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 260 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 261 | break; 262 | }; 263 | case ObjcShortEncoding: { 264 | decode->tokenCount++; 265 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 266 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 267 | break; 268 | }; 269 | case ObjcLongEncoding: { 270 | decode->tokenCount++; 271 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 272 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 273 | break; 274 | }; 275 | case ObjcLLongEncoding: { 276 | decode->tokenCount++; 277 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 278 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 279 | break; 280 | }; 281 | case ObjcUCharEncoding: { 282 | decode->tokenCount++; 283 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 284 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 285 | break; 286 | }; 287 | case ObjcUIntEncoding: { 288 | decode->tokenCount++; 289 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 290 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 291 | break; 292 | }; 293 | case ObjcUShortEncoding: { 294 | decode->tokenCount++; 295 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 296 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 297 | break; 298 | }; 299 | case ObjcULongEncoding: { 300 | decode->tokenCount++; 301 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 302 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 303 | break; 304 | }; 305 | case ObjcULLongEncoding: { 306 | decode->tokenCount++; 307 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 308 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 309 | break; 310 | }; 311 | case ObjcFloatEncoding: { 312 | decode->tokenCount++; 313 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 314 | break; 315 | }; 316 | case ObjcDoubleEncoding: { 317 | decode->tokenCount++; 318 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 319 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 320 | break; 321 | }; 322 | case ObjcBoolEncoding: { 323 | decode->tokenCount++; 324 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 325 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 326 | break; 327 | }; 328 | case ObjcVoidEncoding: { 329 | decode->tokenCount++; 330 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 331 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 332 | break; 333 | }; 334 | case ObjcStringEncoding: { 335 | decode->tokenCount++; 336 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 337 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 338 | break; 339 | }; 340 | case ObjcIdEncoding: { 341 | uint64_t next = offset+1; 342 | if (strncmp(&(type[next]), kObjcNameTokenStart, sizeof(char)) == 0) { 343 | CoreRange nameRange = SDMSTObjcGetTokenRangeFromOffset(type, next+1, kObjcNameTokenEnd); 344 | char *name = calloc(1, sizeof(char)*(3+(uint32_t)nameRange.length)); 345 | char *objectProtocolTest = &(type[nameRange.offset]); 346 | if (strncmp(objectProtocolTest, "<", 1) == 0 && strncmp(objectProtocolTest+(uint32_t)(nameRange.length-1), ">", 1) == 0) { 347 | sprintf(&(name[0]),"id"); 348 | memcpy(&(name[2]), &(type[nameRange.offset]), sizeof(char)*nameRange.length); 349 | } 350 | else { 351 | memcpy(name, &(type[nameRange.offset]), sizeof(char)*nameRange.length); 352 | sprintf(name,"%s*",name); 353 | } 354 | decode->token[decode->tokenCount].typeName = name; 355 | parsedLength += nameRange.length + 2; 356 | } 357 | decode->tokenCount++; 358 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 359 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 360 | break; 361 | }; 362 | case ObjcClassEncoding: { 363 | decode->tokenCount++; 364 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 365 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 366 | break; 367 | }; 368 | case ObjcSelEncoding: { 369 | decode->tokenCount++; 370 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 371 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 372 | break; 373 | }; 374 | case ObjcBitEncoding: { 375 | decode->tokenCount++; 376 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 377 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 378 | break; 379 | }; 380 | case ObjcPointerEncoding: { 381 | decode->token[decode->tokenCount].pointerCount++; 382 | break; 383 | }; 384 | case ObjcUnknownEncoding: { 385 | decode->token[decode->tokenCount].typeName = 0; 386 | decode->tokenCount++; 387 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 388 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 389 | break; 390 | }; 391 | default: { 392 | break; 393 | }; 394 | } 395 | } 396 | else { 397 | uint64_t stackSize; 398 | CoreRange stackRange = SDMSTObjcStackSize(type, offset, &stackSize); 399 | if (stackRange.length) { 400 | parsedLength = (uint32_t)stackRange.length; 401 | } 402 | else { 403 | if (strncmp(&(type[offset]), kObjcNameTokenStart, sizeof(char)) == 0) { 404 | CoreRange nameRange = SDMSTObjcGetTokenRangeFromOffset(type, offset+1, kObjcNameTokenEnd); 405 | char *name = calloc(1, sizeof(char)*((uint32_t)nameRange.length+256)); 406 | memcpy(name, &(type[nameRange.offset]), sizeof(char)*nameRange.length); 407 | decode->token[decode->tokenCount].typeName = name; 408 | parsedLength += (uint32_t)nameRange.length + 1; 409 | } 410 | if (strncmp(&(type[offset]), kObjcPointerEncoding, sizeof(char)) == 0) { 411 | decode->token[decode->tokenCount].pointerCount++; 412 | } 413 | if (strncmp(&(type[offset]), kObjcUnknownEncoding, sizeof(char)) == 0) { 414 | decode->token[decode->tokenCount].typeName = 0; 415 | } 416 | if (strncmp(&(type[offset]), kObjcStructTokenStart, sizeof(char)) == 0) { 417 | uint64_t next = offset+1; 418 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 419 | decode->token[decode->tokenCount].typeClass = ObjcStructEncoding; 420 | decode->token[decode->tokenCount].type = ObjcContainerTypeEncodingNames[0]; 421 | CoreRange contentsRange = SDMSTObjcGetStructContentsRange(type, next); 422 | char *contents = calloc(1, sizeof(char)*((uint32_t)contentsRange.length+256)); 423 | memcpy(contents, &(type[next]), contentsRange.length); 424 | CoreRange nameRange = SDMSTObjcGetStructNameRange(contents, 0); 425 | char *name = calloc(1, sizeof(char)*((uint32_t)nameRange.length+256)); 426 | memcpy(name, &(contents[nameRange.offset]), sizeof(char)*nameRange.length); 427 | decode->token[decode->tokenCount].typeName = name; 428 | 429 | char *structContentString = &(contents[nameRange.offset+nameRange.length])+sizeof(char); 430 | CoreRange contentRange = CoreRangeCreate(0, strlen(structContentString)); 431 | struct loader_objc_lexer_type *structContents = SDMSTMemberCountOfStructContents(structContentString, contentRange); 432 | decode->token[decode->tokenCount].childrenCount = structContents->tokenCount; 433 | decode->token[decode->tokenCount].children = calloc(structContents->tokenCount, sizeof(struct loader_objc_lexer_token)); 434 | for (uint32_t i = 0; i < structContents->tokenCount; i++) { 435 | struct loader_objc_lexer_token *child = &(decode->token[decode->tokenCount].children[i]); 436 | struct loader_objc_lexer_token *structMember = &(structContents->token[i]); 437 | memcpy(child, structMember, sizeof(struct loader_objc_lexer_token)); 438 | } 439 | parsedLength = (uint32_t)contentsRange.length + 1; 440 | free(structContents); 441 | decode->tokenCount++; 442 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 443 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 444 | } 445 | if (strncmp(&(type[offset]), kObjcArrayTokenStart, sizeof(char)) == 0) { 446 | uint64_t next = offset+1; 447 | uint64_t stackSize; 448 | CoreRange stackRange = SDMSTObjcStackSize(type, next, &stackSize); 449 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 450 | decode->token[decode->tokenCount].typeClass = ObjcArrayEncoding; 451 | decode->token[decode->tokenCount].arrayCount = (uint32_t)stackSize; 452 | next += stackRange.length; 453 | CoreRange arrayTypeRange = SDMSTObjcGetArrayContentsRange(type, next); 454 | char *arrayTypeString = calloc(1, sizeof(char)*(uint32_t)(arrayTypeRange.length+1)); 455 | memcpy(arrayTypeString, &(type[arrayTypeRange.offset]), arrayTypeRange.length); 456 | struct loader_objc_lexer_type *arrayType = SDMSTObjcDecodeType(arrayTypeString); 457 | char *typeAssignment = ObjcTypeEncodingNames[SDMObjcLexerConvertTokenToIndex(ObjcUnknownEncoding)]; 458 | if (arrayType->token[arrayType->tokenCount - 1].type) { 459 | typeAssignment = arrayType->token[arrayType->tokenCount - 1].type; 460 | } 461 | uint32_t typeLength = (uint32_t)strlen(typeAssignment); 462 | 463 | decode->token[decode->tokenCount].type = calloc(1, sizeof(char)*(typeLength+1)); 464 | memcpy(decode->token[decode->tokenCount].type, typeAssignment, typeLength); 465 | 466 | decode->token[decode->tokenCount].childrenCount = 1; 467 | decode->token[decode->tokenCount].children = calloc(1, sizeof(struct loader_objc_lexer_token)); 468 | memcpy(decode->token[decode->tokenCount].children, &(arrayType->token[0]), sizeof(struct loader_objc_lexer_token)); 469 | 470 | uint32_t newArrayLength = (uint32_t)(typeLength + 2 + (uint32_t)GetDigitsOfNumber(stackSize)); 471 | char *name = calloc(1, sizeof(char)*(newArrayLength)); 472 | memcpy(name, decode->token[decode->tokenCount].type, newArrayLength); 473 | sprintf(&(name[strlen(typeAssignment)]), "[%lld]", stackSize); 474 | decode->token[decode->tokenCount].typeName = name; 475 | parsedLength += arrayTypeRange.length + stackRange.length; 476 | free(arrayType); 477 | free(arrayTypeString); 478 | decode->tokenCount++; 479 | decode->token = realloc(decode->token, sizeof(struct loader_objc_lexer_token)*(decode->tokenCount+1)); 480 | memset(&(decode->token[decode->tokenCount]), 0, sizeof(struct loader_objc_lexer_token)); 481 | } 482 | } 483 | } 484 | return parsedLength; 485 | } 486 | 487 | struct loader_objc_lexer_type* SDMSTObjcDecodeTypeWithLength(char *type, uint64_t decodeLength) { 488 | struct loader_objc_lexer_type *decode = calloc(1, sizeof(struct loader_objc_lexer_type)); 489 | decode->token = (struct loader_objc_lexer_token *)calloc(1, sizeof(struct loader_objc_lexer_token)); 490 | uint64_t length = decodeLength; 491 | if (length) { 492 | uint64_t offset = 0; 493 | while (offset < length) { 494 | uint32_t parsedLength = SDMSTParseToken(decode, type, offset); 495 | offset = offset + parsedLength; 496 | } 497 | 498 | } 499 | return decode; 500 | } 501 | 502 | struct loader_objc_lexer_type * SDMSTObjcDecodeType(char *type) { 503 | return SDMSTObjcDecodeTypeWithLength(type, strlen(type)); 504 | } 505 | 506 | uint64_t SDMSTObjcDecodeSizeOfType(struct loader_objc_lexer_token *token) { 507 | uint64_t size = 0; 508 | if (token) { 509 | if (token->childrenCount) { 510 | for (uint32_t i = 0; i < token->childrenCount; i++) { 511 | size += SDMSTObjcDecodeSizeOfType(&(token->children[i])); 512 | } 513 | } 514 | else { 515 | if (token->pointerCount) { 516 | size += sizeof(Pointer); 517 | } 518 | else { 519 | switch (token->typeClass) { 520 | case ObjcCharEncoding: { 521 | size += sizeof(char); 522 | break; 523 | }; 524 | case ObjcIntEncoding: { 525 | size += sizeof(int); 526 | break; 527 | }; 528 | case ObjcShortEncoding: { 529 | size += sizeof(short); 530 | break; 531 | }; 532 | case ObjcLongEncoding: { 533 | size += sizeof(long); 534 | break; 535 | }; 536 | case ObjcLLongEncoding: { 537 | size += sizeof(long long); 538 | break; 539 | }; 540 | case ObjcUCharEncoding: { 541 | size += sizeof(unsigned char); 542 | break; 543 | }; 544 | case ObjcUIntEncoding: { 545 | size += sizeof(unsigned int); 546 | break; 547 | }; 548 | case ObjcUShortEncoding: { 549 | size += sizeof(unsigned short); 550 | break; 551 | }; 552 | case ObjcULongEncoding: { 553 | size += sizeof(unsigned long); 554 | break; 555 | }; 556 | case ObjcULLongEncoding: { 557 | size += sizeof(unsigned long long); 558 | break; 559 | }; 560 | case ObjcFloatEncoding: { 561 | size += sizeof(float); 562 | break; 563 | }; 564 | case ObjcDoubleEncoding: { 565 | size += sizeof(double); 566 | break; 567 | }; 568 | case ObjcBoolEncoding: { 569 | size += sizeof(signed char); 570 | break; 571 | }; 572 | case ObjcStringEncoding: { 573 | size += sizeof(char *); 574 | break; 575 | }; 576 | case ObjcIdEncoding: { 577 | size += sizeof(id); 578 | break; 579 | }; 580 | case ObjcClassEncoding: { 581 | size += sizeof(Class); 582 | break; 583 | }; 584 | case ObjcSelEncoding: { 585 | size += sizeof(SEL); 586 | break; 587 | }; 588 | case ObjcBitEncoding: { 589 | size += sizeof(char); 590 | break; 591 | }; 592 | case ObjcPointerEncoding: { 593 | size += sizeof(Pointer); 594 | break; 595 | }; 596 | default: { 597 | break; 598 | }; 599 | } 600 | } 601 | } 602 | } 603 | return size; 604 | } 605 | 606 | #endif 607 | -------------------------------------------------------------------------------- /loader/objc_lexer.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc_lexer.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 11/3/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_objc_lexer_h 10 | #define loader_objc_lexer_h 11 | 12 | #include "util.h" 13 | 14 | #define kObjcCharEncoding "c" 15 | #define kObjcIntEncoding "i" 16 | #define kObjcShortEncoding "s" 17 | #define kObjcLongEncoding "l" 18 | #define kObjcLLongEncoding "q" 19 | #define kObjcUCharEncoding "C" 20 | #define kObjcUIntEncoding "I" 21 | #define kObjcUShortEncoding "S" 22 | #define kObjcULongEncoding "L" 23 | #define kObjcULLongEncoding "Q" 24 | #define kObjcFloatEncoding "f" 25 | #define kObjcDoubleEncoding "d" 26 | #define kObjcBoolEncoding "B" 27 | #define kObjcVoidEncoding "v" 28 | #define kObjcStringEncoding "*" 29 | #define kObjcIdEncoding "@" 30 | #define kObjcClassEncoding "#" 31 | #define kObjcSelEncoding ":" 32 | #define kObjcBitEncoding "b" 33 | #define kObjcPointerEncoding "^" 34 | #define kObjcUnknownEncoding "?" 35 | 36 | #define kObjcConstEncoding "r" 37 | #define kObjcInEncoding "n" 38 | #define kObjcInOutEncoding "N" 39 | #define kObjcOutEncoding "o" 40 | #define kObjcByCopyEncoding "O" 41 | #define kObjcByRefEncoding "R" 42 | #define kObjcOnewayEncoding "V" 43 | 44 | enum LoaderObjcLexerTokenType { 45 | ObjcCharEncoding = 1, 46 | ObjcIntEncoding, 47 | ObjcShortEncoding, 48 | ObjcLongEncoding, 49 | ObjcLLongEncoding, 50 | ObjcUCharEncoding, 51 | ObjcUIntEncoding, 52 | ObjcUShortEncoding, 53 | ObjcULongEncoding, 54 | ObjcULLongEncoding, 55 | ObjcFloatEncoding, 56 | ObjcDoubleEncoding, 57 | ObjcBoolEncoding, 58 | ObjcVoidEncoding, 59 | ObjcStringEncoding, 60 | ObjcIdEncoding, 61 | ObjcClassEncoding, 62 | ObjcSelEncoding, 63 | ObjcBitEncoding, 64 | ObjcPointerEncoding, 65 | ObjcUnknownEncoding, 66 | ObjcStructEncoding, 67 | ObjcArrayEncoding 68 | }; 69 | 70 | #define kObjcNameTokenStart "\"" 71 | #define kObjcNameTokenEnd "\"" 72 | 73 | #define kObjcArrayTokenStart "[" 74 | #define kObjcArrayTokenEnd "]" 75 | 76 | #define kObjcStructTokenStart "{" 77 | #define kObjcStructTokenEnd "}" 78 | 79 | #define kObjcStructDefinitionToken "=" 80 | 81 | #define SDMObjcLexerConvertIndexToToken(a) (enum LoaderObjcLexerTokenType)(a+1) 82 | #define SDMObjcLexerConvertTokenToIndex(a) (uint32_t)(a-1) 83 | 84 | struct loader_objc_lexer_token { 85 | char *type; 86 | char *typeName; 87 | enum LoaderObjcLexerTokenType typeClass; 88 | struct loader_objc_lexer_token *children; 89 | uint32_t childrenCount; 90 | uint32_t pointerCount; 91 | uint32_t arrayCount; 92 | } ATR_PACK loader_objc_lexer_token; 93 | 94 | struct loader_objc_lexer_type { 95 | struct loader_objc_lexer_token *token; 96 | uint32_t tokenCount; 97 | } ATR_PACK loader_objc_lexer_type; 98 | 99 | struct loader_objc_lexer_type* SDMSTObjcDecodeTypeWithLength(char *type, uint64_t decodeLength); 100 | struct loader_objc_lexer_type* SDMSTObjcDecodeType(char *type); 101 | CoreRange SDMSTObjcGetTokenRangeFromOffset(char *type, uint64_t offset, char *token); 102 | char* SDMSTObjcPointersForToken(struct loader_objc_lexer_token *token); 103 | char* SDMSTObjcCreateMethodDescription(struct loader_objc_lexer_type *type, char *name); 104 | uint64_t SDMSTObjcDecodeSizeOfType(struct loader_objc_lexer_token *token); 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /loader/objc_runtime.c: -------------------------------------------------------------------------------- 1 | // 2 | // objc_runtime.c 3 | // loader 4 | // 5 | // Created by Sam Marshall on 11/10/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_objc_runtime_c 10 | #define loader_objc_runtime_c 11 | 12 | #include "objc_runtime.h" 13 | #include 14 | 15 | struct SDMSTObjcClass* SDMSTObjc1CreateClassFromProtocol(struct SDMSTObjc *objcData, struct SDMSTObjc1Protocol *prot, uint64_t offset) { 16 | struct SDMSTObjcClass *newClass = calloc(1, sizeof(struct SDMSTObjcClass)); 17 | if (prot) { 18 | newClass->className = Ptr(PtrAdd(offset, prot->name)); 19 | } 20 | return newClass; 21 | } 22 | 23 | struct SDMSTObjcClass* SDMSTObjc1CreateClassFromCategory(struct SDMSTObjc *objcData, struct SDMSTObjc1Category *cat, uint64_t offset) { 24 | struct SDMSTObjcClass *newClass = calloc(1, sizeof(struct SDMSTObjcClass)); 25 | if (cat) { 26 | newClass->className = Ptr(PtrAdd(offset, cat->name)); 27 | } 28 | return newClass; 29 | } 30 | 31 | struct SDMSTObjcClass* SDMSTObjc1CreateClassFromClass(struct SDMSTObjc *objcData, struct SDMSTObjc1Class *cls, uint64_t offset) { 32 | struct SDMSTObjcClass *newClass = calloc(1, sizeof(struct SDMSTObjcClass)); 33 | if (cls) { 34 | if (cls->superClass != 0) { 35 | bool isValidClass = SDMSTObjc1ValidClassCheck(((uint32_t)(cls->info))); 36 | if (cls->superClass != cls->isa && isValidClass) { 37 | struct SDMSTObjc1Class *objc1class = (struct SDMSTObjc1Class *)PtrAdd(offset, cls->superClass); 38 | newClass->superCls = SDMSTObjc1CreateClassFromClass(objcData, objc1class, offset); 39 | } else if (isValidClass) { 40 | newClass->superCls = (struct SDMSTObjcClass *)PtrAdd(offset, cls->superClass); 41 | } else { 42 | newClass->superCls = 0; 43 | } 44 | newClass->className = Ptr(PtrAdd(offset, cls->name)); 45 | 46 | struct SDMSTObjc1ClassIVarInfo *ivarInfo = (struct SDMSTObjc1ClassIVarInfo *)PtrAdd(offset, cls->ivars); 47 | if (ivarInfo) { 48 | newClass->ivarCount = ivarInfo->count; 49 | newClass->ivar = calloc(newClass->ivarCount, sizeof(struct SDMSTObjcIVar)); 50 | struct SDMSTObjc1ClassIVar *ivarOffset = (struct SDMSTObjc1ClassIVar *)PtrAdd(ivarInfo, sizeof(struct SDMSTObjc1ClassIVarInfo)); 51 | for (uint32_t i = 0; i < newClass->ivarCount; i++) { 52 | newClass->ivar[i].name = Ptr(PtrAdd(offset, ivarOffset[i].name)); 53 | newClass->ivar[i].type = Ptr(PtrAdd(offset, ivarOffset[i].type)); 54 | newClass->ivar[i].offset = (uintptr_t)(ivarOffset[i].offset); 55 | } 56 | 57 | } 58 | 59 | struct SDMSTObjc1ClassMethodInfo *methodInfo = (struct SDMSTObjc1ClassMethodInfo *)PtrAdd(offset, cls->methods); 60 | if (methodInfo && (((uint64_t)methodInfo >= (uint64_t)PtrAdd(PtrHighPointer(offset), objcData->classRange.offset) && (uint64_t)methodInfo < (uint64_t)PtrAdd(PtrHighPointer(offset), (objcData->clsMRange.offset + (uint64_t)objcData->clsMRange.length))) || ((uint64_t)methodInfo >= (uint64_t)PtrAdd(PtrHighPointer(offset), objcData->instMRange.offset) && (uint64_t)methodInfo < (uint64_t)PtrAdd(PtrHighPointer(offset), (objcData->instMRange.offset + objcData->instMRange.length))))) { 61 | newClass->methodCount = methodInfo->count; 62 | newClass->method = calloc(newClass->methodCount, sizeof(struct SDMSTObjcMethod)); 63 | struct SDMSTObjc1ClassMethod *methodOffset = (struct SDMSTObjc1ClassMethod *)PtrAdd(methodInfo, sizeof(struct SDMSTObjc1ClassMethodInfo)); 64 | for (uint32_t i = 0; i < newClass->methodCount; i++) { 65 | newClass->method[i].name = Ptr(PtrAdd(offset, methodOffset[i].name)); 66 | newClass->method[i].type = Ptr(PtrAdd(offset, methodOffset[i].type)); 67 | newClass->method[i].offset = (uintptr_t)(methodOffset[i].imp); 68 | } 69 | } 70 | 71 | struct SDMSTObjc1Protocol *protocolInfo = (struct SDMSTObjc1Protocol *)PtrAdd(offset, cls->protocols); 72 | if (protocolInfo) { 73 | 74 | } 75 | } 76 | } 77 | return newClass; 78 | } 79 | 80 | void SDMSTObjc1CreateClassFromSymbol(struct SDMSTObjc *objcData, struct SDMSTObjc1Symtab *symtab) { 81 | if (symtab) { 82 | uint32_t counter = symtab->catCount + symtab->classCount; 83 | struct SDMSTObjc1SymtabDefinition *symbol = (struct SDMSTObjc1SymtabDefinition *)PtrAdd(symtab, sizeof(struct SDMSTObjc1Symtab)); 84 | for (uint32_t i = 0; i < counter; i++) { 85 | uint64_t memOffset; 86 | if (((PtrAdd(memOffset, symbol[i].defintion) >= (PtrAdd(PtrHighPointer(memOffset), objcData->classRange.offset))) && (PtrAdd(memOffset, symbol[i].defintion) <= (PtrAdd(PtrHighPointer(memOffset), ((uint64_t)(objcData->classRange.offset) + (uint64_t)objcData->classRange.length)))))) { 87 | struct SDMSTObjc1Class *objc1class = (struct SDMSTObjc1Class *)PtrAdd(memOffset, symbol[i].defintion); 88 | struct SDMSTObjcClass *newClass = SDMSTObjc1CreateClassFromClass(objcData, objc1class, memOffset); 89 | memcpy(&(objcData->cls[objcData->clsCount]), newClass, sizeof(struct SDMSTObjcClass)); 90 | free(newClass); 91 | objcData->clsCount++; 92 | objcData->cls = realloc(objcData->cls, sizeof(struct SDMSTObjcClass)*(objcData->clsCount+1)); 93 | } 94 | if ((PtrAdd(memOffset, symbol[i].defintion) >= PtrAdd(PtrHighPointer(memOffset), objcData->catRange.offset)) && (PtrAdd(memOffset, symbol[i].defintion) <= (PtrAdd(PtrHighPointer(memOffset), (objcData->catRange.offset + objcData->catRange.length))))) { 95 | struct SDMSTObjc1Category *objc1cat = (struct SDMSTObjc1Category *)PtrAdd(memOffset,symbol[i].defintion); 96 | struct SDMSTObjcClass *newClass = SDMSTObjc1CreateClassFromCategory(objcData, objc1cat, memOffset); 97 | memcpy(&(objcData->cls[objcData->clsCount]), newClass, sizeof(struct SDMSTObjcClass)); 98 | free(newClass); 99 | objcData->clsCount++; 100 | objcData->cls = realloc(objcData->cls, sizeof(struct SDMSTObjcClass)*(objcData->clsCount+1)); 101 | } 102 | symbol = (struct SDMSTObjc1SymtabDefinition *)PtrAdd(symbol, sizeof(struct SDMSTObjc1SymtabDefinition)); 103 | } 104 | } 105 | } 106 | 107 | struct SDMSTObjcClass* SDMSTObjc2ClassCreateFromClass(struct SDMSTObjc2Class *cls, struct SDMSTObjc2Class *parentClass, CoreRange dataRange, uint64_t offset) { 108 | struct SDMSTObjcClass *newClass = calloc(1, sizeof(struct SDMSTObjcClass)); 109 | if (cls != parentClass) { 110 | if ((PtrAdd(offset, cls->isa >= Ptr(dataRange.offset)) && (PtrAdd(offset, cls->isa) < (PtrAdd(offset, (dataRange.offset + dataRange.length)))))) { 111 | newClass->superCls = SDMSTObjc2ClassCreateFromClass((cls->isa),cls, dataRange, offset); 112 | struct SDMSTObjc2ClassData *data = (struct SDMSTObjc2ClassData *)PtrAdd(cls->data, offset); 113 | newClass->className = Ptr(PtrAdd(data->name, offset)); 114 | 115 | struct SDMSTObjc2ClassIVarInfo *ivarInfo = ((struct SDMSTObjc2ClassIVarInfo*)PtrAdd(data->ivar, offset)); 116 | if (ivarInfo && (uint64_t)ivarInfo != offset) { 117 | newClass->ivarCount = ivarInfo->count; 118 | newClass->ivar = calloc(newClass->ivarCount, sizeof(struct SDMSTObjcIVar)); 119 | struct SDMSTObjc2ClassIVar *ivarOffset = (struct SDMSTObjc2ClassIVar *)PtrAdd(ivarInfo, sizeof(struct SDMSTObjc2ClassIVarInfo)); 120 | for (uint32_t i = 0; i < newClass->ivarCount; i++) { 121 | newClass->ivar[i].name = Ptr(PtrAdd(offset, ivarOffset[i].name)); 122 | newClass->ivar[i].type = Ptr(PtrAdd(offset, ivarOffset[i].type)); 123 | newClass->ivar[i].offset = (uintptr_t)(ivarOffset[i].offset); 124 | } 125 | } 126 | 127 | struct SDMSTObjc2ClassMethodInfo *methodInfo = ((struct SDMSTObjc2ClassMethodInfo*)PtrAdd(data->method, offset)); 128 | if (methodInfo && (uint64_t)methodInfo != offset) { 129 | newClass->methodCount = methodInfo->count; 130 | newClass->method = calloc(newClass->methodCount, sizeof(struct SDMSTObjcMethod)); 131 | struct SDMSTObjc2ClassMethod *methodOffset = (struct SDMSTObjc2ClassMethod *)PtrAdd(methodInfo, sizeof(struct SDMSTObjc2ClassMethodInfo)); 132 | for (uint32_t i = 0; i < newClass->methodCount; i++) { 133 | newClass->method[i].name = Ptr(PtrAdd(offset, methodOffset[i].name)); 134 | newClass->method[i].type = Ptr(PtrAdd(offset, methodOffset[i].type)); 135 | newClass->method[i].offset = (uintptr_t)(methodOffset[i].imp); 136 | } 137 | } 138 | 139 | struct SDMSTObjc2ClassProtcolInfo *protocolInfo = ((struct SDMSTObjc2ClassProtcolInfo*)PtrAdd(data->protocol, offset)); 140 | if (protocolInfo && (uint64_t)protocolInfo != offset) { 141 | newClass->protocolCount = (uint32_t)(protocolInfo->count); 142 | newClass->protocol = calloc(newClass->protocolCount, sizeof(struct SDMSTObjcProtocol)); 143 | struct SDMSTObjc2ClassProtocol *protocolOffset = (struct SDMSTObjc2ClassProtocol *)PtrAdd(protocolInfo, sizeof(struct SDMSTObjc2ClassProtcolInfo)); 144 | for (uint32_t i = 0; i < newClass->protocolCount; i++) { 145 | newClass->protocol[i].offset = (uintptr_t)(protocolOffset[i].offset); 146 | } 147 | } 148 | } 149 | } 150 | return newClass; 151 | } 152 | 153 | 154 | #endif -------------------------------------------------------------------------------- /loader/objc_runtime.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc_runtime.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 11/2/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_objc_runtime_h 10 | #define loader_objc_runtime_h 11 | #include "objc_lexer.h" 12 | #include "objc1_runtime.h" 13 | #include "objc2_runtime.h" 14 | 15 | struct SDMSTObjcIVar { 16 | char *name; 17 | char *type; 18 | uintptr_t offset; 19 | } ATR_PACK SDMSTObjcIVar; 20 | 21 | struct SDMSTObjcMethod { 22 | char *name; 23 | char *type; 24 | uintptr_t offset; 25 | } ATR_PACK SDMSTObjcMethod; 26 | 27 | struct SDMSTObjcProtocol { 28 | uintptr_t offset; 29 | } ATR_PACK SDMSTObjcProtocol; 30 | 31 | struct SDMSTObjcClass { 32 | struct SDMSTObjcClass *superCls; 33 | char *className; 34 | struct SDMSTObjcIVar *ivar; 35 | uint32_t ivarCount; 36 | struct SDMSTObjcMethod *method; 37 | uint32_t methodCount; 38 | struct SDMSTObjcProtocol *protocol; 39 | uint32_t protocolCount; 40 | } ATR_PACK SDMSTObjcClass; 41 | 42 | struct SDMSTObjcModule { 43 | char *impName; 44 | struct SDMSTObjcClass *symbol; 45 | } ATR_PACK SDMSTObjcModule; 46 | 47 | struct SDMSTObjcModuleRaw { 48 | uint32_t version; 49 | uint32_t size; 50 | uint32_t name; 51 | uint32_t symtab; 52 | } ATR_PACK SDMSTObjcModuleRaw; 53 | 54 | struct SDMSTObjcModuleContainer { 55 | struct SDMSTObjcModule *module; 56 | uint32_t moduleCount; 57 | } ATR_PACK SDMSTObjcModuleContainer; 58 | 59 | struct SDMSTObjc { 60 | struct SDMSTObjcClass *cls; 61 | uint32_t clsCount; 62 | CoreRange classRange; 63 | CoreRange catRange; 64 | CoreRange protRange; 65 | CoreRange clsMRange; 66 | CoreRange instMRange; 67 | } ATR_PACK SDMSTObjc; 68 | 69 | #define CLS_CLASS 0x1 70 | #define CLS_META 0x2 71 | #define CLS_INITIALIZED 0x4 72 | #define CLS_POSING 0x8 73 | #define CLS_MAPPED 0x10 74 | #define CLS_FLUSH_CACHE 0x20 75 | #define CLS_GROW_CACHE 0x40 76 | #define CLS_NEED_BIND 0x80 77 | #define CLS_METHOD_ARRAY 0x100 78 | #define CLS_JAVA_HYBRID 0x200 79 | #define CLS_JAVA_CLASS 0x400 80 | #define CLS_INITIALIZING 0x800 81 | #define CLS_FROM_BUNDLE 0x1000 82 | #define CLS_HAS_CXX_STRUCTORS 0x2000 83 | #define CLS_NO_METHOD_ARRAY 0x4000 84 | #define CLS_HAS_LOAD_METHOD 0x8000 85 | #define CLS_CONSTRUCTING 0x10000 86 | #define CLS_EXT 0x20000 87 | 88 | #define SDMSTObjc1ValidClassCheck(a) ((a | CLS_CLASS) == 0 || (a | CLS_META) == 0 || (a | CLS_INITIALIZED) == 0 || (a | CLS_POSING) == 0 || (a | CLS_MAPPED) == 0 || (a | CLS_FLUSH_CACHE) == 0 || (a | CLS_GROW_CACHE) == 0 || (a | CLS_NEED_BIND) == 0 || (a | CLS_METHOD_ARRAY) == 0 || (a | CLS_JAVA_HYBRID) == 0 || (a | CLS_JAVA_CLASS) == 0 || (a | CLS_INITIALIZING) == 0 || (a | CLS_FROM_BUNDLE) == 0 || (a | CLS_HAS_CXX_STRUCTORS) == 0 || (a | CLS_NO_METHOD_ARRAY) == 0 || (a | CLS_HAS_LOAD_METHOD) == 0 || (a | CLS_CONSTRUCTING) == 0 || (a | CLS_EXT) == 0) 89 | 90 | struct SDMSTObjcClass* SDMSTObjc1CreateClassFromProtocol(struct SDMSTObjc *objcData, struct SDMSTObjc1Protocol *prot, uint64_t offset); 91 | struct SDMSTObjcClass* SDMSTObjc1CreateClassFromCategory(struct SDMSTObjc *objcData, struct SDMSTObjc1Category *cat, uint64_t offset); 92 | struct SDMSTObjcClass* SDMSTObjc1CreateClassFromClass(struct SDMSTObjc *objcData, struct SDMSTObjc1Class *cls, uint64_t offset); 93 | void SDMSTObjc1CreateClassFromSymbol(struct SDMSTObjc *objcData, struct SDMSTObjc1Symtab *symtab); 94 | struct SDMSTObjcClass* SDMSTObjc2ClassCreateFromClass(struct SDMSTObjc2Class *cls, struct SDMSTObjc2Class *parentClass, CoreRange dataRange, uint64_t offset); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /loader/runtime_base.c: -------------------------------------------------------------------------------- 1 | // 2 | // runtime_base.c 3 | // loader 4 | // 5 | // Created by Sam Marshall on 12/29/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_runtime_base_c 10 | #define loader_runtime_base_c 11 | 12 | #include "runtime_base.h" 13 | #include 14 | #include 15 | 16 | // SDM: SDMRuntimeBase.s calls 17 | extern void SDMGenericGetSetInterceptor(void); 18 | 19 | // SDM: this exists because we need the size of `Method` 20 | #pragma clang diagnostic push 21 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 22 | typedef struct objc_method MethodStruct; 23 | #pragma clang diagnostic pop 24 | 25 | #define SDMGetSet (IMP)SDMGenericGetSetInterceptor 26 | 27 | #define SDMCreateGetter(ReturnType, obj, selector) ((ReturnType (*)(id, SEL))SDMGenericGetSetInterceptor)(obj, selector) 28 | #define SDMCallGetSetBlock(block) ((void (^)(id, SEL))block) 29 | 30 | BOOL SDMCanRegisterForIvarInClass(char *ivarName, Class class); 31 | BOOL SDMCanRegisterForPropertyInClass(char *propertyName, Class class); 32 | 33 | extern IMP SDMFireGetterSetterNotificationsAndReturnIMP(id self, SEL _cmd); 34 | 35 | #pragma mark - 36 | #pragma mark Private Calls 37 | 38 | BOOL SDMCanRegisterForIvarInClass(char *ivarName, Class class) { 39 | BOOL registerStatus = NO; 40 | Ivar ivar = class_getInstanceVariable(class, ivarName); 41 | if (ivar) { 42 | registerStatus = YES; 43 | } 44 | return registerStatus; 45 | } 46 | 47 | BOOL SDMCanRegisterForPropertyInClass(char *propertyName, Class class) { 48 | BOOL registerStatus = NO; 49 | objc_property_t property = class_getProperty(class, propertyName); 50 | if (property) { 51 | registerStatus = YES; 52 | } 53 | return registerStatus; 54 | } 55 | 56 | IMP observerResolveInstanceMethod(id self, SEL _cmd, ...) { 57 | IMP resolved = nil; 58 | printf("we are being called!"); 59 | return resolved; 60 | } 61 | 62 | char* SDMGenerateGetterName(char *keyName) { 63 | unsigned long length = sizeof(char)*strlen(keyName); 64 | char *hasGet = calloc(1, length); 65 | memcpy(hasGet, keyName, length); 66 | return hasGet; 67 | } 68 | 69 | char* SDMGenerateObserver(char *selName) { 70 | char *observe = "Observer"; 71 | unsigned long oLength = strlen(observe); 72 | unsigned long selLength = strlen(selName); 73 | unsigned long totalLength = sizeof(char)*(selLength+oLength+1); 74 | char *observerSelector = calloc(1, totalLength); 75 | memcpy(observerSelector, observe, oLength); 76 | memcpy(&(observerSelector[oLength]), selName, selLength); 77 | return observerSelector; 78 | } 79 | 80 | char* SDMGenerateSetterName(char *keyName) { 81 | unsigned long length = sizeof(char)*strlen(keyName); 82 | unsigned long totalLength = length+4; 83 | char *hasSet = calloc(1, totalLength); 84 | memcpy(hasSet, "set", 3); 85 | memcpy(&(hasSet[3]), keyName, length); 86 | hasSet[3] = toupper(hasSet[3]); 87 | memcpy(&(hasSet[totalLength-1]), ":", 1); 88 | return hasSet; 89 | } 90 | 91 | char* SDMGenerateMethodSignature(Method method) { 92 | unsigned int count = method_getNumberOfArguments(method); 93 | char *signature = calloc(1, sizeof(char[2])); 94 | method_getReturnType(method, signature, 2); 95 | 96 | for (unsigned int i = 0; i < count; i++) { 97 | unsigned int length = sizeof(char[256]); 98 | char *buffer = calloc(1, length); 99 | method_getArgumentType(method, i, buffer, length); 100 | unsigned long sigLength = sizeof(char)*(strlen(signature)+strlen(buffer)); 101 | signature = realloc(signature, sigLength); 102 | strlcat(signature, buffer, sigLength); 103 | free(buffer); 104 | } 105 | return signature; 106 | } 107 | 108 | IMP SDMFireGetterSetterNotificationsAndReturnIMP(id self, SEL _cmd) { 109 | char *originalSelector = (char*)sel_getName(_cmd); 110 | char *resolveSelector; 111 | BOOL observedSelector = NO; 112 | BOOL isGetter = NO; 113 | BOOL isSetter = NO; 114 | IMP originalImplementation; 115 | struct MethodCalls *originalMethods = nil; 116 | struct ObserverArray *observers = (struct ObserverArray *)objc_getAssociatedObject(self, self); 117 | if (observers) { 118 | uint32_t observableCount = observers->count; 119 | uint32_t index; 120 | for (index = 0; index < observableCount; index++) { 121 | char *observableGetter = observers->array[index].getName; 122 | char *observableSetter = observers->array[index].setName; 123 | if (strncmp(originalSelector, observableGetter, strlen(originalSelector)) == 0) { 124 | observedSelector = isGetter = YES; 125 | break; 126 | } 127 | if (strncmp(originalSelector, observableSetter, strlen(originalSelector)) == 0) { 128 | observedSelector = isSetter = YES; 129 | break; 130 | } 131 | } 132 | if (isGetter) { 133 | originalMethods = (struct MethodCalls *)objc_getAssociatedObject(self, observers->array[index].getName); 134 | SDMCallGetSetBlock(originalMethods->block)(self, _cmd); 135 | } 136 | 137 | if (isSetter) { 138 | originalMethods = (struct MethodCalls *)objc_getAssociatedObject(self, observers->array[index].setName); 139 | SDMCallGetSetBlock(originalMethods->block)(self, _cmd); 140 | } 141 | } 142 | if (!observedSelector) { 143 | originalMethods = calloc(1, sizeof(struct MethodCalls)); 144 | resolveSelector = SDMGenerateObserver(originalSelector); 145 | originalMethods->originalCall = class_getInstanceMethod((Class)object_getClass(self), sel_registerName(resolveSelector)); 146 | originalMethods->switchCall = class_getInstanceMethod((Class)object_getClass(self), _cmd); 147 | } 148 | originalImplementation = method_getImplementation(originalMethods->originalCall); 149 | return originalImplementation; 150 | } 151 | 152 | #pragma mark - 153 | #pragma mark Public Calls 154 | 155 | BOOL SDMRegisterCallbacksForKeyInInstance(BlockPointer getObserve, BlockPointer setObserve, char *keyName, id instance) { 156 | BOOL registerStatus = NO; 157 | BOOL registerGetStatus = NO; 158 | BOOL registerSetStatus = NO; 159 | if ((getObserve && setObserve) && instance) { 160 | __block char *getName = 0; 161 | __block char *setName = 0; 162 | 163 | Class class = objc_getClass(object_getClassName(instance)); 164 | BOOL isProperty = SDMCanRegisterForPropertyInClass(keyName, class); 165 | if (isProperty) { 166 | objc_property_t property = class_getProperty(class, keyName); 167 | if (property) { 168 | 169 | char *hasGet = property_copyAttributeValue(property, "G"); 170 | if (!hasGet) { 171 | hasGet = SDMGenerateGetterName(keyName); 172 | } 173 | getName = hasGet; 174 | 175 | char *isImmutable = property_copyAttributeValue(property, "R"); 176 | if (!isImmutable) { 177 | char *hasSet = property_copyAttributeValue(property, "S"); 178 | if (!hasSet) { 179 | hasSet = SDMGenerateSetterName(keyName); 180 | } 181 | setName = hasSet; 182 | } 183 | } 184 | } else { 185 | BOOL isIVar = SDMCanRegisterForIvarInClass(keyName, class); 186 | if (isIVar) { 187 | getName = SDMGenerateGetterName(keyName); 188 | setName = SDMGenerateSetterName(keyName); 189 | } 190 | } 191 | 192 | __block struct MethodNames *originalMethods; 193 | id associatedObject = objc_getAssociatedObject(instance, instance); 194 | if (associatedObject) { 195 | __block BOOL existingObserverForKey = NO; 196 | __block struct ObserverArray *existingObservers = PtrCast(associatedObject, struct ObserverArray*); 197 | __block uint32_t index; 198 | dispatch_sync(existingObservers->operationsQueue, ^{ 199 | for (index = 0; index < existingObservers->count; index++) { 200 | char *key = existingObservers->array[index].keyName; 201 | if (strncmp(keyName, key, strlen(keyName)) == 0) { 202 | existingObserverForKey = YES; 203 | // SDM: we have an existing observer registered. 204 | break; 205 | } 206 | } 207 | if (!existingObserverForKey) { 208 | if (index == existingObservers->count) { 209 | originalMethods = calloc(1, sizeof(struct MethodNames)); 210 | char *keyOperationsQueueName = calloc(1, sizeof(char[256])); 211 | snprintf(keyOperationsQueueName, 256, "%s-%s-%p",class_getName(class),keyName,instance); 212 | originalMethods->keyQueue = dispatch_queue_create(keyOperationsQueueName, DISPATCH_QUEUE_SERIAL); 213 | originalMethods->keyName = calloc(1, strlen(keyName)); 214 | memcpy(originalMethods->keyName, keyName, strlen(keyName)); 215 | originalMethods->getName = calloc(1, strlen(getName)); 216 | memcpy(originalMethods->getName, getName, strlen(getName)); 217 | originalMethods->setName = calloc(1, strlen(setName)); 218 | memcpy(originalMethods->setName, setName, strlen(setName)); 219 | 220 | existingObservers->array = realloc(existingObservers->array, sizeof(struct MethodNames)*(existingObservers->count+1)); 221 | existingObservers->count++; 222 | memcpy(&(existingObservers->array[existingObservers->count-1]), originalMethods, sizeof(struct MethodNames)); 223 | } 224 | } 225 | }); 226 | if (!existingObserverForKey) { 227 | if (index != existingObservers->count) { 228 | originalMethods = &(existingObservers->array[index]); 229 | if (originalMethods->isEnabled) { 230 | return registerStatus; 231 | } 232 | } 233 | } else { 234 | return registerStatus; 235 | } 236 | } else { 237 | originalMethods = calloc(1, sizeof(struct MethodNames)); 238 | char *keyOperationsQueueName = calloc(1, sizeof(char[256])); 239 | snprintf(keyOperationsQueueName, 256, "%s-%s-%p",class_getName(class),keyName,instance); 240 | originalMethods->keyQueue = dispatch_queue_create(keyOperationsQueueName, DISPATCH_QUEUE_SERIAL); 241 | originalMethods->keyName = calloc(1, strlen(keyName)); 242 | memcpy(originalMethods->keyName, keyName, strlen(keyName)); 243 | originalMethods->getName = calloc(1, strlen(getName)); 244 | memcpy(originalMethods->getName, getName, strlen(getName)); 245 | originalMethods->setName = calloc(1, strlen(setName)); 246 | memcpy(originalMethods->setName, setName, strlen(setName)); 247 | 248 | struct ObserverArray *observers = calloc(1, sizeof(struct ObserverArray)); 249 | char *operationsQueueName = calloc(1, 0x100); 250 | snprintf(operationsQueueName, 0x100, "%s-observer-operations-queue",class_getName(class)); 251 | observers->operationsQueue = dispatch_queue_create(operationsQueueName, DISPATCH_QUEUE_SERIAL); 252 | observers->array = originalMethods; 253 | observers->count = 0x1; 254 | objc_setAssociatedObject(instance, instance, PtrCast(observers, id), OBJC_ASSOCIATION_ASSIGN); 255 | } 256 | 257 | if (originalMethods->getName) { 258 | SEL realGetSelector = sel_registerName(originalMethods->getName); 259 | Method resolveGetter = class_getInstanceMethod(class, realGetSelector); 260 | SEL observerGetSelector; 261 | 262 | if (resolveGetter) { 263 | char *observerGetterName = SDMGenerateObserver(originalMethods->getName); 264 | observerGetSelector = sel_registerName(observerGetterName); 265 | char *getMethodSignature = SDMGenerateMethodSignature(resolveGetter); 266 | 267 | IMP getSelector = SDMGetSet; 268 | 269 | struct MethodCalls *methods = calloc(1, sizeof(struct MethodCalls)); 270 | methods->block = getObserve; 271 | methods->switchCall = resolveGetter; 272 | BOOL addObserverGetter = class_addMethod(class, observerGetSelector, getSelector, getMethodSignature); 273 | if (addObserverGetter) { 274 | Method getter = class_getInstanceMethod(class, observerGetSelector); 275 | method_exchangeImplementations(resolveGetter, getter); 276 | Method observerGetter = calloc(1, sizeof(MethodStruct)); 277 | memcpy(observerGetter, getter, sizeof(MethodStruct)); 278 | methods->originalCall = observerGetter; 279 | objc_setAssociatedObject(instance, originalMethods->getName, PtrCast(methods,id), OBJC_ASSOCIATION_ASSIGN); 280 | } else { 281 | Method getTest = class_getInstanceMethod(class, observerGetSelector); 282 | if (getTest) { 283 | method_exchangeImplementations(resolveGetter, getTest); 284 | methods->originalCall = getTest; 285 | objc_setAssociatedObject(instance, originalMethods->getName, PtrCast(methods,id), OBJC_ASSOCIATION_ASSIGN); 286 | addObserverGetter = YES; 287 | } 288 | } 289 | registerGetStatus = addObserverGetter; 290 | free(observerGetterName); 291 | } 292 | } 293 | 294 | if (originalMethods->setName) { 295 | SEL realSetSelector = sel_registerName(originalMethods->setName); 296 | Method resolveSetter = class_getInstanceMethod(class, realSetSelector); 297 | 298 | if (resolveSetter) { 299 | char *observerSetterName = SDMGenerateObserver(originalMethods->setName); 300 | SEL observerSetSelector = sel_registerName(observerSetterName); 301 | char *setMethodSignature = SDMGenerateMethodSignature(resolveSetter); 302 | 303 | IMP setSelector = SDMGetSet; 304 | 305 | struct MethodCalls *methods = calloc(1, sizeof(struct MethodCalls)); 306 | methods->block = setObserve; 307 | methods->switchCall = resolveSetter; 308 | BOOL addObserverSetter = class_addMethod(class, observerSetSelector, setSelector, setMethodSignature); 309 | if (addObserverSetter) { 310 | Method setter = class_getInstanceMethod(class, observerSetSelector); 311 | method_exchangeImplementations(resolveSetter, setter); 312 | Method observerSetter = calloc(1, sizeof(MethodStruct)); 313 | memcpy(observerSetter, setter, sizeof(MethodStruct)); 314 | methods->originalCall = observerSetter; 315 | objc_setAssociatedObject(instance, originalMethods->setName, PtrCast(methods,id), OBJC_ASSOCIATION_ASSIGN); 316 | } else { 317 | Method setTest = class_getInstanceMethod(class, observerSetSelector); 318 | if (setTest) { 319 | method_exchangeImplementations(resolveSetter, setTest); 320 | methods->originalCall = setTest; 321 | objc_setAssociatedObject(instance, originalMethods->setName, PtrCast(methods,id), OBJC_ASSOCIATION_ASSIGN); 322 | addObserverSetter = YES; 323 | } 324 | } 325 | registerSetStatus = addObserverSetter; 326 | free(observerSetterName); 327 | } 328 | } 329 | if (registerGetStatus) { 330 | registerStatus = YES; 331 | originalMethods->isEnabled = registerGetStatus; 332 | } 333 | } 334 | return registerStatus; 335 | } 336 | 337 | void SDMRemoveCallbackForKeyInInstance(char *keyName, id instance) { 338 | __block id associatedObject = objc_getAssociatedObject(instance, instance); 339 | if (associatedObject) { 340 | __block struct ObserverArray *observers = PtrCast(associatedObject, struct ObserverArray*); 341 | dispatch_sync(observers->operationsQueue, ^{ 342 | for (uint32_t i = 0; i < observers->count; i++) { 343 | struct MethodNames *originalMethods = &(observers->array[i]); 344 | char *observerKey = originalMethods->keyName; 345 | if (strncmp(keyName, observerKey, strlen(keyName)) == 0) { 346 | 347 | id originalGetterValue = objc_getAssociatedObject(instance, originalMethods->getName); 348 | struct MethodCalls *observerGetterMethod = PtrCast(originalGetterValue,struct MethodCalls *); 349 | if (observerGetterMethod) { 350 | method_exchangeImplementations(observerGetterMethod->switchCall, observerGetterMethod->originalCall); 351 | } 352 | 353 | id originalSetterValue = objc_getAssociatedObject(instance, originalMethods->setName); 354 | struct MethodCalls *observerSetterMethod = PtrCast(originalSetterValue,struct MethodCalls *); 355 | if (observerSetterMethod) { 356 | method_exchangeImplementations(observerSetterMethod->switchCall, observerSetterMethod->originalCall); 357 | } 358 | 359 | originalMethods->isEnabled = NO; 360 | } 361 | } 362 | }); 363 | } 364 | } 365 | 366 | #endif 367 | -------------------------------------------------------------------------------- /loader/runtime_base.h: -------------------------------------------------------------------------------- 1 | // 2 | // runtime_base.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 12/29/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_runtime_base_h 10 | #define loader_runtime_base_h 11 | 12 | #include "util.h" 13 | #include "type_register.h" 14 | 15 | #define ObserverGetSetBlock(ObserverName) void (^ObserverName)(id, SEL) = ^(id self, SEL _cmd) 16 | 17 | BOOL SDMRegisterCallbacksForKeyInInstance(BlockPointer getObserve, BlockPointer setObserve, char *keyName, id instance); 18 | 19 | void SDMRemoveCallbackForKeyInInstance(char *keyName, id instance); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /loader/runtime_base.s: -------------------------------------------------------------------------------- 1 | // Created by: Gwynne Raskind, gwynne@darkrainfall.org 2 | // Only the x86_64 function is fully explained; the other versions only comment the arch-specific notes 3 | 4 | .globl _SDMGenericGetSetInterceptor 5 | #if __x86_64__ 6 | _SDMGenericGetSetInterceptor: 7 | push %rbp 8 | mov %rsp, %rbp // set up a stack frame for easier debugging 9 | 10 | mov $0, %r10 11 | mov $1, %rax 12 | cmovne %rax, %r10 // save Z flag (stret from objc_msgSend) into r10 13 | 14 | // At this point we are correctly set up for returning the correct value in the correct place by definition. 15 | // ALL volatile state used for argument passing and returning must be preserved unconditionally before we call any functions. 16 | // We do not consider %rax a volatile state for this purpose, as it's not an input. 17 | // We also allow %r8 to be volatile since its value should not matter to a getter 18 | 19 | push %rdi // save arg0 (...) may be stret ptr or self 20 | push %rsi // save arg1 (...) may be self or _cmd 21 | push %rdx // save arg2 (...) may be _cmd or arg 22 | push %rcx // save arg3 (...) args 23 | push %r8 // save arg4 (...) args 24 | push %r9 // save arg5 (...) args 25 | sub $512, %rsp // reserve space on the stack to... 26 | fxsave (%rsp) // save off the full x87/MMX/SSE state 27 | 28 | // this function receives arg0 (self) and arg1 (_cmd) and MUST fire any notifications 29 | // AND return the IMP pointer for the original getter or setter 30 | cmp $1, %r10 // are we in stret mode? 31 | cmove %rsi, %rdi // if so, shift self up one 32 | cmove %rdx, %rsi // and also shift _cmd up one 33 | call _SDMFireGetterSetterNotificationsAndReturnIMP 34 | 35 | fxrstor (%rsp) // restore the full x87/MMX/SSE state 36 | add $512, %rsp // restore the stack pointer 37 | pop %r9 // restore arg5 38 | pop %r8 // restore arg4 39 | pop %rcx // restore arg3 40 | pop %rdx // restore arg2 41 | pop %rsi // restore arg1 42 | pop %rdi // restore arg0 43 | 44 | // restore original frame pointer; after this instruction, this function disappears from the debugger's backtrace 45 | pop %rbp 46 | 47 | // tail call to the original IMP - this right here is the part we just can't tell the compiler to do in C which makes the rest necessary 48 | jmp *%rax 49 | #elif __i386__ 50 | _SDMGenericGetSetInterceptor: 51 | push %ebp 52 | mov %esp, %ebp // stack frame 53 | 54 | mov $0x220, %edi 55 | mov $0x224, %esi 56 | cmovne %esi, %edi // save Z flag into offset register; must be done no later than this 57 | 58 | // i386 args go on the stack, non-fp registers are all volatile 59 | sub $520, %esp 60 | fxsave (%esp) 61 | 62 | // Stack: 63 | // param3 - 544 param2 - 540 param1 - 536 retaddr - 532 64 | // ebp - 528 fxsave - 16 _cmd - 4 self - 0 65 | sub $0x10, %esp // reserve args space on stack + alignment 66 | mov 0(%esp,%edi), %eax // set up self and _cmd arguments on the stack by copying from appropos spot in param area 67 | mov %eax, 0(%esp) 68 | mov 4(%esp,%edi), %eax 69 | mov %eax, 4(%esp) 70 | call _SDMFireGetterSetterNotificationsAndReturnIMP 71 | add $0x10, %esp // restore stack 72 | 73 | fxrstor (%esp) 74 | add $520, %esp 75 | 76 | pop %ebp 77 | jmp *%eax 78 | #elif __armv7__ || __ARM_ARCH_7__ || __ARM_ARCH_7S__ 79 | .syntax unified 80 | .code 32 81 | .align 5 82 | _SDMGenericGetSetInterceptor: 83 | push {r7, lr} 84 | add r7, sp, #8 // establish stack frame 85 | 86 | push {r0-r3} // save all argument registers 87 | vstmdb sp!, {d0-d7} // save VFP regs 88 | // if stret, shift self and _cmd up one; note that we haven't changed 89 | // NZCX since entry so it's safe to wait to here 90 | itt ne 91 | movne r0, r1 92 | movne r1, r2 93 | blx _SDMFireGetterSetterNotificationsAndReturnIMP 94 | mov ip, r0 // save IMP in IP (intraprocedural scratch) register 95 | vldmia sp!, {d0-d7} // restore VFP regs 96 | pop {r0-r3} // restore argument registers 97 | 98 | pop {r7, lr} // destroy stack frame 99 | bx ip // tail call to IMP WITH interworking and WITHOUT linking! 100 | #elif __arm64__ 101 | _SDMGenericGetSetInterceptor: 102 | stp fp, lr, [sp, #-16]! // save frame pointer and link register 103 | mov fp, sp // establish stack frame 104 | 105 | stp x0, x1, [sp, #-16]! 106 | stp x2, x3, [sp, #-16]! 107 | stp x4, x5, [sp, #-16]! 108 | stp x6, x7, [sp, #-16]! 109 | stp q0, q1, [sp, #-32]! 110 | stp q2, q3, [sp, #-32]! 111 | stp q4, q5, [sp, #-32]! 112 | stp q6, q7, [sp, #-32]! 113 | bl _SDMFireGetterNotificationsAndReturnImp 114 | mov x16, x0 // save IMP in ip0 (intraprocedural scratch) 115 | ldp q6, q7, [sp], #32 116 | ldp q4, q5, [sp], #32 117 | ldp q2, q3, [sp], #32 118 | ldp q0, q1, [sp], #32 119 | ldp x6, x7, [sp], #16 120 | ldp x4, x5, [sp], #16 121 | ldp x2, x3, [sp], #16 122 | ldp x0, x1, [sp], #16 123 | 124 | ldp fp, lr, [sp], #16 125 | b x16 126 | #endif 127 | -------------------------------------------------------------------------------- /loader/type_register.h: -------------------------------------------------------------------------------- 1 | // 2 | // type_register.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 12/29/13. 6 | // Copyright (c) 2013 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_type_register_h 10 | #define loader_type_register_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #pragma mark - 19 | #pragma mark Internal Types 20 | 21 | struct ObserverArray { 22 | dispatch_queue_t operationsQueue; 23 | struct MethodNames *array; 24 | uint32_t count; 25 | }; 26 | 27 | struct MethodNames { 28 | dispatch_queue_t keyQueue; 29 | char *keyName; 30 | char *getName; 31 | char *setName; 32 | BOOL isEnabled; 33 | }; 34 | 35 | #pragma mark - 36 | #pragma mark Return Blocks 37 | 38 | typedef void (^BlockPointer)(); 39 | 40 | typedef char (^SDMcharBlock)(id self); 41 | typedef int (^SDMintBlock)(id self); 42 | typedef short (^SDMshortBlock)(id self); 43 | typedef long (^SDMlongBlock)(id self); 44 | typedef long long (^SDMlonglongBlock)(id self); 45 | typedef unsigned char (^SDMunsignedcharBlock)(id self); 46 | typedef unsigned int (^SDMunsignedintBlock)(id self); 47 | typedef unsigned short (^SDMunsignedshortBlock)(id self); 48 | typedef unsigned long (^SDMunsignedlongBlock)(id self); 49 | typedef unsigned long long (^SDMunsignedlonglongBlock)(id self); 50 | typedef float (^SDMfloatBlock)(id self); 51 | typedef double (^SDMdoubleBlock)(id self); 52 | typedef BOOL (^SDMboolBlock)(id self); 53 | typedef char* (^SDMstringBlock)(id self); 54 | typedef id (^SDMidBlock)(id self); 55 | typedef Class (^SDMclassBlock)(id self); 56 | typedef SEL (^SDMselBlock)(id self); 57 | typedef Pointer (^SDMpointerBlock)(id self); 58 | 59 | struct MethodCalls { 60 | Method originalCall; 61 | Method switchCall; 62 | __unsafe_unretained BlockPointer block; 63 | }; 64 | 65 | #define SDMCreateBlockType(ReturnType) typedef ReturnType (^SDM##ReturnType##Block)(id self) 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /loader/util.h: -------------------------------------------------------------------------------- 1 | // 2 | // util.h 3 | // loader 4 | // 5 | // Created by Sam Marshall on 2/17/14. 6 | // Copyright (c) 2014 Sam Marshall. All rights reserved. 7 | // 8 | 9 | #ifndef loader_util_h 10 | #define loader_util_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define ATR_PACK __attribute__ ((packed)) 18 | #define ATR_FUNC(name) __attribute__ ((ifunc(name))) 19 | #define ATR_UNUSED __attribute__ ((unused)) 20 | 21 | #ifndef __clang__ 22 | #define __has_feature(x) /* empty */ 23 | #endif 24 | 25 | #if !__has_feature(objc_arc) 26 | #define __unsafe_unretained /* empty */ 27 | #endif 28 | 29 | #define GetDigitsOfNumber(num) (num > 0 ? (int)log10(num)+0x1 : 0x1) 30 | 31 | struct Range { 32 | uint64_t offset; 33 | uint64_t length; 34 | } ATR_PACK Range; 35 | 36 | typedef struct Range CoreRange; 37 | 38 | #define CoreRangeCreate(offset, length) (CoreRange){offset, length} 39 | #define CoreRangeContainsValue(range, value) (value >= range.offset && value < (range.offet + range.length)) 40 | 41 | typedef uintptr_t* Pointer; 42 | typedef uintptr_t* (*FunctionPointer)(); 43 | 44 | #define k32BitMask 0xffffffff 45 | #define k64BitMask 0xffffffffffffffff 46 | #define k64BitMaskHigh 0xffffffff00000000 47 | #define k64BitMaskLow 0x00000000ffffffff 48 | #define PtrCastSmallPointer(a) (*(Pointer)&(a)) 49 | #define PtrHighPointer(a) (a & k64BitMaskHigh) 50 | #define PtrLowPointer(a) (a & k64BitMaskLow) 51 | 52 | #define Ptr(ptr) PtrCast(ptr,char*) 53 | #define PtrCast(ptr, cast) ((cast)ptr) 54 | #define PtrAdd(ptr, add) (Ptr(ptr) + (uint64_t)add) 55 | #define PtrSub(ptr, sub) (Ptr(ptr) - (uint64_t)sub) 56 | 57 | #endif 58 | --------------------------------------------------------------------------------