├── Entitlements.plist ├── Example.c ├── Hook ├── Assembler.c ├── Assembler.h ├── ImmediateDecoding.h ├── InlineHook.c └── InlineHook.h ├── LICENSE ├── Make ├── android.mk ├── darwin.mk └── linux.mk ├── Makefile ├── Memory ├── Memory.h ├── MemoryAllocator.c ├── MemoryAllocator.h ├── MemoryTracker.c └── MemoryTracker.h ├── README.md ├── SymbolResolve ├── Darwin │ ├── LCStrings.h │ ├── Macho.c │ └── Macho.h └── Linux │ ├── Elf.c │ └── Elf.h ├── apple ├── cs_blobs.h └── dyld_cache_format.h └── utility ├── debug.h ├── error.h └── utility.h /Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | com.apple.private.security.no-container 8 | 9 | com.apple.private.skip-library-validation 10 | 11 | run-unsigned-code 12 | 13 | get-task-allow 14 | 15 | task_for_pid-allow 16 | 17 | com.apple.security.app-sandbox 18 | 19 | com.apple.security.get-task-allow 20 | 21 | com.apple.security.cs.disable-library-validation 22 | 23 | com.apple.security.cs.allow-unsigned-executable-memory 24 | 25 | com.apple.security.cs.disable-executable-page-protection 26 | 27 | com.apple.security.cs.allow-relative-library-loads 28 | 29 | com.apple.private.cs.debugger 30 | 31 | dynamic-codesigning 32 | 33 | 34 | -------------------------------------------------------------------------------- /Example.c: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | // INCLUDES 4 | //------------------------------------------------------------------------------ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef __APPLE__ 13 | #include 14 | #include 15 | #include "SymbolResolve/Darwin/Macho.h" 16 | #else 17 | #include 18 | #include 19 | #include "SymbolResolve/Linux/Elf.h" 20 | #endif 21 | 22 | #include "utility/debug.h" 23 | #include "utility/error.h" 24 | #include "utility/utility.h" 25 | 26 | #include "Hook/InlineHook.h" 27 | 28 | #include "Memory/MemoryTracker.h" 29 | 30 | #ifndef DEBUG_MODE 31 | #ifdef BWSR_DEBUG 32 | #undef BWSR_DEBUG 33 | #endif 34 | 35 | #define BWSR_DEBUG( LEVEL, ARGS... ) fprintf( stderr, ##ARGS ); 36 | #endif 37 | 38 | //------------------------------------------------------------------------------ 39 | // HOOK FUNCTIONS AND HOOK TYPES 40 | //------------------------------------------------------------------------------ 41 | 42 | #ifdef __APPLE__ 43 | typedef int32_t 44 | ( *AudioUnitProcess_t ) 45 | ( 46 | AudioUnit inUnit, 47 | AudioUnitRenderActionFlags* __nullable ioActionFlags, 48 | const AudioTimeStamp* inTimeStamp, 49 | UInt32 inNumberFrames, 50 | AudioBufferList* ioData 51 | ); 52 | #endif 53 | 54 | 55 | int hcreat( const char * files, mode_t modes ) 56 | { 57 | BWSR_DEBUG( LOG_CRITICAL, 58 | "SUCCESS! Caught creat()!: '%s'\n", 59 | files ); 60 | __UNUSED( files, modes ) 61 | return -1; 62 | } 63 | 64 | int hprintf( const char* text, ... ) 65 | { 66 | BWSR_DEBUG( LOG_CRITICAL, 67 | "SUCCESS! Caught printf() with text: '%s'\n", 68 | text ); 69 | __UNUSED( text ) 70 | return -1; 71 | } 72 | 73 | #ifdef __APPLE__ 74 | int32_t hAudioUnitProcess 75 | ( 76 | AudioUnit inUnit, 77 | AudioUnitRenderActionFlags* __nullable ioActionFlags, 78 | const AudioTimeStamp* inTimeStamp, 79 | UInt32 inNumberFrames, 80 | AudioBufferList* ioData 81 | ) 82 | { 83 | BWSR_DEBUG( LOG_CRITICAL, "SUCCESS! Caught AudioUnitProcess()!\n" ); 84 | __UNUSED( inUnit, 85 | ioActionFlags, 86 | inTimeStamp, 87 | inNumberFrames, 88 | ioData ) 89 | return -1; 90 | } 91 | #endif 92 | 93 | //------------------------------------------------------------------------------ 94 | // CODESIGN CALLBACKS 95 | //------------------------------------------------------------------------------ 96 | 97 | void 98 | BeforePageWriteCallbackFn 99 | ( 100 | uintptr_t PageAddress 101 | ) 102 | { 103 | BWSR_DEBUG( LOG_CRITICAL, "PageAddress: %" PRIuPTR "\n", PageAddress ); 104 | __UNUSED( PageAddress ) 105 | // Uneeded for most people 106 | } 107 | 108 | void 109 | AfterPageWriteCallbackFn 110 | ( 111 | uintptr_t PageAddress 112 | ) 113 | { 114 | BWSR_DEBUG( LOG_ALERT, "PageAddress: %" PRIuPTR "\n", PageAddress ); 115 | __UNUSED( PageAddress ) 116 | // Rehash Code Page 117 | // Rehash CDHash 118 | // CodeDirectory stuff :) 119 | } 120 | 121 | //------------------------------------------------------------------------------ 122 | // EXAMPLES 123 | //------------------------------------------------------------------------------ 124 | 125 | static 126 | void 127 | EXAMPLE_hooking_creat 128 | ( 129 | void 130 | ) 131 | { 132 | BWSR_InlineHook( creat, hcreat, NULL, BeforePageWriteCallbackFn, AfterPageWriteCallbackFn ); 133 | BWSR_DEBUG( LOG_DEBUG, "Calling creat()\n" ); 134 | 135 | int fd = creat( "/var/mobile/creat_test_file1.txt", S_IRWXG | S_IRWXU | S_IRWXO ); 136 | 137 | if( 0 < fd ) 138 | { 139 | BWSR_DEBUG( LOG_DEBUG, "FAILURE! creat() call went through!!!\n" ); 140 | close( fd ); 141 | } 142 | 143 | BWSR_DEBUG( LOG_DEBUG, "Unhooking creat()\n" ); 144 | BWSR_DestroyHook( creat ); 145 | } 146 | 147 | static 148 | void 149 | EXAMPLE_hooking_printf 150 | ( 151 | void 152 | ) 153 | { 154 | void* oldprintf = NULL; 155 | 156 | BWSR_InlineHook( printf, hprintf, &oldprintf, NULL, NULL ); 157 | 158 | printf( "Testing printf of an integer: %d", 1 ); 159 | 160 | if( NULL != oldprintf ) 161 | { 162 | BWSR_DEBUG( LOG_CRITICAL, "Calling original printf(). Console should display!\n" ); 163 | 164 | if( EOF == ((__typeof(printf)*)oldprintf)( "Testing the original version of printf with integer: %d!\n", 1 ) ) 165 | { 166 | BWSR_DEBUG( LOG_CRITICAL, "FAILURE: Original printf() did not write any bytes to console!\n" ); 167 | } 168 | else { 169 | BWSR_DEBUG( LOG_CRITICAL, "SUCCESS: Original printf() worked!\n" ); 170 | } 171 | } 172 | else { 173 | BWSR_DEBUG( LOG_CRITICAL, "FAILURE: original printf() could not be called!\n" ); 174 | } 175 | } 176 | 177 | #if defined( __APPLE__ ) 178 | void 179 | EXAMPLE_hooking_AudioUnitProcess 180 | ( 181 | void 182 | ) 183 | { 184 | uintptr_t aup_address = 0; 185 | AudioUnit inUnit = NULL; 186 | AudioUnitRenderActionFlags* ioActionFlags = NULL; 187 | const AudioTimeStamp* inTimeStamp = NULL; 188 | UInt32 inNumberFrames = 0; 189 | AudioBufferList* ioData = NULL; 190 | 191 | BWSR_ResolveSymbol( "AudioUnitProcess", NULL, &aup_address ); 192 | BWSR_InlineHook( (void*)aup_address, hAudioUnitProcess, NULL, BeforePageWriteCallbackFn, AfterPageWriteCallbackFn ); 193 | 194 | AudioUnitProcess( inUnit, ioActionFlags, inTimeStamp, inNumberFrames, ioData ); 195 | } 196 | #else 197 | void 198 | EXAMPLE_linux_SymbolResolve 199 | ( 200 | void 201 | ) 202 | { 203 | uintptr_t open_address = 0; 204 | BWSR_ResolveSymbol( "open", NULL, &open_address ); 205 | 206 | BWSR_DEBUG( LOG_CRITICAL, "open address: %p\n", open ); 207 | BWSR_DEBUG( LOG_CRITICAL, "resolved address: 0x%lx\n", open_address ); 208 | } 209 | #endif 210 | 211 | 212 | int main() 213 | { 214 | 215 | #ifndef DEBUG_MODE 216 | fprintf( stderr, "Example was made without DEBUG printing. Output will be limited!\n" ); 217 | #endif 218 | 219 | EXAMPLE_hooking_creat(); 220 | 221 | EXAMPLE_hooking_printf(); 222 | 223 | #if defined( __APPLE__ ) 224 | 225 | EXAMPLE_hooking_AudioUnitProcess(); 226 | 227 | #else 228 | 229 | EXAMPLE_linux_SymbolResolve(); 230 | 231 | #endif 232 | 233 | BWSR_DEBUG( LOG_CRITICAL, "Cleaning up all hooks\n" ); 234 | 235 | // Clean up all hooks 236 | BWSR_DestroyAllHooks(); 237 | 238 | #if defined( DEBUG_MODE ) 239 | 240 | size_t leaks = MemoryTracker_CheckForMemoryLeaks(); 241 | BWSR_DEBUG( LOG_CRITICAL, 242 | "%zu memory leaks found!\n", 243 | leaks ); 244 | 245 | #endif 246 | } 247 | -------------------------------------------------------------------------------- /Hook/Assembler.c: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // INCLUDES 4 | // ----------------------------------------------------------------------------- 5 | 6 | #include "Hook/Assembler.h" 7 | #include "Memory/MemoryTracker.h" 8 | 9 | // ----------------------------------------------------------------------------- 10 | // DEFINITIONS 11 | // ----------------------------------------------------------------------------- 12 | 13 | // Destination Register - Register where the result of an operation is stored or where data is moved to. 14 | #define Rd( rd ) ( rd->RegisterId << kRdShift ) 15 | // Result Register - Load and store operations. 16 | #define Rt( rt ) ( rt->RegisterId << kRtShift ) 17 | // Source Register - Register from which data is read or used as an input for an operation. 18 | #define Rn( rn ) ( rn->RegisterId << kRnShift ) 19 | 20 | #define ARM64_TMP_REG_NDX_0 17 21 | 22 | #define OPERAND_IMMEDIATE( IMMEDIATE ) (operand_t) \ 23 | { \ 24 | .Immediate = IMMEDIATE, \ 25 | .Register = (register_data_t*) &InvalidRegister, \ 26 | .Shift = NO_SHIFT, \ 27 | .ShiftExtendImmediate = 0 \ 28 | } 29 | 30 | // ----------------------------------------------------------------------------- 31 | // GLOBALS 32 | // ----------------------------------------------------------------------------- 33 | 34 | static const register_data_t InvalidRegister = 35 | { 36 | .RegisterId = 0, 37 | .RegisterSize = 0, 38 | .RegisterType = kInvalid 39 | }; 40 | 41 | static const register_data_t TMP_REG_0 = 42 | { 43 | .RegisterId = ARM64_TMP_REG_NDX_0, 44 | .RegisterSize = 64, 45 | .RegisterType = kRegister_64 46 | }; 47 | 48 | // ----------------------------------------------------------------------------- 49 | // PROTOTYPES 50 | // ----------------------------------------------------------------------------- 51 | 52 | /** 53 | * \brief Writes the given `InputBuffer` into `Buffer`. 54 | * \param[in,out] Buffer Memory buffer recieving `InputBuffer` 55 | * \param[in] InputBuffer Input buffer should be an Instruction. 56 | * \param[in] InputBufferSize The size of the instruction being written. 57 | * \return `BWSR_STATUS` 58 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer` or `InputBuffer` is `NULL`. 59 | * \retval `ERROR_INVALID_ARGUMENT_VALUE` if `InputBufferSize` is not greater than `0`. 60 | * \retval `ERROR_MEM_ALLOC` If reallocation of `Buffer` fails. 61 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with `InputBuffer`. 62 | * \warning `Buffer` may be reallocated if it cannot contain `InputBuffer` 63 | */ 64 | static 65 | BWSR_STATUS 66 | INTERNAL_Assembler_WriteInstruction 67 | ( 68 | IN OUT memory_buffer_t* Buffer, 69 | IN uint8_t* InputBuffer, 70 | IN int InputBufferSize 71 | ); 72 | 73 | /** 74 | * \brief Writes the encoded instruction for LDR into the provided `Buffer` 75 | * \param[in,out] Buffer Buffer to emit instruction. 76 | * \param[in] Op LDR instruction. 77 | * \param[in] Register Load and store operations Register. 78 | * \param[in] Immediate Encoded Instruction. 79 | * \return `BWSR_STATUS` 80 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer` or `Result` is `NULL`. 81 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 82 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with `Immediate`. 83 | * \warning Through the call chain, `Buffer` may be reallocated. 84 | */ 85 | static 86 | BWSR_STATUS 87 | INTERNAL_Assembler_LoadRegisterLiteral 88 | ( 89 | IN OUT memory_buffer_t* Buffer, 90 | IN LoadRegLiteralOp Op, 91 | IN register_data_t* Register, 92 | IN int64_t Immediate 93 | ); 94 | 95 | /** 96 | * \brief `LDR` (Load Register) instruction is used to load data from memory 97 | * into a register. 98 | * This instruction is written into the provided `Buffer`. 99 | * \param[in,out] Buffer Buffer to emit instruction. 100 | * \param[in] Register Load and store instructions Register. 101 | * \param[in] Immediate Encoded Instruction. 102 | * \return `BWSR_STATUS` 103 | * \retval `ERROR_ARGUMENT_IS_NULL` If `Buffer` or `Register` is `NULL`. 104 | * \retval `ERROR_MEM_ALLOC` If the reallocation of `Buffer` fails. 105 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with `Immediate`. 106 | * \warning Through the call chain, `Buffer` may be reallocated. 107 | */ 108 | static 109 | BWSR_STATUS 110 | INTERNAL_Assembler_LDR 111 | ( 112 | IN OUT memory_buffer_t* Buffer, 113 | IN register_data_t* Register, 114 | IN int64_t Immediate 115 | ); 116 | 117 | /** 118 | * \brief `AddSubImmediate` refers to a specific type of instruction that allows 119 | * for conditional addition or subtraction of an immediate value to or from a register. 120 | * This instruction is written into the provided `Buffer`. 121 | * \param[in,out] Buffer Buffer to emit instruction. 122 | * \param[in] Destination Register where the result of an operation is stored or where data is moved to. 123 | * \param[in] Source Register from which data is read or used as an input for an operation. 124 | * \param[in] Operand Operand holding immediate value. 125 | * \param[in] Op `ADD` or `SUB` literal fixed immediate in `32` or `64` bit. 126 | * \return `BWSR_STATUS` 127 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer`, `Destination`, `Source`, or `Operand` is `NULL` 128 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 129 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded Instruction. 130 | * \warning Through the call chain, `Buffer` may be reallocated. 131 | */ 132 | static 133 | BWSR_STATUS 134 | INTERNAL_Assembler_AddSubImmediate 135 | ( 136 | IN OUT memory_buffer_t* Buffer, 137 | IN const register_data_t* Destination, 138 | IN const register_data_t* Source, 139 | IN const operand_t* Operand, 140 | IN AddSubImmediateOp Op 141 | ); 142 | 143 | /** 144 | * \brief `ADD` instructions are used to perform addition operations. 145 | * This `ADD` instruction is written into the provided `Buffer`. 146 | * \param[in,out] Buffer Buffer to emit instruction 147 | * \param[in] Destination Register where the result of an operation is stored or where data is moved to. 148 | * \param[in] Source Register from which data is read or used as an input for an operation. 149 | * \param[in] Immediate Encoded instruction 150 | * \return `BWSR_STATUS` 151 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer`, `Destination`, or `Source` is `NULL`. 152 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 153 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded Instruction. 154 | * \warning Through the call chain, `Buffer` may be reallocated. 155 | */ 156 | static 157 | BWSR_STATUS 158 | INTERNAL_Assembler_ADD 159 | ( 160 | IN OUT memory_buffer_t* Buffer, 161 | IN const register_data_t* Destination, 162 | IN const register_data_t* Source, 163 | IN int64_t Immediate 164 | ); 165 | 166 | /** 167 | * \brief Register operation size, 32 bits or 64 bits 168 | * \param[in] Register Register 169 | * \return `int32_t` 170 | * \retval `0` if register size is `32` bits. 171 | * \retval `INT32_MIN` if register size is `64` bits. 172 | */ 173 | static 174 | int32_t 175 | INTERNAL_Assembler_OpEncode_SF 176 | ( 177 | IN const register_data_t* Register 178 | ); 179 | 180 | /** 181 | * \brief `Move Wide` instruction allows for inserting a 16-bit immediate value 182 | * into a register at a specified bit position. This instruction is particularly 183 | * useful for constructing or modifying 64-bit values in `X` registers (64-bit) 184 | * or 32-bit values in `W` registers (32-bit). 185 | * This instruction is written into the provided `Buffer`. 186 | * \param[in,out] Buffer Buffer to emit instruction 187 | * \param[in] Register Where the result of an operation is stored or where data is moved to. 188 | * \param[in] Immediate Encoded instruction 189 | * \param[in] Shift Shift of the encoded instructions. Expected as a multiple of `16`. 190 | * \param[in] Op Move wide immediate fixed either `MOVZ` or `MOVK` 191 | * \return `BWSR_STATUS` 192 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer` or `Destination` is `NULL`. 193 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 194 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded instruction. 195 | * \warning Through the call chain, `Buffer` may be reallocated. 196 | */ 197 | static 198 | BWSR_STATUS 199 | INTERNAL_Assembler_MoveWide 200 | ( 201 | IN OUT memory_buffer_t* Buffer, 202 | IN register_data_t* Register, 203 | IN uint64_t Immediate, 204 | IN int Shift, 205 | IN MoveWideImmediateOp Op 206 | ); 207 | 208 | /** 209 | * \brief Resolves and updates references to instructions in `Buffer` based on `RelocationData`. 210 | * \param[in] RelocationData X 211 | * \param[in,out] Buffer B 212 | * \return `void` 213 | */ 214 | static 215 | void 216 | INTERNAL_Assembler_LinkConfusedInstructions 217 | ( 218 | IN relocation_data_t* RelocationData, 219 | IN OUT memory_buffer_t* Buffer 220 | ); 221 | 222 | /** 223 | * \brief brief 224 | * \param[in] Assembler A 225 | * \param[in] RelocationData R 226 | * \return `void` 227 | */ 228 | static 229 | void 230 | INTERNAL_Assembler_BindRelocationData 231 | ( 232 | IN assembler_t* Assembler, 233 | IN relocation_data_t* RelocationData 234 | ); 235 | 236 | /** 237 | * \brief brief 238 | * \param[in,out] RelocationData R 239 | * \param[in] LinkType L 240 | * \param[in] PCOffset P 241 | * \return `BWSR_STATUS` 242 | * \retval `ERROR_ARGUMENT_IS_NULL` if `RelocationData` is `NULL`. 243 | * \retval `ERROR_MEM_ALLOC` if allocation of reference instruction fails. 244 | * \retval `ERROR_SUCCESS` if a reference instruction was added and updated. 245 | */ 246 | static 247 | BWSR_STATUS 248 | INTERNAL_Assembler_LinkToOffset 249 | ( 250 | IN OUT relocation_data_t* RelocationData, 251 | IN const int LinkType, 252 | IN const size_t PCOffset 253 | ); 254 | 255 | // ----------------------------------------------------------------------------- 256 | // IMPLEMENTATION 257 | // ----------------------------------------------------------------------------- 258 | 259 | static 260 | BWSR_STATUS 261 | INTERNAL_Assembler_WriteInstruction 262 | ( 263 | IN OUT memory_buffer_t* Buffer, 264 | IN uint8_t* InputBuffer, 265 | IN int InputBufferSize 266 | ) 267 | { 268 | BWSR_STATUS retVal = ERROR_SUCCESS; 269 | uint32_t capacity = 0; 270 | 271 | __NOT_NULL( Buffer, InputBuffer ); 272 | __GREATER_THAN_0( InputBufferSize ); 273 | 274 | if( ( Buffer->BufferSize + InputBufferSize ) > Buffer->BufferCapacity ) 275 | { 276 | capacity = Buffer->BufferCapacity * 2; 277 | 278 | while( capacity < ( Buffer->BufferSize + InputBufferSize ) ) 279 | { 280 | capacity *= 2; 281 | } // while() 282 | 283 | if( NULL == ( Buffer->Buffer = (uint8_t*) BwsrRealloc( Buffer->Buffer, capacity ) ) ) 284 | { 285 | BWSR_DEBUG( LOG_ERROR, "BwsrRealloc() Failed\n" ); 286 | Buffer->BufferSize = 0; 287 | retVal = ERROR_MEM_ALLOC; 288 | } 289 | else { 290 | Buffer->BufferCapacity = capacity; 291 | } // BwsrRealloc() 292 | } // Buffer->BufferCapacity 293 | 294 | if( ERROR_SUCCESS == retVal ) 295 | { 296 | memcpy( ( Buffer->Buffer + Buffer->BufferSize ), 297 | InputBuffer, 298 | InputBufferSize ); 299 | 300 | Buffer->BufferSize += InputBufferSize; 301 | } // ERROR_SUCCESS == retVal 302 | 303 | return retVal; 304 | } 305 | 306 | static 307 | BWSR_STATUS 308 | INTERNAL_Assembler_LoadRegisterLiteral 309 | ( 310 | IN OUT memory_buffer_t* Buffer, 311 | IN LoadRegLiteralOp Op, 312 | IN register_data_t* Register, 313 | IN int64_t Immediate 314 | ) 315 | { 316 | BWSR_STATUS retVal = ERROR_FAILURE; 317 | uint32_t encoding = 0; 318 | 319 | __NOT_NULL( Buffer, Register ) 320 | 321 | encoding = ( Op 322 | | BIT_SHIFT( ( Immediate >> 2 ), 26, 5 ) 323 | | Rt( Register ) ); 324 | 325 | retVal = Assembler_Write32BitInstruction( Buffer, encoding ); 326 | 327 | return retVal; 328 | } 329 | 330 | static 331 | BWSR_STATUS 332 | INTERNAL_Assembler_LDR 333 | ( 334 | IN OUT memory_buffer_t* Buffer, 335 | IN register_data_t* Register, 336 | IN int64_t Immediate 337 | ) 338 | { 339 | BWSR_STATUS retVal = ERROR_FAILURE; 340 | LoadRegLiteralOp op = LiteralLoadRegisterFixed; 341 | 342 | __NOT_NULL( Buffer, Register ) 343 | 344 | switch( Register->RegisterType ) 345 | { 346 | case kRegister_32: 347 | { 348 | op = LDR_w_literal; 349 | break; 350 | } 351 | 352 | case kRegister_X: 353 | { 354 | op = LDR_x_literal; 355 | break; 356 | } 357 | 358 | case kSIMD_FP_Register_S: 359 | { 360 | op = LDR_s_literal; 361 | break; 362 | } 363 | 364 | case kSIMD_FP_Register_D: 365 | { 366 | op = LDR_d_literal; 367 | break; 368 | } 369 | 370 | case kSIMD_FP_Register_Q: 371 | { 372 | op = LDR_q_literal; 373 | break; 374 | } 375 | 376 | default: 377 | { 378 | BWSR_DEBUG( LOG_WARNING, "This code should not be reachable!\n" ); 379 | break; 380 | } 381 | } 382 | 383 | retVal = INTERNAL_Assembler_LoadRegisterLiteral( Buffer, 384 | op, 385 | Register, 386 | Immediate ); 387 | 388 | return retVal; 389 | } 390 | 391 | static 392 | BWSR_STATUS 393 | INTERNAL_Assembler_AddSubImmediate 394 | ( 395 | IN OUT memory_buffer_t* Buffer, 396 | IN const register_data_t* Destination, 397 | IN const register_data_t* Source, 398 | IN const operand_t* Operand, 399 | IN AddSubImmediateOp Op 400 | ) 401 | { 402 | BWSR_STATUS retVal = ERROR_FAILURE; 403 | uint32_t value = 0; 404 | 405 | __NOT_NULL( Buffer, 406 | Destination, 407 | Source, 408 | Operand ) 409 | 410 | if( 0 != Operand->Register->RegisterId ) 411 | { 412 | retVal = ERROR_SUCCESS; 413 | } 414 | else { 415 | value = ( Op 416 | | Rd( Destination ) 417 | | Rn( Source ) 418 | | BIT_SHIFT( Operand->Immediate, 12, 10 ) ); 419 | 420 | retVal = Assembler_Write32BitInstruction( Buffer, value ); 421 | } 422 | 423 | return retVal; 424 | } 425 | 426 | static 427 | BWSR_STATUS 428 | INTERNAL_Assembler_ADD 429 | ( 430 | IN OUT memory_buffer_t* Buffer, 431 | IN const register_data_t* Destination, 432 | IN const register_data_t* Source, 433 | IN int64_t Immediate 434 | ) 435 | { 436 | BWSR_STATUS retVal = ERROR_FAILURE; 437 | AddSubImmediateOp op = ADD_w_imm; 438 | 439 | __NOT_NULL( Buffer, 440 | Destination, 441 | Source ) 442 | 443 | if( ( 64 == Destination->RegisterSize ) && 444 | ( 64 == Source->RegisterSize ) ) 445 | { 446 | op = ADD_x_imm; 447 | } 448 | 449 | retVal = INTERNAL_Assembler_AddSubImmediate( Buffer, 450 | Destination, 451 | Source, 452 | &OPERAND_IMMEDIATE( Immediate ), 453 | op ); 454 | 455 | return retVal; 456 | } 457 | 458 | static 459 | int32_t 460 | INTERNAL_Assembler_OpEncode_SF 461 | ( 462 | IN const register_data_t* Register 463 | ) 464 | { 465 | int32_t retVal = 0; 466 | 467 | __NOT_NULL_RETURN_0( Register ) 468 | 469 | if( 64 == Register->RegisterSize ) 470 | { 471 | retVal = INT32_MIN; 472 | } 473 | 474 | return retVal; 475 | } 476 | 477 | static 478 | BWSR_STATUS 479 | INTERNAL_Assembler_MoveWide 480 | ( 481 | IN OUT memory_buffer_t* Buffer, 482 | IN register_data_t* Register, 483 | IN uint64_t Immediate, 484 | IN int Shift, 485 | IN MoveWideImmediateOp Op 486 | ) 487 | { 488 | BWSR_STATUS retVal = ERROR_FAILURE; 489 | uint32_t value = 0; 490 | 491 | __NOT_NULL( Buffer, Register ) 492 | 493 | if( 0 < Shift ) 494 | { 495 | Shift /= 16; 496 | } 497 | else { 498 | Shift = 0; 499 | } 500 | 501 | value = ( MoveWideImmediateFixed 502 | | Op 503 | | INTERNAL_Assembler_OpEncode_SF( Register ) 504 | | BIT_SHIFT( Shift, 2, 21 ) 505 | | BIT_SHIFT( Immediate, 16, 5 ) 506 | | Rd( Register ) ); 507 | 508 | retVal = Assembler_Write32BitInstruction( Buffer, value ); 509 | 510 | return retVal; 511 | } 512 | 513 | static 514 | void 515 | INTERNAL_Assembler_LinkConfusedInstructions 516 | ( 517 | IN relocation_data_t* RelocationData, 518 | IN OUT memory_buffer_t* Buffer 519 | ) 520 | { 521 | int64_t fixupOffset = 0; 522 | uint32_t instruction = 0; 523 | uint32_t newInstruction = 0; 524 | size_t i = 0; 525 | 526 | __NOT_NULL_RETURN_VOID( RelocationData, Buffer ) 527 | 528 | for( i = 0; i < RelocationData->ReferenceInstructionCount; ++i ) 529 | { 530 | fixupOffset = RelocationData->PcOffset - RelocationData->ReferenceInstructions[ i ].Offset; 531 | instruction = *(int32_t*)( Buffer->Buffer + RelocationData->ReferenceInstructions[ i ].Offset ); 532 | newInstruction = 0; 533 | 534 | if( kLabelImm19 == RelocationData->ReferenceInstructions[ i ].LinkType ) 535 | { 536 | SET_BITS( instruction, 537 | 5, 538 | 23, 539 | GET_BITS( ( fixupOffset >> 2 ), 0, 18 ) ); 540 | 541 | newInstruction = instruction; 542 | } 543 | 544 | *(int32_t*)( Buffer->Buffer + RelocationData->ReferenceInstructions[ i ].Offset ) = newInstruction; 545 | } // for() 546 | } 547 | 548 | static 549 | void 550 | INTERNAL_Assembler_BindRelocationData 551 | ( 552 | IN assembler_t* Assembler, 553 | IN relocation_data_t* RelocationData 554 | ) 555 | { 556 | __NOT_NULL_RETURN_VOID( Assembler, RelocationData ); 557 | 558 | RelocationData->PcOffset = Assembler->Buffer.BufferSize; 559 | 560 | if( 0 != RelocationData->ReferenceInstructionCount ) 561 | { 562 | INTERNAL_Assembler_LinkConfusedInstructions( RelocationData, &Assembler->Buffer ); 563 | } 564 | } 565 | 566 | static 567 | BWSR_STATUS 568 | INTERNAL_Assembler_LinkToOffset 569 | ( 570 | IN OUT relocation_data_t* RelocationData, 571 | IN const int LinkType, 572 | IN const size_t PCOffset 573 | ) 574 | { 575 | BWSR_STATUS retVal = ERROR_FAILURE; 576 | size_t refSize = 0; 577 | 578 | __NOT_NULL( RelocationData ) 579 | 580 | RelocationData->ReferenceInstructionCount++; 581 | refSize = RelocationData->ReferenceInstructionCount * sizeof( reference_instruct_t ); 582 | 583 | if( NULL == RelocationData->ReferenceInstructions ) 584 | { 585 | RelocationData->ReferenceInstructions = (reference_instruct_t*) BwsrMalloc( refSize ); 586 | } 587 | else { 588 | RelocationData->ReferenceInstructions = (reference_instruct_t*) BwsrRealloc( RelocationData->ReferenceInstructions, refSize ); 589 | } // RelocationData->ReferenceInstructions 590 | 591 | if( NULL == RelocationData->ReferenceInstructions ) 592 | { 593 | BWSR_DEBUG( LOG_ERROR, "BwsrMalloc() Failed\n" ); 594 | RelocationData->ReferenceInstructionCount = 0; 595 | retVal = ERROR_MEM_ALLOC; 596 | } 597 | else { 598 | RelocationData->ReferenceInstructions[ RelocationData->ReferenceInstructionCount - 1 ].LinkType = LinkType; 599 | RelocationData->ReferenceInstructions[ RelocationData->ReferenceInstructionCount - 1 ].Offset = PCOffset; 600 | retVal = ERROR_SUCCESS; 601 | } // RelocationData->ReferenceInstructions 602 | 603 | return retVal; 604 | } 605 | 606 | BWSR_STATUS 607 | Assembler_Initialize 608 | ( 609 | IN assembler_t* Assembler, 610 | IN uintptr_t FixedAddress 611 | ) 612 | { 613 | BWSR_STATUS retVal = ERROR_FAILURE; 614 | 615 | __NOT_NULL( Assembler ) 616 | 617 | if( NULL == ( Assembler->Buffer.Buffer = (uint8_t*) BwsrMalloc( 64 ) ) ) 618 | { 619 | BWSR_DEBUG( LOG_ERROR, "BwsrMalloc() Failed\n" ); 620 | retVal = ERROR_MEM_ALLOC; 621 | } 622 | else { 623 | Assembler->FixedAddress = FixedAddress; 624 | Assembler->Buffer.BufferSize = 0; 625 | Assembler->Buffer.BufferCapacity = 64; 626 | Assembler->RelocationData = NULL; 627 | Assembler->RelocationDataSize = 0; 628 | Assembler->RelocationDataCapacity = 0; 629 | 630 | retVal = ERROR_SUCCESS; 631 | } // BwsrMalloc() 632 | 633 | return retVal; 634 | } 635 | 636 | BWSR_STATUS 637 | Assembler_CreateRelocationData 638 | ( 639 | IN OUT relocation_data_t** Relocation, 640 | IN assembler_t* Assembler, 641 | IN uint64_t Data 642 | ) 643 | { 644 | BWSR_STATUS retVal = ERROR_FAILURE; 645 | relocation_data_t** relocationData = NULL; 646 | size_t capacity = 0; 647 | size_t refSize = 0; 648 | 649 | __NOT_NULL( Relocation, Assembler ) 650 | __GREATER_THAN_0( Data ) 651 | 652 | if( NULL == ( *Relocation = (relocation_data_t*) BwsrMalloc( sizeof( relocation_data_t ) ) ) ) 653 | { 654 | BWSR_DEBUG( LOG_ERROR, "BwsrMalloc() Failed\n" ); 655 | retVal = ERROR_MEM_ALLOC; 656 | } 657 | else { 658 | memcpy( ( *Relocation )->Data, 659 | &Data, 660 | sizeof( uint64_t ) ); 661 | 662 | if( Assembler->RelocationDataSize >= Assembler->RelocationDataCapacity ) 663 | { 664 | capacity = ( ( Assembler->RelocationDataCapacity == 0 ) 665 | ? 1 666 | : ( Assembler->RelocationDataCapacity * 2 ) ); 667 | refSize = ( capacity * sizeof( relocation_data_t* ) ); 668 | 669 | if( NULL == Assembler->RelocationData ) 670 | { 671 | relocationData = (relocation_data_t**) BwsrMalloc( refSize ); 672 | } 673 | else { 674 | relocationData = (relocation_data_t**) BwsrRealloc( Assembler->RelocationData, refSize ); 675 | } // NULL == Assembler->RelocationData 676 | 677 | if( NULL == relocationData ) 678 | { 679 | BwsrFree( *Relocation ); 680 | capacity = 0; 681 | retVal = ERROR_MEM_ALLOC; 682 | } 683 | else { 684 | retVal = ERROR_SUCCESS; 685 | } // NULL == relocationData 686 | 687 | Assembler->RelocationData = relocationData; 688 | Assembler->RelocationDataCapacity = capacity; 689 | } // Assembler->RelocationDataSize 690 | 691 | if( ERROR_SUCCESS == retVal ) 692 | { 693 | ( *Relocation )->DataSize = (uint8_t) sizeof( uint64_t ); 694 | ( *Relocation )->ReferenceInstructionCount = 0; 695 | ( *Relocation )->PcOffset = 0; 696 | ( *Relocation )->ReferenceInstructions = NULL; 697 | 698 | Assembler->RelocationData[ Assembler->RelocationDataSize++ ] = *Relocation; 699 | } 700 | } // BwsrMalloc() 701 | 702 | return retVal; 703 | } 704 | 705 | BWSR_STATUS 706 | Assembler_WriteRelocationDataToPageBuffer 707 | ( 708 | IN assembler_t* Assembler 709 | ) 710 | { 711 | BWSR_STATUS retVal = ERROR_SUCCESS; 712 | size_t i = 0; 713 | 714 | __NOT_NULL( Assembler ) 715 | 716 | for( i = 0; ( i < Assembler->RelocationDataSize ) && ( ERROR_SUCCESS == retVal ); i++ ) 717 | { 718 | INTERNAL_Assembler_BindRelocationData( Assembler, Assembler->RelocationData[ i ] ); 719 | 720 | retVal = INTERNAL_Assembler_WriteInstruction( &Assembler->Buffer, 721 | Assembler->RelocationData[ i ]->Data, 722 | Assembler->RelocationData[ i ]->DataSize ); 723 | } // for() 724 | 725 | return retVal; 726 | } 727 | 728 | BWSR_STATUS 729 | Assembler_Write32BitInstruction 730 | ( 731 | IN OUT memory_buffer_t* Buffer, 732 | IN uint32_t Value 733 | ) 734 | { 735 | BWSR_STATUS retVal = ERROR_FAILURE; 736 | 737 | __NOT_NULL( Buffer ) 738 | 739 | retVal = INTERNAL_Assembler_WriteInstruction( Buffer, 740 | (uint8_t*) &Value, 741 | sizeof( uint32_t ) ); 742 | 743 | return retVal; 744 | } 745 | 746 | 747 | BWSR_STATUS 748 | Assembler_LoadStore 749 | ( 750 | IN OUT memory_buffer_t* Buffer, 751 | IN LoadStoreOp Op, 752 | IN const register_data_t* Register, 753 | IN const memory_operand_t* Addr 754 | ) 755 | { 756 | BWSR_STATUS retVal = ERROR_FAILURE; 757 | int scale = 0; 758 | uint32_t value = 0; 759 | 760 | __NOT_NULL( Buffer, 761 | Register, 762 | Addr ) 763 | 764 | if( AddrModeOffset != Addr->AddressMode ) 765 | { 766 | retVal = ERROR_SUCCESS; 767 | } 768 | else { 769 | 770 | if( LoadStoreUnsignedOffsetFixed == ( Op & LoadStoreUnsignedOffsetFixed ) ) 771 | { 772 | scale = GET_BITS( Op, 30, 31 ); 773 | } 774 | 775 | value = ( LoadStoreUnsignedOffsetFixed 776 | | Op 777 | | BIT_SHIFT( (int64_t)( Addr->Offset >> scale ), 12, 10 ) 778 | | ( Addr->Base.RegisterId << kRnShift ) 779 | | Rt( Register ) ); 780 | retVal = Assembler_Write32BitInstruction( Buffer, value ); 781 | } // AddrModeOffset != Addr->AddressMode 782 | 783 | return retVal; 784 | } 785 | 786 | BWSR_STATUS 787 | Assembler_ADRP_ADD 788 | ( 789 | IN OUT memory_buffer_t* Buffer, 790 | IN register_data_t* Register, 791 | IN uint64_t From, 792 | IN uint64_t To 793 | ) 794 | { 795 | BWSR_STATUS retVal = ERROR_FAILURE; 796 | uint64_t from_PAGE = ALIGN_FLOOR( From, 0x1000 ); 797 | uint64_t to_PAGE = ALIGN_FLOOR( To, 0x1000 ); 798 | uint64_t to_PAGEOFF = (uint64_t) ( To % 0x1000 ); 799 | uint32_t value = 0; 800 | 801 | __NOT_NULL( Buffer, Register ) 802 | __GREATER_THAN_0( From, To ) 803 | 804 | value = ( ADRP 805 | | Rd( Register ) 806 | | BIT_SHIFT( GET_BITS( ( to_PAGE - from_PAGE ) >> 12, 0, 1 ), 2, 29 ) 807 | | BIT_SHIFT( GET_BITS( ( to_PAGE - from_PAGE ) >> 12, 2, 20 ), 19, 5 ) ); 808 | 809 | if( ERROR_SUCCESS != ( retVal = Assembler_Write32BitInstruction( Buffer, value ) ) ) 810 | { 811 | BWSR_DEBUG( LOG_ERROR, "Assemble_adrp() Failed\n" ); 812 | } 813 | else { 814 | retVal = INTERNAL_Assembler_ADD( Buffer, 815 | Register, 816 | Register, 817 | to_PAGEOFF ); 818 | } // Assemble_adrp() 819 | 820 | return retVal; 821 | } 822 | 823 | BWSR_STATUS 824 | Assembler_MOV 825 | ( 826 | IN OUT memory_buffer_t* Buffer, 827 | IN register_data_t* Register, 828 | IN uint64_t Immediate 829 | ) 830 | { 831 | BWSR_STATUS retVal = ERROR_FAILURE; 832 | 833 | const uint32_t w0 = (uint32_t)( Immediate & 0xffffffff ); 834 | const uint32_t w1 = (uint32_t)( Immediate >> 32 ); 835 | const uint16_t h0 = (uint16_t)( w0 & 0xffff ); 836 | const uint16_t h1 = (uint16_t)( w0 >> 16 ); 837 | const uint16_t h2 = (uint16_t)( w1 & 0xffff ); 838 | const uint16_t h3 = (uint16_t)( w1 >> 16 ); 839 | 840 | __NOT_NULL( Buffer, Register ) 841 | __GREATER_THAN_0( Immediate ) 842 | 843 | if( ERROR_SUCCESS != ( retVal = INTERNAL_Assembler_MoveWide( Buffer, 844 | Register, 845 | h0, 846 | 0, 847 | MOVZ ) ) ) 848 | { 849 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_Assembler_MoveWide() Failed\n" ); 850 | } 851 | else { 852 | if( ERROR_SUCCESS != ( retVal = INTERNAL_Assembler_MoveWide( Buffer, 853 | Register, 854 | h1, 855 | 16, 856 | MOVK ) ) ) 857 | { 858 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_Assembler_MoveWide() Failed\n" ); 859 | } 860 | else { 861 | if( ERROR_SUCCESS != ( retVal = INTERNAL_Assembler_MoveWide( Buffer, 862 | Register, 863 | h2, 864 | 32, 865 | MOVK ) ) ) 866 | { 867 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_Assembler_MoveWide() Failed\n" ); 868 | } 869 | else { 870 | retVal = INTERNAL_Assembler_MoveWide( Buffer, 871 | Register, 872 | h3, 873 | 48, 874 | MOVK ); 875 | } // Assemble_movk() 876 | } // Assemble_movk() 877 | } // Assemble_movz() 878 | 879 | return retVal; 880 | } 881 | 882 | BWSR_STATUS 883 | Assembler_WriteInstruction_LDR 884 | ( 885 | IN OUT memory_buffer_t* Buffer, 886 | IN register_data_t* Register, 887 | IN relocation_data_t* RelocationData 888 | ) 889 | { 890 | BWSR_STATUS retVal = ERROR_FAILURE; 891 | 892 | __NOT_NULL( Buffer, 893 | Register, 894 | RelocationData ) 895 | 896 | if( ERROR_SUCCESS != ( retVal = INTERNAL_Assembler_LinkToOffset( RelocationData, 897 | kLabelImm19, 898 | Buffer->BufferSize ) ) ) 899 | { 900 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_Assembler_LinkToOffset() Failed\n" ); 901 | } 902 | else { 903 | retVal = INTERNAL_Assembler_LDR( Buffer, 904 | Register, 905 | 0 ); 906 | } // INTERNAL_Assembler_LinkToOffset() 907 | 908 | return retVal; 909 | } 910 | 911 | BWSR_STATUS 912 | Assembler_LiteralLdrBranch 913 | ( 914 | IN OUT assembler_t* Assembler, 915 | IN uint64_t Address 916 | ) 917 | { 918 | BWSR_STATUS retVal = ERROR_FAILURE; 919 | relocation_data_t* relocationData = NULL; 920 | uint32_t value = 0; 921 | 922 | __NOT_NULL( Assembler ) 923 | __GREATER_THAN_0( Address ) 924 | 925 | if( ERROR_SUCCESS != ( retVal = Assembler_CreateRelocationData( &relocationData, 926 | Assembler, 927 | Address ) ) ) 928 | { 929 | BWSR_DEBUG( LOG_ERROR, "Assembler_CreateRelocationData() Failed\n" ); 930 | } 931 | else { 932 | if( ERROR_SUCCESS != ( retVal = Assembler_WriteInstruction_LDR( &Assembler->Buffer, 933 | (register_data_t*) &TMP_REG_0, 934 | relocationData ) ) ) 935 | { 936 | BWSR_DEBUG( LOG_ERROR, "Assembler_WriteInstruction_LDR() Failed\n" ); 937 | } 938 | else { 939 | value = ( BR | ( ARM64_TMP_REG_NDX_0 << kRnShift ) ); 940 | retVal = Assembler_Write32BitInstruction( &Assembler->Buffer, value ); 941 | } // Assembler_WriteInstruction_LDR() 942 | } // Assembler_CreateRelocationData() 943 | 944 | if( ERROR_SUCCESS != retVal ) 945 | { 946 | if( NULL != relocationData ) 947 | { 948 | BwsrFree( relocationData ); 949 | } 950 | } // ERROR_SUCCESS != retVal 951 | 952 | return retVal; 953 | } 954 | 955 | BWSR_STATUS 956 | Assembler_Release 957 | ( 958 | IN OUT assembler_t* Assembler 959 | ) 960 | { 961 | BWSR_STATUS retVal = ERROR_FAILURE; 962 | 963 | __NOT_NULL( Assembler ) 964 | 965 | if( Assembler->RelocationData ) 966 | { 967 | while( Assembler->RelocationDataSize-- ) 968 | { 969 | BwsrFree( Assembler->RelocationData[ Assembler->RelocationDataSize ]->ReferenceInstructions ); 970 | BwsrFree( Assembler->RelocationData[ Assembler->RelocationDataSize ] ); 971 | } // while() 972 | 973 | BwsrFree( Assembler->RelocationData ); 974 | Assembler->RelocationData = NULL; 975 | } // Assembler->RelocationData 976 | 977 | if( Assembler->Buffer.Buffer ) 978 | { 979 | BwsrFree( Assembler->Buffer.Buffer ); 980 | Assembler->Buffer.Buffer = NULL; 981 | } // Assembler->Buffer.Buffer 982 | 983 | if( Assembler->FixedMemoryRange ) 984 | { 985 | BwsrFree( (void*)Assembler->FixedMemoryRange ); 986 | Assembler->FixedMemoryRange = 0; 987 | } // Assembler->FixedMemoryRange 988 | 989 | retVal = ERROR_SUCCESS; 990 | 991 | return retVal; 992 | } -------------------------------------------------------------------------------- /Hook/Assembler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __ASSEMBLER_H__ 3 | #define __ASSEMBLER_H__ 4 | 5 | // ----------------------------------------------------------------------------- 6 | // INCLUDES 7 | // ----------------------------------------------------------------------------- 8 | 9 | #include "utility/debug.h" 10 | #include "utility/error.h" 11 | #include "utility/utility.h" 12 | 13 | #include 14 | #include 15 | 16 | // ----------------------------------------------------------------------------- 17 | // ENUMS 18 | // ----------------------------------------------------------------------------- 19 | 20 | typedef enum InstructionFields { 21 | kRdShift = 0, 22 | kRnShift = 5, 23 | kRtShift = 0, 24 | } InstructionFields; 25 | 26 | typedef enum UnconditionalBranchToRegisterOp { 27 | UnconditionalBranchToRegisterFixed = 0xD6000000, 28 | BR = UnconditionalBranchToRegisterFixed | 0x001F0000, 29 | BLR = UnconditionalBranchToRegisterFixed | 0x003F0000, 30 | } UnconditionalBranchToRegisterOp; 31 | 32 | typedef enum RegisterType { 33 | kRegister_32, 34 | kRegister_W = kRegister_32, 35 | kRegister_64, 36 | kRegister_X = kRegister_64, 37 | kRegister, 38 | 39 | kVRegister, 40 | kSIMD_FP_Register_8, 41 | kSIMD_FP_Register_B = kSIMD_FP_Register_8, 42 | kSIMD_FP_Register_16, 43 | kSIMD_FP_Register_H = kSIMD_FP_Register_16, 44 | kSIMD_FP_Register_32, 45 | kSIMD_FP_Register_S = kSIMD_FP_Register_32, 46 | kSIMD_FP_Register_64, 47 | kSIMD_FP_Register_D = kSIMD_FP_Register_64, 48 | kSIMD_FP_Register_128, 49 | kSIMD_FP_Register_Q = kSIMD_FP_Register_128, 50 | 51 | kInvalid 52 | } RegisterType; 53 | 54 | typedef enum AddSubImmediateOp { 55 | AddSubImmediateFixed = 0x11000000, 56 | ADD_w_imm = AddSubImmediateFixed | ( 0b00 << 31 ) | ( 0b00 << 30 ), 57 | SUB_w_imm = AddSubImmediateFixed | ( 0b00 << 31 ) | ( 0b01 << 30 ), 58 | ADD_x_imm = AddSubImmediateFixed | ( 0b01 << 31 ) | ( 0b00 << 30 ), 59 | SUB_x_imm = AddSubImmediateFixed | ( 0b01 << 31 ) | ( 0b01 << 30 ), 60 | } AddSubImmediateOp; 61 | 62 | typedef enum LoadRegLiteralOp { 63 | LiteralLoadRegisterFixed = 0x18000000, 64 | LiteralLoadRegisterFixedMask = 0x3B000000, 65 | LDR_w_literal = LiteralLoadRegisterFixed | ( 0b00 << 30 ) | ( 0b00 << 26 ), 66 | LDR_x_literal = LiteralLoadRegisterFixed | ( 0b01 << 30 ) | ( 0b00 << 26 ), 67 | LDR_s_literal = LiteralLoadRegisterFixed | ( 0b00 << 30 ) | ( 0b01 << 26 ), 68 | LDR_d_literal = LiteralLoadRegisterFixed | ( 0b01 << 30 ) | ( 0b01 << 26 ), 69 | LDR_q_literal = LiteralLoadRegisterFixed | ( 0b10 << 30 ) | ( 0b01 << 26 ), 70 | } LoadRegLiteralOp; 71 | 72 | typedef enum Shift { 73 | NO_SHIFT = -1, 74 | LSL = 0x0, 75 | LSR = 0x1, 76 | ASR = 0x2, 77 | ROR = 0x3, 78 | MSL = 0x4 79 | } Shift; 80 | 81 | typedef enum MoveWideImmediateOp { 82 | MoveWideImmediateFixed = 0x12800000, 83 | MOVZ = 0x40000000, 84 | MOVK = 0x60000000, 85 | } MoveWideImmediateOp; 86 | 87 | // Load/store 88 | typedef enum LoadStoreOp { 89 | STR_x = ( 0b11 << 30 ) | ( 0b00 << 22 ), 90 | LDR_x = ( 0b11 << 30 ) | ( 0b01 << 22 ), 91 | } LoadStoreOp; 92 | 93 | typedef enum AddrMode { 94 | AddrModeOffset, 95 | AddrModePreIndex, 96 | AddrModePostIndex 97 | } AddrMode; 98 | 99 | typedef enum LoadStoreUnsignedOffset { 100 | LoadStoreUnsignedOffsetFixed = 0x39000000, 101 | } LoadStoreUnsignedOffset; 102 | 103 | typedef enum PCRelAddressingOp { 104 | PCRelAddressingFixed = 0x10000000, 105 | PCRelAddressingFixedMask = 0x1F000000, 106 | PCRelAddressingMask = 0x9F000000, 107 | ADR = PCRelAddressingFixed | 0x00000000, 108 | ADRP = PCRelAddressingFixed | 0x80000000, 109 | } PCRelAddressingOp; 110 | 111 | typedef enum ReferenceLinkType { 112 | kLabelImm19 113 | } ReferenceLinkType; 114 | 115 | // ----------------------------------------------------------------------------- 116 | // STRUCTURES 117 | // ----------------------------------------------------------------------------- 118 | 119 | typedef struct memory_buffer_t { 120 | uint8_t* Buffer; 121 | uint32_t BufferSize; 122 | uint32_t BufferCapacity; 123 | } memory_buffer_t; 124 | 125 | typedef struct register_data_t { 126 | int RegisterId; 127 | int RegisterSize; 128 | RegisterType RegisterType; 129 | } register_data_t; 130 | 131 | typedef struct reference_instruct_t { 132 | int LinkType; 133 | size_t Offset; 134 | } reference_instruct_t; 135 | 136 | typedef struct relocation_data_t { 137 | size_t ReferenceInstructionCount; 138 | reference_instruct_t* ReferenceInstructions; 139 | uintptr_t PcOffset; 140 | uint8_t Data[ 8 ]; 141 | uint8_t DataSize; 142 | } relocation_data_t; 143 | 144 | typedef struct operand_t { 145 | int64_t Immediate; 146 | register_data_t* Register; 147 | Shift Shift; 148 | int32_t ShiftExtendImmediate; 149 | } operand_t; 150 | 151 | typedef struct assembler_t { 152 | uintptr_t FixedAddress; 153 | uintptr_t FixedMemoryRange; 154 | memory_buffer_t Buffer; 155 | relocation_data_t** RelocationData; 156 | size_t RelocationDataSize; 157 | size_t RelocationDataCapacity; 158 | } assembler_t; 159 | 160 | typedef struct memory_operand_t { 161 | register_data_t Base; 162 | int64_t Offset; 163 | AddrMode AddressMode; 164 | } memory_operand_t; 165 | 166 | // ----------------------------------------------------------------------------- 167 | // EXPORTED FUNCTIONS 168 | // ----------------------------------------------------------------------------- 169 | 170 | /** 171 | * \brief Initializes an Assembler and allocates it it's buffer. 172 | * \param[in] Assembler A 173 | * \param[in] FixedAddress Start of the memory range. 174 | * \return `BWSR_STATUS` 175 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Assembler` is `NULL`. 176 | * \retval `ERROR_MEM_ALLOC` if allocation of the `Assembler`'s buffer fails. 177 | * \retval `ERROR_SUCCESS` if `Assembler` was initialized and a buffer was created. 178 | * \warning This method allocates `Assembler->Buffer.Buffer`. 179 | */ 180 | BWSR_STATUS 181 | Assembler_Initialize 182 | ( 183 | IN assembler_t* Assembler, 184 | IN uintptr_t FixedAddress 185 | ); 186 | 187 | /** 188 | * \brief Allocates and initializes `RelocationData` and updates it's 189 | * contents with `Data`. This is then appended to the 190 | * `Assembler->RelocationData` array. 191 | * \param[in,out] RelocationData Stores `Data`. 192 | * \param[in] Assembler A 193 | * \param[in] Data Typically an address or label. 194 | * \return `BWSR_STATUS` 195 | * \retval `ERROR_ARGUMENT_IS_NULL` if `RelocationData` or `Assembler` is `NULL`. 196 | * \retval `ERROR_MEM_ALLOC` if any memory allocation fails. 197 | * \retval `ERROR_SUCCESS` if `RelocationData` was allocated and initialized. 198 | * \warning This method allocates `RelocationData` and `Assembler->RelocationData`. 199 | */ 200 | BWSR_STATUS 201 | Assembler_CreateRelocationData 202 | ( 203 | IN OUT relocation_data_t** RelocationData, 204 | IN assembler_t* Assembler, 205 | IN uint64_t Data 206 | ); 207 | 208 | /** 209 | * \brief Iterates through `Assembler->RelocationData` array, fixes up each 210 | * instruction, and then emits the instructions into `Assembler->Buffer`. 211 | * \param[in] Assembler A 212 | * \return `BWSR_STATUS` 213 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Assembler` is `NULL`. 214 | * \retval `ERROR_INVALID_ARGUMENT_VALUE` if `Assembler` contains relocation data with a size not greater than 0. 215 | * \retval `ERROR_MEM_ALLOC` if reallocation of `Assembler`'s buffer fails. 216 | * \retval `ERROR_SUCCESS` if `Assembler`'s buffer was updated. 217 | * \warning Through the call chain, `Assembler`'s buffer may be reallocated. 218 | */ 219 | BWSR_STATUS 220 | Assembler_WriteRelocationDataToPageBuffer 221 | ( 222 | IN assembler_t* Assembler 223 | ); 224 | 225 | /** 226 | * \brief Writes a given `Value` as an instruction to `Buffer`. 227 | * \param[in,out] Buffer Buffer to emit instruction. 228 | * \param[in] Value An instruction to emit into `Buffer`. 229 | * \return `BWSR_STATUS` 230 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer` is `NULL`. 231 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 232 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded instruction. 233 | * \warning Through the call chain, `Buffer` may be reallocated. 234 | */ 235 | BWSR_STATUS 236 | Assembler_Write32BitInstruction 237 | ( 238 | IN OUT memory_buffer_t* Buffer, 239 | IN uint32_t Value 240 | ); 241 | 242 | /** 243 | * \brief `LoadStore` instructions are used to load data from memory into 244 | * a register (Load) or store data from a register back into memory (Store). 245 | * These instructions are written into the provided `Buffer`. 246 | * \param[in,out] Buffer Buffer to emit instruction. 247 | * \param[in] Op Expected to be either `STR` or `LDR`. 248 | * \param[in] Register Load and store operations Register. 249 | * \param[in] Addr Address mode, offset, and register id. 250 | * \return `BWSR_STATUS` 251 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer`, `Result`, or `Addr` is `NULL`. 252 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 253 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded instruction. 254 | * \warning Through the call chain, `Buffer` may be reallocated. 255 | */ 256 | BWSR_STATUS 257 | Assembler_LoadStore 258 | ( 259 | IN OUT memory_buffer_t* Buffer, 260 | IN LoadStoreOp Op, 261 | IN const register_data_t* Register, 262 | IN const memory_operand_t* Addr 263 | ); 264 | 265 | /** 266 | * \brief `ADRP` (Address of Page) and `ADD` instructions are used together 267 | * to calculate the address of a large memory region. The `ADRP` instruction 268 | * computes the address of a 4KB page aligned with a specified memory address. 269 | * The `ADD` instruction is used to add an additional offset to the address 270 | * calculated by `ADRP`. 271 | * These instructions are written into the provided `Buffer`. 272 | * \param[in,out] Buffer Buffer to emit instruction. 273 | * \param[in] Register Where the result of an operation is stored or where data is moved to. 274 | * \param[in] From Start address. 275 | * \param[in] To End address. 276 | * \return `BWSR_STATUS` 277 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer` or `Destination` is `NULL`. 278 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 279 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded instruction. 280 | * \warning Through the call chain, `Buffer` may be reallocated. 281 | */ 282 | BWSR_STATUS 283 | Assembler_ADRP_ADD 284 | ( 285 | IN OUT memory_buffer_t* Buffer, 286 | IN register_data_t* Register, 287 | IN uint64_t From, 288 | IN uint64_t To 289 | ); 290 | 291 | /** 292 | * \brief `MOV` instruction is used to move (or copy) a value into a register. 293 | * This instruction is written into the provided `Buffer`. 294 | * \param[in,out] Buffer Buffer to emit instruction. 295 | * \param[in] Register Where the result of an operation is stored or where data is moved to. 296 | * \param[in] Immediate Immediate of encoded instruction. 297 | * \return `BWSR_STATUS` 298 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer` or `Destination` is `NULL`. 299 | * \retval `ERROR_MEM_ALLOC` if the reallocation of `Buffer` fails. 300 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded instruction. 301 | * \warning Through the call chain, `Buffer` may be reallocated. 302 | */ 303 | BWSR_STATUS 304 | Assembler_MOV 305 | ( 306 | IN OUT memory_buffer_t* Buffer, 307 | IN register_data_t* Register, 308 | IN uint64_t Immediate 309 | ); 310 | 311 | /** 312 | * \brief `LDR` (Load Register) instruction is used to load data from memory 313 | * into a register. 314 | * This instruction is written into the provided `Buffer`. 315 | * \param[in,out] Buffer Buffer to emit instruction. 316 | * \param[in] Result Load and store instructions Register. 317 | * \param[in] Relocation Contains branching address or location of a specific label. 318 | * \return `BWSR_STATUS` 319 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Buffer`, `Result`, or `Relocation` is `NULL`. 320 | * \retval `ERROR_MEM_ALLOC` if any allocation fails. 321 | * \retval `ERROR_SUCCESS` if `Buffer` was updated with the encoded instruction. 322 | * \warning Through the call chain, `Buffer` may be reallocated. 323 | */ 324 | BWSR_STATUS 325 | Assembler_WriteInstruction_LDR 326 | ( 327 | IN OUT memory_buffer_t* Buffer, 328 | IN register_data_t* Result, 329 | IN relocation_data_t* Relocation 330 | ); 331 | 332 | /** 333 | * \brief `LDR` and `BR` instructions are used together to load a literal value 334 | * with an immediate offset and branch to a different part of the code or to a 335 | * specific label. 336 | * These instructions are written into the provided `Assembler->Buffer`. 337 | * \param[in,out] Assembler A 338 | * \param[in] Address Branching address or location of a specific label. 339 | * \return `BWSR_STATUS` 340 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Assembler` is `NULL`. 341 | * \retval `ERROR_MEM_ALLOC` if any allocation fails. 342 | * \retval `ERROR_SUCCESS` if `Assembler->Buffer` was updated with the encoded instruction. 343 | * \warning Through the call chain, `Assembler->Buffer` may be reallocated. 344 | */ 345 | BWSR_STATUS 346 | Assembler_LiteralLdrBranch 347 | ( 348 | IN OUT assembler_t* Assembler, 349 | IN uint64_t Address 350 | ); 351 | 352 | /** 353 | * \brief Free all allocations held by the `Assembler` and resets all 354 | * references and data tracking variables. 355 | * \param[in,out] Assembler A 356 | * \return `BWSR_STATUS` 357 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Assembler` is `NULL`. 358 | * \retval `ERROR_SUCCESS` after all allocations are released. 359 | */ 360 | BWSR_STATUS 361 | Assembler_Release 362 | ( 363 | IN OUT assembler_t* Assembler 364 | ); 365 | 366 | #endif // __ASSEMBLER_H__ -------------------------------------------------------------------------------- /Hook/ImmediateDecoding.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __IMEDIATE_DECODING_H__ 3 | #define __IMEDIATE_DECODING_H__ 4 | 5 | // ----------------------------------------------------------------------------- 6 | // INCLUDES 7 | // ----------------------------------------------------------------------------- 8 | 9 | #include 10 | #include 11 | #include "utility/utility.h" 12 | 13 | // ----------------------------------------------------------------------------- 14 | // STRUCTURES 15 | // ----------------------------------------------------------------------------- 16 | 17 | struct { 18 | // Destination register 19 | uint32_t Destination : 5; 20 | // Upper immediate `19` bits 21 | uint32_t ImmHi : 19; 22 | // Must be 10000 == 0x10 23 | uint32_t Dummy_0 : 5; 24 | // Lower immediate `2` bits 25 | uint32_t ImmLo : 2; 26 | // `0` for `ADR`. `1` for `ADRP`. 27 | uint32_t Op : 1; 28 | } InstructionDecoder; 29 | 30 | // ----------------------------------------------------------------------------- 31 | // IMMEDIATE DECODING 32 | // ----------------------------------------------------------------------------- 33 | 34 | /** 35 | * \brief Performs a sign extension 36 | * \param[in] Extension Value by the sign extension performed. 37 | * \param[in] SignBit Bit position of the sign bit (0-indexed). 38 | * \return `int64_t` sign-extended value of `Extension`. 39 | */ 40 | static inline 41 | int64_t 42 | INTERNAL_SignExtend 43 | ( 44 | IN int64_t Extension, 45 | IN int SignBit 46 | ) 47 | { 48 | int64_t sign_mask = 0; 49 | int64_t extend = 0; 50 | 51 | sign_mask = ( 0 - GET_BIT( Extension, ( SignBit - 1 ) ) ); 52 | extend = ( Extension | ( ( sign_mask >> SignBit ) << SignBit ) ); 53 | 54 | return extend; 55 | } 56 | 57 | /** 58 | * \brief Extract and calculate a 26-bit immediate offset from the 59 | * given instruction. 60 | * \return `int64_t` the calculated 64-bit offset. 61 | */ 62 | static inline 63 | int64_t 64 | Imm26Offset 65 | ( 66 | IN uint32_t Instruction 67 | ) 68 | { 69 | int64_t offset = 0; 70 | int64_t imm26 = 0; 71 | 72 | imm26 = GET_BITS( Instruction, 0, 25 ); 73 | offset = ( imm26 << 2 ); 74 | offset = INTERNAL_SignExtend( offset, 28 ); 75 | 76 | return offset; 77 | } 78 | 79 | /** 80 | * \brief Extract and calculate a 19-bit immediate offset from the 81 | * given instruction. 82 | * \return `int64_t` the calculated 64-bit offset. 83 | */ 84 | static inline 85 | int64_t 86 | Imm19Offset 87 | ( 88 | IN uint32_t Instruction 89 | ) 90 | { 91 | int64_t offset = 0; 92 | int64_t imm19 = 0; 93 | 94 | imm19 = GET_BITS( Instruction, 5, 23 ); 95 | offset = ( imm19 << 2 ); 96 | offset = INTERNAL_SignExtend( offset, 21 ); 97 | 98 | return offset; 99 | } 100 | 101 | /** 102 | * \brief Extract and calculate a 14-bit immediate offset from the 103 | * given instruction. 104 | * \return `int64_t` the calculated 64-bit offset. 105 | */ 106 | static inline 107 | int64_t 108 | Imm14Offset 109 | ( 110 | IN uint32_t Instruction 111 | ) 112 | { 113 | int64_t offset = 0; 114 | int64_t imm14 = 0; 115 | 116 | imm14 = GET_BITS( Instruction, 5, 18 ); 117 | offset = ( imm14 << 2 ); 118 | offset = INTERNAL_SignExtend( offset, 16 ); 119 | 120 | return offset; 121 | } 122 | 123 | /** 124 | * \brief Extract and calculate a combined offset from separate 125 | * high and low immediate values in the given instruction. 126 | * \return `int64_t` the calculated 64-bit offset. 127 | */ 128 | static inline 129 | int64_t 130 | ImmHiImmLoOffset 131 | ( 132 | IN uint32_t Instruction 133 | ) 134 | { 135 | int64_t imm = 0; 136 | 137 | *(uint32_t*) &InstructionDecoder = Instruction; 138 | 139 | imm = InstructionDecoder.ImmLo + ( InstructionDecoder.ImmHi << 2 ); 140 | imm = INTERNAL_SignExtend( imm, 21 ); 141 | 142 | return imm; 143 | } 144 | 145 | /** 146 | * \brief Extract and calculate a combined offset and left-shift 147 | * it by 12 bits from separate high and low immediate values in 148 | * the given instruction. 149 | * \return `int64_t` the calculated 64-bit offset. 150 | */ 151 | static inline 152 | int64_t 153 | ImmHiImmLoZero12Offset 154 | ( 155 | IN uint32_t Instruction 156 | ) 157 | { 158 | int64_t imm = 0; 159 | 160 | imm = ImmHiImmLoOffset( Instruction ); 161 | imm = ( imm << 12 ); 162 | 163 | return imm; 164 | } 165 | 166 | #endif // __IMEDIATE_DECODING_H__ -------------------------------------------------------------------------------- /Hook/InlineHook.h: -------------------------------------------------------------------------------- 1 | 2 | #ifdef __cplusplus 3 | extern "C" { 4 | #endif 5 | 6 | typedef void 7 | ( *CallBeforePageWrite ) 8 | ( 9 | uintptr_t AlignedPageAddress 10 | ); 11 | 12 | typedef void 13 | ( *CallAfterPageWrite ) 14 | ( 15 | uintptr_t AlignedPageAddress 16 | ); 17 | 18 | int 19 | BWSR_InlineHook 20 | ( 21 | void* Address, 22 | void* HookFunction, 23 | void** OutOriginalFunction, 24 | void* BeforePageWriteFn, 25 | void* AfterPageWriteFn 26 | ); 27 | 28 | int 29 | BWSR_DestroyHook 30 | ( 31 | void* Address 32 | ); 33 | 34 | void 35 | BWSR_DestroyAllHooks 36 | ( 37 | void 38 | ); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 BossKoopa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Make/android.mk: -------------------------------------------------------------------------------- 1 | 2 | ifdef ANDROID_NDK 3 | 4 | PLATFORM := 5 | 6 | ifeq ($(UNAME),Darwin) 7 | $(eval PLATFORM := darwin) 8 | else ifeq ($(UNAME),Linux) 9 | $(eval PLATFORM := linux) 10 | endif 11 | 12 | ANDROID_TOOLCHAIN := $(ANDROID_NDK)/toolchains/llvm/prebuilt/$(PLATFORM)-x86_64/bin/clang 13 | ANDROID_SYSROOT := $(ANDROID_NDK)/toolchains/llvm/prebuilt/$(PLATFORM)-x86_64/sysroot 14 | AR_android := $(ANDROID_NDK)/toolchains/llvm/prebuilt/$(PLATFORM)-x86_64/bin/llvm-ar 15 | 16 | ANDROID_ARCH_FLAGS := -target aarch64-none-linux-android30 17 | ANDROID_ARCHS := arm64 18 | ANDROID_PLATFORMS := android 19 | 20 | ANDROID_DIRS := \ 21 | Memory \ 22 | Hook \ 23 | SymbolResolve/Linux 24 | 25 | EXAMPLE_LDFLAGS_android := \ 26 | -pie \ 27 | -llog \ 28 | -I. \ 29 | $(ANDROID_ARCH_FLAGS) 30 | 31 | ANDROID_GCCFLAGS := \ 32 | $(ANDROID_ARCH_FLAGS) \ 33 | -Os \ 34 | -Wall \ 35 | -Wextra \ 36 | -Werror \ 37 | --sysroot=$(ANDROID_SYSROOT) 38 | 39 | GCCFLAGS_android_debug := \ 40 | $(ANDROID_GCCFLAGS) \ 41 | -DDEBUG_MODE 42 | 43 | GCCFLAGS_android_release := $(ANDROID_GCCFLAGS) 44 | 45 | GCC_android := $(ANDROID_TOOLCHAIN) 46 | 47 | android_example_release: \ 48 | build/android/release/arm64/Example 49 | 50 | android_example_debug: \ 51 | build/android/debug/arm64/Example 52 | 53 | android_release: \ 54 | build/android/release/arm64/libBwsrHook 55 | 56 | android_debug: \ 57 | build/android/debug/arm64/libBwsrHook 58 | 59 | else 60 | 61 | android_example_release: 62 | android_example_debug: 63 | android_release: 64 | android_debug: 65 | 66 | endif 67 | -------------------------------------------------------------------------------- /Make/darwin.mk: -------------------------------------------------------------------------------- 1 | 2 | ifeq ($(UNAME),Darwin) 3 | 4 | GCC_BIN_ios := $(shell xcrun --sdk iphoneos --find clang) 5 | SDK_ios := $(shell xcrun --sdk iphoneos --show-sdk-path) 6 | AR_ios := $(shell xcrun --sdk iphoneos --find ar) 7 | 8 | GCC_BIN_mac := $(shell xcrun --sdk macosx --find clang) 9 | SDK_mac := $(shell xcrun --sdk macosx --show-sdk-path) 10 | AR_mac := $(shell xcrun --sdk macosx --find ar) 11 | 12 | DARWIN_ARCHS := arm64 arm64e 13 | 14 | DARWIN_PLATFORMS := ios mac 15 | 16 | DARWIN_DIRS := \ 17 | Memory \ 18 | Hook \ 19 | SymbolResolve/Darwin 20 | 21 | DARWIN_GCCFLAGS := \ 22 | -Os \ 23 | -Wall \ 24 | -Wextra \ 25 | -Werror \ 26 | -Wimplicit 27 | 28 | GCCFLAGS_mac_debug := \ 29 | $(DARWIN_GCCFLAGS) \ 30 | -DDEBUG_MODE 31 | 32 | GCCFLAGS_ios_debug := \ 33 | $(DARWIN_GCCFLAGS) \ 34 | -DDEBUG_MODE 35 | 36 | EXAMPLE_LDFLAGS_ios := \ 37 | -F$(SDK_ios)/System/Library/Frameworks/ \ 38 | -framework CoreFoundation \ 39 | -framework AudioToolbox \ 40 | -mios-version-min=14.0 41 | 42 | EXAMPLE_LDFLAGS_mac := \ 43 | -F$(SDK_mac)/System/Library/Frameworks/ \ 44 | -framework CoreFoundation \ 45 | -framework AudioToolbox 46 | 47 | GCCFLAGS_mac_release := $(DARWIN_GCCFLAGS) 48 | GCCFLAGS_ios_release := $(DARWIN_GCCFLAGS) 49 | 50 | GCC_mac := $(GCC_BIN_mac) -isysroot $(SDK_mac) 51 | GCC_ios := $(GCC_BIN_ios) -isysroot $(SDK_ios) -mios-version-min=14.0 52 | 53 | mac_example_release: \ 54 | $(BUILD_DIR)/mac/release/arm64/Example \ 55 | $(BUILD_DIR)/mac/release/arm64e/Example 56 | 57 | mac_example_debug: \ 58 | $(BUILD_DIR)/mac/debug/arm64/Example \ 59 | $(BUILD_DIR)/mac/debug/arm64e/Example 60 | 61 | ios_example_release: \ 62 | $(BUILD_DIR)/ios/release/arm64/Example \ 63 | $(BUILD_DIR)/ios/release/arm64e/Example 64 | 65 | ios_example_debug: \ 66 | $(BUILD_DIR)/ios/debug/arm64/Example \ 67 | $(BUILD_DIR)/ios/debug/arm64e/Example 68 | 69 | mac_release: \ 70 | $(BUILD_DIR)/mac/release/arm64/libBwsrHook \ 71 | $(BUILD_DIR)/mac/release/arm64e/libBwsrHook 72 | 73 | mac_debug: \ 74 | $(BUILD_DIR)/mac/debug/arm64/libBwsrHook \ 75 | $(BUILD_DIR)/mac/debug/arm64e/libBwsrHook 76 | 77 | ios_release: \ 78 | $(BUILD_DIR)/ios/release/arm64/libBwsrHook \ 79 | $(BUILD_DIR)/ios/release/arm64e/libBwsrHook 80 | 81 | ios_debug: \ 82 | $(BUILD_DIR)/ios/debug/arm64/libBwsrHook \ 83 | $(BUILD_DIR)/ios/debug/arm64e/libBwsrHook 84 | 85 | else 86 | 87 | mac_example_release: 88 | mac_example_debug: 89 | ios_example_release: 90 | ios_example_debug: 91 | mac_release: 92 | mac_debug: 93 | ios_release: 94 | ios_debug: 95 | 96 | endif 97 | -------------------------------------------------------------------------------- /Make/linux.mk: -------------------------------------------------------------------------------- 1 | 2 | CLANG_ARCH := 3 | UNAME := $(shell uname -s) 4 | 5 | ifeq ($(UNAME),Linux) 6 | 7 | LINUX_TOOLCHAIN := clang 8 | AR_linux := ar 9 | LINUX_ARCHS := arm64 10 | LINUX_PLATFORMS := linux 11 | 12 | LINUX_DIRS := \ 13 | Memory \ 14 | Hook \ 15 | SymbolResolve/Linux 16 | 17 | LINUX_GCCFLAGS := \ 18 | -Os \ 19 | -Wall \ 20 | -Wextra \ 21 | -Werror 22 | 23 | EXAMPLE_LDFLAGS_linux := 24 | 25 | GCCFLAGS_linux_debug := \ 26 | $(LINUX_GCCFLAGS) \ 27 | -DDEBUG_MODE 28 | 29 | GCCFLAGS_linux_release := $(LINUX_GCCFLAGS) 30 | GCC_linux := $(LINUX_TOOLCHAIN) 31 | 32 | $(eval CLANG_ARCH := $(shell clang -dumpmachine | cut -d '-' -f 1)) 33 | 34 | endif 35 | 36 | ifeq ($(CLANG_ARCH),aarch64) 37 | 38 | linux_example_release: \ 39 | $(BUILD_DIR)/linux/release/arm64/Example 40 | 41 | linux_example_debug: \ 42 | $(BUILD_DIR)/linux/debug/arm64/Example 43 | 44 | linux_release: \ 45 | $(BUILD_DIR)/linux/release/arm64/libBwsrHook 46 | 47 | linux_debug: \ 48 | $(BUILD_DIR)/linux/debug/arm64/libBwsrHook 49 | 50 | else 51 | 52 | linux_example_release: 53 | linux_example_debug: 54 | linux_release: 55 | linux_debug: 56 | 57 | endif 58 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | UNAME := $(shell uname -s) 3 | BUILD_DIR := build 4 | 5 | include Make/darwin.mk 6 | include Make/linux.mk 7 | include Make/android.mk 8 | 9 | DEPLOYMENTS := \ 10 | debug \ 11 | release 12 | 13 | define platform_rules 14 | # Source files 15 | SRCS_$(1) := $(foreach dir, \ 16 | $(4), \ 17 | $(wildcard $(dir)/*.c)) 18 | 19 | OBJS_$(1) := $$(patsubst %.c, \ 20 | $$(BUILD_DIR)/$(1)/$(3)/$(2)/%.o, \ 21 | $$(SRCS_$(1))) 22 | 23 | # Compiled objects 24 | $$(BUILD_DIR)/$(1)/$(3)/$(2)/%.o: %.c | \ 25 | $$(addprefix $$(BUILD_DIR)/$(1)/$(3)/$(2)/,$$($(4))) 26 | @echo "Compiling for $(1) on $(2) in $(3): $$<..." 27 | @mkdir -p $$(dir $$@) 28 | @$$(GCC_$(1)) $$(GCCFLAGS_$(1)_$(3)) -arch $(2) -I. -c $$< -o $$@ 29 | 30 | # libBwsrHook 31 | $$(BUILD_DIR)/$(1)/$(3)/$(2)/libBwsrHook: \ 32 | $$(OBJS_$(1)) | \ 33 | $$(addprefix $$(BUILD_DIR)/$(1)/$(3)/$(2)/,$$($(4))) 34 | @echo "Building Archive for $(1) on $(2) in $(3)..." 35 | @$$(AR_$(1)) rcs $(BUILD_DIR)/$(1)/$(3)/$(2)/libBwsrHook.a $$^ 36 | 37 | # Example 38 | $$(BUILD_DIR)/$(1)/$(3)/$(2)/Example: Example.c \ 39 | $$(OBJS_$(1)) | \ 40 | $$(addprefix $$(BUILD_DIR)/$(1)/$(3)/$(2)/,$$($(4))) 41 | @echo "Compiling Example for $(1) on $(2) in $(3)..." 42 | @$$(GCC_$(1)) $$(GCCFLAGS_$(1)_$(3)) -arch $(2) $$(EXAMPLE_LDFLAGS_$(1)) -I. -o $$@ $$^ 43 | ifeq ($(1),ios) 44 | @codesign -s - --entitlements Entitlements.plist $$@ 45 | endif 46 | 47 | $$(addprefix $$(BUILD_DIR)/$(1)/$(3)/$(2)/,$$($(4))): 48 | @mkdir -p $$@ 49 | endef 50 | 51 | # Evaluate the platform_rules for each platform 52 | ifeq ($(UNAME),Darwin) 53 | $(foreach platform,$(DARWIN_PLATFORMS), \ 54 | $(foreach arch,$(DARWIN_ARCHS), \ 55 | $(foreach deployment,$(DEPLOYMENTS), \ 56 | $(eval $(call platform_rules,$(platform),$(arch),$(deployment),$(DARWIN_DIRS))) \ 57 | ) \ 58 | ) \ 59 | ) 60 | endif 61 | 62 | ifeq ($(UNAME),Linux) 63 | $(foreach platform,$(LINUX_PLATFORMS), \ 64 | $(foreach arch,$(LINUX_ARCHS), \ 65 | $(foreach deployment,$(DEPLOYMENTS), \ 66 | $(eval $(call platform_rules,$(platform),$(arch),$(deployment),$(LINUX_DIRS))) \ 67 | ) \ 68 | ) \ 69 | ) 70 | endif 71 | 72 | ifdef ANDROID_NDK 73 | $(foreach platform,$(ANDROID_PLATFORMS), \ 74 | $(foreach arch,$(ANDROID_ARCHS), \ 75 | $(foreach deployment,$(DEPLOYMENTS), \ 76 | $(eval $(call platform_rules,$(platform),$(arch),$(deployment),$(ANDROID_DIRS))) \ 77 | ) \ 78 | ) \ 79 | ) 80 | endif 81 | 82 | $(BUILD_DIR): 83 | @mkdir -p $@ 84 | 85 | clean: 86 | rm -rf build 87 | 88 | collect_header: 89 | @cp Hook/InlineHook.h $(BUILD_DIR) 90 | 91 | hooklib_debug: \ 92 | mac_debug \ 93 | ios_debug \ 94 | android_debug \ 95 | linux_debug 96 | 97 | hooklib_release: \ 98 | mac_release \ 99 | ios_release \ 100 | android_release \ 101 | linux_release 102 | 103 | examples_debug: \ 104 | mac_example_debug \ 105 | ios_example_debug \ 106 | android_example_debug \ 107 | linux_example_debug 108 | 109 | examples_release: \ 110 | mac_example_release \ 111 | ios_example_release \ 112 | android_example_release \ 113 | linux_example_release 114 | 115 | examples: \ 116 | examples_release \ 117 | examples_debug 118 | 119 | hooklibs: \ 120 | hooklib_release \ 121 | hooklib_debug 122 | 123 | debug: \ 124 | hooklib_debug \ 125 | examples_debug 126 | 127 | release: \ 128 | hooklib_release \ 129 | examples_release 130 | 131 | all: hooklibs examples collect_header 132 | 133 | .DEFAULT_GOAL := all 134 | 135 | .PHONY: all clean release debug 136 | -------------------------------------------------------------------------------- /Memory/Memory.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORY_H__ 2 | #define __MEMORY_H__ 3 | 4 | #include "Memory/MemoryTracker.h" 5 | #include "Memory/MemoryAllocator.h" 6 | 7 | #endif // __MEMORY_H__ -------------------------------------------------------------------------------- /Memory/MemoryAllocator.c: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // INCLUDES 4 | // ----------------------------------------------------------------------------- 5 | 6 | #include 7 | #include 8 | 9 | #if defined( __APPLE__ ) 10 | #include 11 | #endif 12 | 13 | #include "Memory/Memory.h" 14 | 15 | // ----------------------------------------------------------------------------- 16 | // STRUCTURES & DEFINITIONS 17 | // ----------------------------------------------------------------------------- 18 | 19 | #define ALIGN_CEIL( ADDRESS, RANGE ) \ 20 | ( ( (uintptr_t) ADDRESS + (uintptr_t) RANGE - 1 ) & ~( (uintptr_t)RANGE - 1 ) ) 21 | 22 | /** 23 | * \brief Enforces adherence to memory protection range. 24 | */ 25 | typedef enum MemoryPermission { 26 | kNoAccess, 27 | 28 | kRead = 1, 29 | kWrite = 2, 30 | kExecute = 4, 31 | 32 | kReadWrite = kRead | kWrite, 33 | kReadExecute = kRead | kExecute, 34 | kReadWriteExecute = kRead | kWrite | kExecute, 35 | } MemoryPermission; 36 | 37 | // ----------------------------------------------------------------------------- 38 | // GLOBALS 39 | // ----------------------------------------------------------------------------- 40 | 41 | #if defined(__APPLE__) 42 | const int kMmapFd = VM_MAKE_TAG(255); 43 | #else 44 | const int kMmapFd = -1; 45 | #endif 46 | 47 | const int kMmapFdOffset = 0; 48 | 49 | // ----------------------------------------------------------------------------- 50 | // PROTOTYPES 51 | // ----------------------------------------------------------------------------- 52 | 53 | /** 54 | * \brief Converts MemoryPermission to suitable access permission 55 | * \param[in] Access Access permssion to convert 56 | * \return int 57 | * \retval int of memory protections matching the ones definied by `Access`. 58 | */ 59 | static 60 | int 61 | INTERNAL_GetPageProtection 62 | ( 63 | IN const MemoryPermission Access 64 | ); 65 | 66 | /** 67 | * \brief Initializes an Allocator. 68 | * \param[in,out] Allocator Allocator instance to initialize. 69 | * \param[in] VMPage The Allocated virtual page 70 | * \param[in] Capacity The size of the virtual page 71 | * \param[in] Alignment The byte alignment of the page 72 | * \return void 73 | */ 74 | static 75 | void 76 | INTERNAL_AllocatorInitialize 77 | ( 78 | OUT allocator_t* Allocator, 79 | IN uint8_t* VMPage, 80 | IN uint32_t Capacity, 81 | IN uint32_t Alignment 82 | ); 83 | 84 | /** 85 | * \brief Gets the next page offset in the buffer of the allocator. 86 | * \param[in,out] Data Pointer to update with the page offset 87 | * \param[in] Allocator The allocator holding page buffers 88 | * \param[in] BufferSize The size needed by `Data` 89 | * \param[in] Alignment The byte alignment of the virtual page. 90 | * \return BWSR_STATUS 91 | * \retval ERROR_MEMORY_OVERFLOW if the allocator does not have enough memory available 92 | * \retval ERROR_ARGUMENT_IS_NULL If `Data` or `Allocator` is `NULL`. 93 | * \retval ERROR_INVALID_ARGUMENT_VALUE If `BufferSize` is not greater than `0`. 94 | * \retval ERROR_SUCCESS if `Data` now points to a region of `Alloctor`'s buffer 95 | */ 96 | static 97 | BWSR_STATUS 98 | INTERNAL_Allocator_GetNextOffsetInBuffer 99 | ( 100 | OUT uint8_t** Data, 101 | IN OUT allocator_t* Allocator, 102 | IN const uint32_t BufferSize, 103 | IN const uint32_t Alignment 104 | ); 105 | 106 | /** 107 | * \brief Sets the protection permission on specific page buffer 108 | * \param[in] Address The address of the page buffer 109 | * \param[in] PageSize The size of the page buffer 110 | * \param[in] Access Permission to set the page buffer 111 | * \return BWSR_STATUS 112 | * \retval ERROR_ARGUMENT_IS_NULL if `Address` is `NULL`. 113 | * \retval ERROR_MEMORY_PERMISSION if the page permission could not be set 114 | * \retval ERROR_SUCCESS if the page permissions were changed 115 | */ 116 | static 117 | BWSR_STATUS 118 | INTERNAL_SetPagePermission 119 | ( 120 | IN OUT void* Address, 121 | IN const size_t PageSize, 122 | IN const MemoryPermission Access 123 | ); 124 | 125 | /** 126 | * \brief Allocates a virtual page with the given protection permissions 127 | * \param[in,out] MemoryRegion Address of mapped memory region 128 | * \param[in] MappingLength Length of the mapping 129 | * \param[in] Access Mapping options 130 | * \param[in] FixedAddress Start address of the mapping 131 | * \return BWSR_STATUS 132 | * \retval ERROR_ARGUMENT_IS_NULL if `MemoryRegion` is `NULL`. 133 | * \retval ERROR_INVALID_ARGUMENT_VALUE if `MappingLength` is not greater than `0`. 134 | * \retval ERROR_MEMORY_MAPPING if mmap fails. 135 | * \retval ERROR_SUCCESS if the page was allocated with the specified permissions 136 | */ 137 | static 138 | BWSR_STATUS 139 | INTERNAL_AllocateVirtualPage 140 | ( 141 | OUT void** MemoryRegion, 142 | IN const size_t MappingLength, 143 | IN const MemoryPermission Access, 144 | IN void* FixedAddress 145 | ); 146 | 147 | // ----------------------------------------------------------------------------- 148 | // IMPLEMENTATION 149 | // ----------------------------------------------------------------------------- 150 | 151 | static 152 | int 153 | INTERNAL_GetPageProtection 154 | ( 155 | IN const MemoryPermission Access 156 | ) 157 | { 158 | int prot = 0; 159 | 160 | if( Access & kRead ) 161 | { 162 | prot |= PROT_READ; 163 | } 164 | if( Access & kWrite ) 165 | { 166 | prot |= PROT_WRITE; 167 | } 168 | if( Access & kExecute ) 169 | { 170 | prot |= PROT_EXEC; 171 | } 172 | 173 | return prot; 174 | } 175 | 176 | static 177 | void 178 | INTERNAL_AllocatorInitialize 179 | ( 180 | OUT allocator_t* Allocator, 181 | IN uint8_t* VMPage, 182 | IN uint32_t Capacity, 183 | IN uint32_t Alignment 184 | ) 185 | { 186 | __NOT_NULL_RETURN_VOID( Allocator ); 187 | 188 | Allocator->Buffer = VMPage; 189 | Allocator->Capacity = Capacity; 190 | Allocator->BuiltinAlignment = Alignment; 191 | Allocator->Size = 0; 192 | } 193 | 194 | static 195 | BWSR_STATUS 196 | INTERNAL_Allocator_GetNextOffsetInBuffer 197 | ( 198 | OUT uint8_t** Data, 199 | IN OUT allocator_t* Allocator, 200 | IN const uint32_t BufferSize, 201 | IN const uint32_t Alignment 202 | ) 203 | { 204 | BWSR_STATUS retVal = ERROR_FAILURE; 205 | uint32_t alignment = 0; 206 | uintptr_t pageCeiling = 0; 207 | 208 | __NOT_NULL( Data, Allocator ); 209 | __GREATER_THAN_0( BufferSize ); 210 | 211 | alignment = ( ( Alignment != 0 ) 212 | ? Alignment 213 | : Allocator->BuiltinAlignment ); 214 | pageCeiling = (uintptr_t)( Allocator->Buffer + Allocator->Size ); 215 | 216 | Allocator->Size += ( ALIGN_CEIL( pageCeiling, alignment ) - pageCeiling ); 217 | 218 | if( ( Allocator->Size + BufferSize ) > Allocator->Capacity ) 219 | { 220 | BWSR_DEBUG( LOG_WARNING, "Allocator not large enough!\n" ); 221 | retVal = ERROR_MEMORY_OVERFLOW; 222 | } 223 | else { 224 | *Data = (uint8_t*)( Allocator->Buffer + Allocator->Size ); 225 | Allocator->Size += BufferSize; 226 | 227 | retVal = ERROR_SUCCESS; 228 | } 229 | 230 | return retVal; 231 | } 232 | 233 | static 234 | BWSR_STATUS 235 | INTERNAL_SetPagePermission 236 | ( 237 | IN OUT void* Address, 238 | IN const size_t PageSize, 239 | IN const MemoryPermission Access 240 | ) 241 | { 242 | BWSR_STATUS retVal = ERROR_FAILURE; 243 | int protection = 0; 244 | 245 | __NOT_NULL( Address ); 246 | __GREATER_THAN_0( PageSize ); 247 | 248 | protection = INTERNAL_GetPageProtection( Access ); 249 | 250 | if( 0 != mprotect( Address, 251 | PageSize, 252 | protection ) ) 253 | { 254 | BWSR_DEBUG( LOG_ERROR, "mprotect() Failed\n" ); 255 | retVal = ERROR_MEMORY_PERMISSION; 256 | } 257 | else { 258 | retVal = ERROR_SUCCESS; 259 | } 260 | 261 | return retVal; 262 | } 263 | 264 | static 265 | BWSR_STATUS 266 | INTERNAL_AllocateVirtualPage 267 | ( 268 | OUT void** MemoryRegion, 269 | IN const size_t MappingLength, 270 | IN const MemoryPermission Access, 271 | IN void* FixedAddress 272 | ) 273 | { 274 | BWSR_STATUS retVal = ERROR_FAILURE; 275 | int protection = 0; 276 | int flags = ( MAP_PRIVATE | MAP_ANONYMOUS ); 277 | 278 | __NOT_NULL( MemoryRegion ); 279 | __GREATER_THAN_0( MappingLength ); 280 | 281 | protection = INTERNAL_GetPageProtection( Access ); 282 | 283 | if( NULL != FixedAddress ) 284 | { 285 | flags |= MAP_FIXED; 286 | } 287 | 288 | if( MAP_FAILED == ( *MemoryRegion = mmap( FixedAddress, 289 | MappingLength, 290 | protection, 291 | flags, 292 | kMmapFd, 293 | kMmapFdOffset ) ) ) 294 | { 295 | BWSR_DEBUG( LOG_ERROR, "mmap() Failed\n" ); 296 | retVal = ERROR_MEMORY_MAPPING; 297 | } 298 | else { 299 | retVal = ERROR_SUCCESS; 300 | } // mmap() 301 | 302 | return retVal; 303 | } 304 | 305 | BWSR_STATUS 306 | MemoryAllocator_AllocateExecutionBlock 307 | ( 308 | IN OUT memory_range_t** MemoryRange, 309 | IN OUT memory_allocator_t* Allocator, 310 | IN size_t BufferSize 311 | ) 312 | { 313 | BWSR_STATUS retVal = ERROR_FAILURE; 314 | uint8_t* result = NULL; 315 | void* page = NULL; 316 | size_t i = 0; 317 | size_t allocatorSize = 0; 318 | size_t pageSize = 0; 319 | 320 | __NOT_NULL( Allocator, MemoryRange ); 321 | __GREATER_THAN_0( BufferSize ); 322 | 323 | pageSize = (size_t)sysconf( _SC_PAGESIZE ); 324 | 325 | if( BufferSize > pageSize ) 326 | { 327 | BWSR_DEBUG( LOG_ERROR, 328 | "Requested Size is too large: %zu\n", 329 | BufferSize ); 330 | return ERROR_MEMORY_OVERFLOW; 331 | } // dummy check 332 | 333 | for( i = 0; ( i < Allocator->AllocatorCount ) && ( ERROR_SUCCESS != retVal ); i++ ) 334 | { 335 | retVal = INTERNAL_Allocator_GetNextOffsetInBuffer( &result, 336 | &Allocator->Allocators[ i ], 337 | BufferSize, 338 | 0 ); 339 | } // for() 340 | 341 | if( !result ) 342 | { 343 | if( ERROR_SUCCESS != ( retVal = INTERNAL_AllocateVirtualPage( &page, 344 | pageSize, 345 | kNoAccess, 346 | NULL ) ) ) 347 | { 348 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_AllocateVirtualPage() Failed\n" ); 349 | } 350 | else { 351 | if( ERROR_SUCCESS != ( retVal = INTERNAL_SetPagePermission( page, 352 | pageSize, 353 | kReadExecute ) ) ) 354 | { 355 | BWSR_DEBUG( LOG_ERROR, "OSMemory_SetPermission() Failed\n" ); 356 | } 357 | else { 358 | Allocator->AllocatorCount++; 359 | allocatorSize = Allocator->AllocatorCount * sizeof( allocator_t ); 360 | 361 | if( NULL == Allocator->Allocators ) 362 | { 363 | Allocator->Allocators = (allocator_t*) BwsrMalloc( allocatorSize ); 364 | } 365 | else { 366 | Allocator->Allocators = (allocator_t*) BwsrRealloc( Allocator->Allocators, allocatorSize ); 367 | } 368 | 369 | if( NULL == Allocator->Allocators ) 370 | { 371 | BWSR_DEBUG( LOG_ERROR, "BwsrMalloc() Failed\n" ); 372 | retVal = ERROR_MEM_ALLOC; 373 | } 374 | else { 375 | INTERNAL_AllocatorInitialize( &Allocator->Allocators[ Allocator->AllocatorCount - 1 ], 376 | (uint8_t*) page, 377 | (uint32_t) sysconf( _SC_PAGESIZE ), 378 | 8 ); 379 | 380 | retVal = INTERNAL_Allocator_GetNextOffsetInBuffer( &result, 381 | &Allocator->Allocators[ Allocator->AllocatorCount - 1 ], 382 | BufferSize, 383 | 0 ); 384 | } // BwsrMalloc() 385 | } // OSMemory_SetPermission() 386 | } // INTERNAL_AllocateVirtualPage() 387 | } // !result 388 | 389 | if( ERROR_SUCCESS == retVal ) 390 | { 391 | if( NULL == ( *MemoryRange = (memory_range_t*) BwsrMalloc( sizeof( memory_range_t ) ) ) ) 392 | { 393 | BWSR_DEBUG( LOG_ERROR, "BwsrMalloc() Failed\n" ); 394 | retVal = ERROR_MEM_ALLOC; 395 | } 396 | else { 397 | ( *MemoryRange )->Start = (uintptr_t)result; 398 | ( *MemoryRange )->Size = BufferSize; 399 | } // BwsrMalloc() 400 | } // INTERNAL_Allocator_GetNextOffsetInBuffer() 401 | 402 | return retVal; 403 | } -------------------------------------------------------------------------------- /Memory/MemoryAllocator.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORY_ALLOCATOR_H__ 2 | #define __MEMORY_ALLOCATOR_H__ 3 | 4 | // ----------------------------------------------------------------------------- 5 | // INCLUDES 6 | // ----------------------------------------------------------------------------- 7 | 8 | #include 9 | #include 10 | 11 | #include "utility/utility.h" 12 | #include "utility/error.h" 13 | 14 | // ----------------------------------------------------------------------------- 15 | // STRUCTURES & DEFINITIONS 16 | // ----------------------------------------------------------------------------- 17 | 18 | typedef struct memory_range_t { 19 | // Starting address of the memory range 20 | uintptr_t Start; 21 | // Size of the memory range in bytes 22 | size_t Size; 23 | } memory_range_t; 24 | 25 | typedef struct allocator_t { 26 | // Pointer to the allocated memory buffer 27 | uint8_t* Buffer; 28 | // Current size of the allocated buffer in bytes 29 | uint32_t Size; 30 | // Total capacity of the allocated buffer in bytes 31 | uint32_t Capacity; 32 | // Page alignment requirement for allocations (typically 8 or 0) 33 | uint32_t BuiltinAlignment; 34 | } allocator_t; 35 | 36 | typedef struct memory_allocator_t { 37 | // Pointer to all the allocators in use 38 | allocator_t* Allocators; 39 | // Current amount of allocators 40 | size_t AllocatorCount; 41 | } memory_allocator_t; 42 | 43 | // ----------------------------------------------------------------------------- 44 | // EXPORTED FUNCTIONS 45 | // ----------------------------------------------------------------------------- 46 | 47 | /** 48 | * \brief Creates a memory block of a given size with `PROT_READ` and 49 | * `PROT_EXEC` permission. 50 | * \param[in,out] MemoryRange Block of allocated memory 51 | * \param[in,out] Allocator Allocator used to hold the memory 52 | * \param[in] BufferSize Size required of the memory block 53 | * \return `BWSR_STATUS` 54 | * \retval `ERROR_ARGUMENT_IS_NULL` if `Allocator` or `MemoryRange` is `NULL`. 55 | * \retval `ERROR_INVALID_ARGUMENT_VALUE` if `BufferSize` is not greater than `0`. 56 | * \retval `ERROR_MEMORY_MAPPING` if `mmap` fails. 57 | * \retval `ERROR_MEMORY_PERMISSION` if the page permission could not be set 58 | * \retval `ERROR_MEM_ALLOC` on allocation failure 59 | * \retval `ERROR_MEMORY_OVERFLOW` if the allocator does not have enough memory available 60 | * \retval `ERROR_SUCCESS` if `MemoryRange` was allocated with the correct permissions 61 | */ 62 | BWSR_STATUS 63 | MemoryAllocator_AllocateExecutionBlock 64 | ( 65 | IN OUT memory_range_t** MemoryRange, 66 | IN OUT memory_allocator_t* Allocator, 67 | IN size_t BufferSize 68 | ); 69 | 70 | #endif // __MEMORY_ALLOCATOR_H__ 71 | -------------------------------------------------------------------------------- /Memory/MemoryTracker.c: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // INCLUDES 4 | // ----------------------------------------------------------------------------- 5 | 6 | #include 7 | 8 | #ifdef BWSR_SECURELY_ZERO_MEMORY 9 | 10 | #include 11 | 12 | #endif // BWSR_SECURELY_ZERO_MEMORY 13 | 14 | #include "Memory/MemoryTracker.h" 15 | #include "utility/debug.h" 16 | #include "utility/error.h" 17 | 18 | // ----------------------------------------------------------------------------- 19 | // STRUCTURES & DEFINITIONS 20 | // ----------------------------------------------------------------------------- 21 | 22 | #define FREE_ALLOCATION_POINTER 1 23 | #define KEEP_ALLOCATION_POINTER 0 24 | 25 | /** 26 | * \brief Tracks file name and line number of allocations 27 | */ 28 | typedef struct memory_tracker_t { 29 | // Address of the allocated memory 30 | void* Address; 31 | // The size, in bytes, of the allocated memory 32 | size_t AllocationSize; 33 | // The location of the next memory tracker instance 34 | struct memory_tracker_t* Next; 35 | // The location of the previous memory tracker instance 36 | struct memory_tracker_t* Previous; 37 | // The line number of the originator requesting allocation 38 | size_t LineNumber; 39 | // The file name of the originator requesting allocation 40 | char FileName[ 1 ]; 41 | } memory_tracker_t; 42 | 43 | // ----------------------------------------------------------------------------- 44 | // GLOBALS 45 | // ----------------------------------------------------------------------------- 46 | 47 | static memory_tracker_t gMemoryTracker = 48 | { 49 | .Address = 0, 50 | .AllocationSize = 0, 51 | .Next = &gMemoryTracker, 52 | .Previous = &gMemoryTracker 53 | }; 54 | 55 | // ----------------------------------------------------------------------------- 56 | // PROTOTYPES 57 | // ----------------------------------------------------------------------------- 58 | 59 | /** 60 | * \brief Releases a memory tracker and removes it from the global link 61 | * \param[in,out] Tracker The Tracker of a memory allocation 62 | * \param[in] ReleaseAddress Wether not to release the allocation 63 | * \return void 64 | */ 65 | static 66 | void 67 | INTERNAL_MemoryTracker_Release 68 | ( 69 | IN OUT memory_tracker_t* Tracker, 70 | IN const uint8_t ReleaseAddress 71 | ); 72 | 73 | /** 74 | * \brief Initializes a memory tracker and adds it to the global link 75 | * \param[in,out] Tracker Pointer to track memory allocation 76 | * \param[in] AllocationSize The requested allocation size 77 | * \param[in] FileName The file name of the originator 78 | * \param[in] LineNumber The line number of the originator 79 | * \return BWSR_STATUS 80 | * \retval ERROR_ARGUMENT_IS_NULL if `Tracker` or `FileName` is `NULL`. 81 | * \retval ERROR_INVALID_ARGUMENT_VALUE if `AllocationSize` or `LineNumber` is not greater than `0`. 82 | * \retval ERROR_MEM_ALLOC if `Tracker` could not be allocated 83 | * \retval ERROR_SUCCESS if `Tracker` was allocated and linked in `gMemoryTracker`. 84 | */ 85 | static 86 | BWSR_STATUS 87 | INTERNAL_MemoryTracker_Initialize 88 | ( 89 | OUT memory_tracker_t** Tracker, 90 | IN const size_t AllocationSize, 91 | IN const char* FileName, 92 | IN const size_t LineNumber 93 | ); 94 | 95 | // ----------------------------------------------------------------------------- 96 | // IMPLEMENTATION 97 | // ----------------------------------------------------------------------------- 98 | 99 | static 100 | void 101 | INTERNAL_MemoryTracker_Release 102 | ( 103 | IN OUT memory_tracker_t* Tracker, 104 | IN const uint8_t ReleaseAddress 105 | ) 106 | { 107 | __NOT_NULL_RETURN_VOID( Tracker ); 108 | 109 | if( ( FREE_ALLOCATION_POINTER == ReleaseAddress ) && 110 | ( NULL != Tracker->Address ) ) 111 | { 112 | 113 | #ifdef BWSR_SECURELY_ZERO_MEMORY 114 | 115 | memset_s( Tracker->Address, 116 | Tracker->AllocationSize, 117 | 0, 118 | Tracker->AllocationSize ); 119 | 120 | #endif // BWSR_SECURELY_ZERO_MEMORY 121 | 122 | free( Tracker->Address ); 123 | Tracker->Address = NULL; 124 | } // Tracking check 125 | 126 | Tracker->Previous->Next = Tracker->Next; 127 | Tracker->Next->Previous = Tracker->Previous; 128 | Tracker->Next = NULL; 129 | Tracker->Previous = NULL; 130 | Tracker->AllocationSize = 0; 131 | 132 | free( Tracker ); 133 | } 134 | 135 | static 136 | BWSR_STATUS 137 | INTERNAL_MemoryTracker_Initialize 138 | ( 139 | OUT memory_tracker_t** Tracker, 140 | IN const size_t AllocationSize, 141 | IN const char* FileName, 142 | IN const size_t LineNumber 143 | ) 144 | { 145 | BWSR_STATUS retVal = ERROR_FAILURE; 146 | size_t lineLength = 0; 147 | 148 | __NOT_NULL( Tracker, FileName ); 149 | __GREATER_THAN_0( AllocationSize, LineNumber ); 150 | 151 | lineLength = strnlen( FileName, PATH_MAX ); 152 | 153 | if( NULL == ( *Tracker = malloc( sizeof( memory_tracker_t ) + lineLength + sizeof( char ) ) ) ) 154 | { 155 | retVal = ERROR_MEM_ALLOC; 156 | } 157 | else { 158 | memcpy( ( *Tracker )->FileName, 159 | FileName, 160 | lineLength ); 161 | 162 | *( ( *Tracker )->FileName + lineLength ) = 0x00; 163 | ( *Tracker )->AllocationSize = AllocationSize; 164 | ( *Tracker )->LineNumber = LineNumber; 165 | ( *Tracker )->Next = &gMemoryTracker; 166 | ( *Tracker )->Previous = gMemoryTracker.Previous; 167 | gMemoryTracker.Previous->Next = *Tracker; 168 | gMemoryTracker.Previous = *Tracker; 169 | 170 | retVal = ERROR_SUCCESS; 171 | } // malloc() 172 | 173 | return retVal; 174 | } 175 | 176 | void 177 | MemoryTracker_Free 178 | ( 179 | IN void* Pointer 180 | ) 181 | { 182 | memory_tracker_t* tracker = gMemoryTracker.Next; 183 | 184 | __NOT_NULL_RETURN_VOID( Pointer ); 185 | 186 | while( ( tracker != &gMemoryTracker ) && 187 | ( tracker->Address != Pointer ) ) 188 | { 189 | tracker = tracker->Next; 190 | } // while() 191 | 192 | if( tracker == &gMemoryTracker ) 193 | { 194 | BWSR_DEBUG( LOG_INFO, 195 | "Not tracking address: %p. Not attempting release.\n", 196 | Pointer ); 197 | } 198 | else { 199 | INTERNAL_MemoryTracker_Release( tracker, FREE_ALLOCATION_POINTER ); 200 | } // dummy check 201 | 202 | return; 203 | } 204 | 205 | void* 206 | MemoryTracker_Reallocate 207 | ( 208 | IN OUT void* Reference, 209 | IN const size_t AllocationSize, 210 | IN const char* FileName, 211 | IN const size_t LineNumber 212 | ) 213 | { 214 | memory_tracker_t* tracker = gMemoryTracker.Next; 215 | void* allocation = NULL; 216 | 217 | __NOT_NULL_RETURN_NULL( Reference, FileName ); 218 | __GREATER_THAN_0_RETURN_NULL( AllocationSize, LineNumber ); 219 | 220 | while( ( tracker != &gMemoryTracker ) && 221 | ( tracker->Address != Reference ) ) 222 | { 223 | tracker = tracker->Next; 224 | } // while() 225 | 226 | if( tracker == &gMemoryTracker ) 227 | { 228 | BWSR_DEBUG( LOG_CRITICAL, "You don't know what you're doing.\n" ); 229 | } 230 | else { 231 | INTERNAL_MemoryTracker_Release( tracker, KEEP_ALLOCATION_POINTER ); 232 | 233 | if( ERROR_SUCCESS != INTERNAL_MemoryTracker_Initialize( &tracker, 234 | AllocationSize, 235 | FileName, 236 | LineNumber ) ) 237 | { 238 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_MemoryTracker_Initialize() Failed\n" ); 239 | } 240 | else { 241 | if( NULL == ( allocation = realloc( Reference, AllocationSize ) ) ) 242 | { 243 | BWSR_DEBUG( LOG_ERROR, "realloc() Failed\n" ); 244 | INTERNAL_MemoryTracker_Release( tracker, KEEP_ALLOCATION_POINTER ); 245 | } 246 | else { 247 | tracker->Address = allocation; 248 | } // realloc() 249 | } // INTERNAL_MemoryTracker_Initialize() 250 | } // dummy check 251 | 252 | return allocation; 253 | } 254 | 255 | void* 256 | MemoryTracker_Calloc 257 | ( 258 | IN const size_t AllocationCount, 259 | IN const size_t AllocationSize, 260 | IN const char* FileName, 261 | IN const size_t LineNumber 262 | ) 263 | { 264 | memory_tracker_t* tracker = NULL; 265 | void* allocation = NULL; 266 | 267 | __NOT_NULL_RETURN_NULL( FileName ); 268 | __GREATER_THAN_0_RETURN_NULL( AllocationCount, 269 | AllocationSize, 270 | LineNumber ); 271 | 272 | if( ERROR_SUCCESS != INTERNAL_MemoryTracker_Initialize( &tracker, 273 | ( AllocationSize * AllocationCount ), 274 | FileName, 275 | LineNumber ) ) 276 | { 277 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_MemoryTracker_Initialize() Failed\n" ); 278 | } 279 | else { 280 | if( NULL == ( allocation = calloc( AllocationCount, AllocationSize ) ) ) 281 | { 282 | BWSR_DEBUG( LOG_ERROR, "malloc() Failed\n" ); 283 | INTERNAL_MemoryTracker_Release( tracker, KEEP_ALLOCATION_POINTER ); 284 | } 285 | else { 286 | tracker->Address = allocation; 287 | } // malloc() 288 | } // INTERNAL_MemoryTracker_Initialize() 289 | 290 | return allocation; 291 | } 292 | 293 | void* 294 | MemoryTracker_Allocate 295 | ( 296 | IN const uint64_t AllocationSize, 297 | IN const char* FileName, 298 | IN const size_t LineNumber 299 | ) 300 | { 301 | memory_tracker_t* tracker = NULL; 302 | void* allocation = NULL; 303 | 304 | __NOT_NULL_RETURN_NULL( FileName ); 305 | __GREATER_THAN_0_RETURN_NULL( AllocationSize, LineNumber ); 306 | 307 | if( ERROR_SUCCESS != INTERNAL_MemoryTracker_Initialize( &tracker, 308 | AllocationSize, 309 | FileName, 310 | LineNumber ) ) 311 | { 312 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_MemoryTracker_Initialize() Failed\n" ); 313 | } 314 | else { 315 | if( NULL == ( allocation = malloc( AllocationSize ) ) ) 316 | { 317 | BWSR_DEBUG( LOG_ERROR, "malloc() Failed\n" ); 318 | INTERNAL_MemoryTracker_Release( tracker, KEEP_ALLOCATION_POINTER ); 319 | } 320 | else { 321 | tracker->Address = allocation; 322 | } // malloc() 323 | } // INTERNAL_MemoryTracker_Initialize() 324 | 325 | return allocation; 326 | } 327 | 328 | size_t 329 | MemoryTracker_CheckForMemoryLeaks 330 | ( 331 | void 332 | ) 333 | { 334 | memory_tracker_t* tracker = gMemoryTracker.Next; 335 | size_t leakCount = 0; 336 | 337 | #ifdef DEBUG_MODE 338 | size_t leakAmount = 0; 339 | #endif 340 | 341 | while( tracker != &gMemoryTracker ) 342 | { 343 | leakCount++; 344 | 345 | BWSR_DEBUG( LOG_WARNING, 346 | "%s[%zu]: Leaked %zu Bytes at Address: %p!", 347 | tracker->FileName, 348 | tracker->LineNumber, 349 | tracker->AllocationSize, 350 | tracker->Address ); 351 | #ifdef DEBUG_MODE 352 | leakAmount += tracker->AllocationSize; 353 | #endif 354 | tracker = tracker->Next; 355 | } // while() 356 | 357 | #ifdef DEBUG_MODE 358 | if( leakCount ) 359 | { 360 | BWSR_DEBUG( LOG_WARNING, 361 | "Totals: %zu leaks totalling %zu Bytes!", 362 | leakCount, 363 | leakAmount ); 364 | } 365 | #endif 366 | 367 | return leakCount; 368 | } 369 | -------------------------------------------------------------------------------- /Memory/MemoryTracker.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MEMORY_TRACKER_H__ 3 | #define __MEMORY_TRACKER_H__ 4 | 5 | // ----------------------------------------------------------------------------- 6 | // INCLUDES 7 | // ----------------------------------------------------------------------------- 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "utility/utility.h" 15 | 16 | // ----------------------------------------------------------------------------- 17 | // DEFINITIONS 18 | // ----------------------------------------------------------------------------- 19 | 20 | #if defined( DEBUG_MODE ) 21 | 22 | // Memory tracked malloc 23 | #define BwsrMalloc( AllocationSize ) \ 24 | MemoryTracker_Allocate( AllocationSize, \ 25 | __FILE__, \ 26 | __LINE__ ) 27 | 28 | // Memory tracker realloc 29 | #define BwsrRealloc( Pointer, AllocationSize ) \ 30 | MemoryTracker_Reallocate( Pointer, \ 31 | AllocationSize, \ 32 | __FILE__, \ 33 | __LINE__ ) 34 | 35 | // Memory tracked calloc 36 | #define BwsrCalloc( AllocationCount, AllocationSize ) \ 37 | MemoryTracker_Calloc( AllocationCount, \ 38 | AllocationSize, \ 39 | __FILE__, \ 40 | __LINE__ ) 41 | 42 | // Memory tracked free 43 | #define BwsrFree( Pointer ) \ 44 | MemoryTracker_Free( Pointer ) 45 | 46 | #else 47 | 48 | // Memory tracked malloc 49 | #define BwsrMalloc( AllocationSize ) \ 50 | malloc( AllocationSize ) 51 | 52 | // Memory tracker realloc 53 | #define BwsrRealloc( Pointer, AllocationSize ) \ 54 | realloc( Pointer, AllocationSize ) 55 | 56 | // Memory tracked calloc 57 | #define BwsrCalloc( AllocationCount, AllocationSize ) \ 58 | calloc( AllocationCount, AllocationSize ) 59 | 60 | // Memory tracked free 61 | #define BwsrFree( Pointer ) \ 62 | if( NULL != Pointer ) \ 63 | { \ 64 | free( Pointer ); \ 65 | } 66 | 67 | #endif 68 | 69 | // ----------------------------------------------------------------------------- 70 | // EXPORTED FUNCTIONS 71 | // ----------------------------------------------------------------------------- 72 | 73 | /** 74 | * \brief Releases both the tracker and the allocation at a given address 75 | * \param[in] Pointer The pointer of the allocated memory 76 | * \return void 77 | */ 78 | void 79 | MemoryTracker_Free 80 | ( 81 | IN void* Pointer 82 | ); 83 | 84 | /** 85 | * \brief Reallocates memory at the given address and updates the tracker 86 | * \param[in,out] Reference The pointer to the allcoated memory 87 | * \param[in] AllocationSize The updated allocation size 88 | * \param[in] FileName The file name of the originator 89 | * \param[in] LineNumber The line number of the originator 90 | * \return void* 91 | * \retval NULL if any allocation fails. 92 | * \retval NULL if `Reference` or `FileName` is `NULL`. 93 | * \retval NULL if `AllocationSize` or `LineNumber` is not greater than `0`. 94 | * \retval void* a pointer to the new allocation 95 | */ 96 | void* 97 | MemoryTracker_Reallocate 98 | ( 99 | IN OUT void* Reference, 100 | IN const size_t AllocationSize, 101 | IN const char* FileName, 102 | IN const size_t LineNumber 103 | ); 104 | 105 | /** 106 | * \brief Allocates memory of the specified size and initializes a tracker 107 | * \param[in] AllocationCount The number of objects 108 | * \param[in] AllocationSize The size of each object 109 | * \param[in] FileName The file name of the originator 110 | * \param[in] LineNumber The line number of the originator 111 | * \return void* 112 | * \retval NULL if any allocation fails. 113 | * \retval NULL if `FileName` is `NULL`. 114 | * \retval NULL if `AllocationCount`, `AllocationSize` or `LineNumber` is not greater than `0`. 115 | * \retval void* a pointer to the new allocation 116 | */ 117 | void* 118 | MemoryTracker_Calloc 119 | ( 120 | IN const size_t AllocationCount, 121 | IN const size_t AllocationSize, 122 | IN const char* FileName, 123 | IN const size_t LineNumber 124 | ); 125 | 126 | /** 127 | * \brief Allocates memory of the specified size and initializes a tracker 128 | * \param[in] AllocationSize The size of the allcation 129 | * \param[in] FileName The file name of the originator 130 | * \param[in] LineNumber The line number of the originator 131 | * \return void* 132 | * \retval NULL if any allocation fails. 133 | * \retval NULL if `FileName` is `NULL`. 134 | * \retval NULL if `AllocationSize` or `LineNumber` is not greater than `0`. 135 | * \retval void* a pointer to the new allocation 136 | */ 137 | void* 138 | MemoryTracker_Allocate 139 | ( 140 | IN const uint64_t AllocationSize, 141 | IN const char* FileName, 142 | IN const size_t LineNumber 143 | ); 144 | 145 | /** 146 | * \brief Iterates the memory tracker and counts the remaining allocations 147 | * \return size_t 148 | * \retval size_t A count of the remaining allocations in the memory tracker 149 | */ 150 | size_t 151 | MemoryTracker_CheckForMemoryLeaks 152 | ( 153 | void 154 | ); 155 | 156 | #endif // __MEMORY_TRACKER_H__ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BWSR 2 | Inline Hooking Library for Arm64 devices across multiple platforms. 3 | 4 | Platform Support: 5 | - iOS (arm64/arm64e). 6 | - Android (arm64). 7 | - Linux (arm64). 8 | - OSX (arm64/arm64e). 9 | 10 | BWSR is a versatile inline hooking library implemented entirely in `C`, designed to facilitate dynamic code modification and interception on `Linux`, `OSX`, `iOS`, and `Android`. 11 | 12 | ## Building 13 | Building `iOS` and `MacOSX` requires a Mac machine with `X-Code` and `Command-Line-Tools` installed. 14 | 15 | Building `Android` requires a recent AndroidNDK downloaded and have the `ANDROID_NDK` environmental set to the path of the NDK. 16 | 17 | Building `Linux` requires that `build-essential` and `clang` are installed. 18 | 19 | To make the hooking library and all the example programs simply run: 20 | ```sh 21 | make 22 | ``` 23 | 24 | To make only the hooking library 25 | ```sh 26 | make hooklibs 27 | ``` 28 | 29 | To make the example program 30 | ```sh 31 | make examples 32 | ``` 33 | 34 | ## Symbol Resolver (Locating the Address of a Function) 35 | 36 | ### Symbol Resolution When the Image IS Known 37 | This will return the address of the first occurence encountered of only the mach header matching the specific image name and the specific function name. 38 | ```c 39 | uintptr_t function_address = 0; 40 | 41 | // iOS 42 | retVal = BWSR_ResolveSymbol( "AudioUnitProcess", "AudioToolbox", &function_address ); 43 | 44 | // Android 45 | retVal = BWSR_ResolveSymbol( "open", "/apex/com.android.runtime/lib64/bionic/libc.so", &function_address ); 46 | ``` 47 | 48 | ### Symbol Resolution When the Image Is **NOT** Known 49 | This will return the address of the first occurence encounted in any mach header for the matching function name. This is usually fine but if the function name is common enough you may get the address of the wrong function. 50 | ```c 51 | uintptr_t function_address = 0; 52 | 53 | // iOS/Mac 54 | retVal = BWSR_ResolveSymbol( "AudioUnitProcess", NULL, &function_address ); 55 | 56 | // Android/Linux 57 | retVal = BWSR_ResolveSymbol( "open", NULL, &function_address ); 58 | ``` 59 | 60 | ## Inline Hooking 61 | Hooks and code page backups are handled internally, so there is no need to worry about reverting hooks or memory leaks. 62 | 63 | ### Simple Inline Hook 64 | The easiest and most user friendly way to hook 65 | ```c 66 | // Function receiving the printf calls 67 | int hook_printf( const char* text, ... ) { 68 | return -1; 69 | } 70 | 71 | // A simple hook of printf 72 | BWSR_InlineHook( printf, hook_printf, NULL, NULL, NULL ); 73 | 74 | // Cleanup the hook 75 | BWSR_DestroyHook( printf ); 76 | ``` 77 | 78 | ### Original Function Callback 79 | It may be benefitial to have a pointer to where the original function to use inside of the hooked function for recording or altering parameters. 80 | ```c 81 | // Pointer to the original creat() 82 | void* original_creat = NULL; 83 | 84 | // The version replacing creat() 85 | int hcreat( const char * files, mode_t modes ) { 86 | BWSR_DEBUG( LOG_CRITICAL, "SUCCESS! Caught creat()\n" ); 87 | if( NULL != original_creat ) 88 | return ((__typeof(creat)*)original_creat)("/some/new/location", modes); 89 | return 0; 90 | } 91 | 92 | BWSR_InlineHook( creat, hcreat, &original_creat, NULL, NULL ); 93 | ``` 94 | 95 | 96 | ### Codesign Friendly 97 | On iOS it may be benefitial to know the address of the page where the hook is employed before or after the hook is written out. In the snippet below, is an example of a callback triggered before and after the modification of the code page is done. 98 | ```c 99 | void BeforePageWriteCallbackFn( uintptr_t PageAddress ) { 100 | BWSR_DEBUG( LOG_CRITICAL, "PageAddress: %" PRIuPTR "\n", PageAddress ); 101 | /// Do something before the write occurs. 102 | } 103 | 104 | void AfterPageWriteCallbackFn( uintptr_t PageAddress ) { 105 | BWSR_DEBUG( LOG_ALERT, "PageAddress: %" PRIuPTR "\n", PageAddress ); 106 | // Do something after the write occurs... 107 | // Update CDHashes, etc. 108 | } 109 | 110 | BWSR_InlineHook( printf, hook_printf, NULL, BeforePageWriteCallbackFn, AfterPageWriteCallbackFn ); 111 | ``` 112 | 113 | ### Simple Hook Cleanup 114 | It may be benefitial to undo all hooks and release all memory associated with hooks at once. This can be done at any time through one simple call. 115 | ```c 116 | BWSR_DestroyAllHooks(); 117 | ``` 118 | 119 | ## Memory Tracker 120 | > [!IMPORTANT] 121 | > The memory tracker is only used when `DEBUG_MODE` is defined. It is not used for release builds. 122 | 123 | The memory tracker was built to ensure all memory leaks are resolved. In order for the memory tracker to successfully track allocations the calls BWSR allocation and free calls be used. The current allocations/leaked memory at any time with a simple call. 124 | ```c 125 | size_t leaks = 0; 126 | 127 | leaks = MemoryTracker_CheckForMemoryLeaks(); 128 | 129 | if( leaks > 0 ) 130 | { 131 | // Uh-oh! 132 | } 133 | ``` 134 | 135 | ## TODO 136 | The list of items that needs to be done is far longer than this list, but these are these are the next important goals: 137 | - Dynamic entitlements for iOS. 138 | 139 | ## ACKNOWLEDGMENTS 140 | - https://github.com/kubo/plthook/ 141 | - https://github.com/jmpews/Dobby 142 | - https://github.com/asLody/whale -------------------------------------------------------------------------------- /SymbolResolve/Darwin/LCStrings.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __LCSTRINGS_H__ 3 | #define __LCSTRINGS_H__ 4 | 5 | #define LOAD_COMMAND_STRINGS( E ) \ 6 | E( LC_SEGMENT, "segment of this file to be mapped" ) \ 7 | E( LC_SYMTAB, "link-edit stab symbol table info" ) \ 8 | E( LC_SYMSEG, "link-edit gdb symbol table info " \ 9 | "(obsolete)" ) \ 10 | E( LC_THREAD, "thread" ) \ 11 | E( LC_UNIXTHREAD, "unix thread (includes a stack)" ) \ 12 | E( LC_LOADFVMLIB, "load a specified fixed VM shared library" ) \ 13 | E( LC_IDFVMLIB, "fixed VM shared library identification" ) \ 14 | E( LC_IDENT, "object identification info (obsolete)" ) \ 15 | E( LC_FVMFILE, "fixed VM file inclusion (internal use)" ) \ 16 | E( LC_PREPAGE, "prepage command (internal use)" ) \ 17 | E( LC_DYSYMTAB, "dynamic link-edit symbol table info" ) \ 18 | E( LC_LOAD_DYLIB, "load a dynamically linked shared library" ) \ 19 | E( LC_ID_DYLIB, "dynamically linked shared lib ident" ) \ 20 | E( LC_LOAD_DYLINKER, "load a dynamic linker" ) \ 21 | E( LC_ID_DYLINKER, "dynamic linker identification" ) \ 22 | E( LC_PREBOUND_DYLIB, "modules prebound for a dynamically " \ 23 | "linked shared library" ) \ 24 | E( LC_ROUTINES, "image routines" ) \ 25 | E( LC_SUB_FRAMEWORK, "sub framework" ) \ 26 | E( LC_SUB_UMBRELLA, "sub umbrella" ) \ 27 | E( LC_SUB_CLIENT, "sub client" ) \ 28 | E( LC_SUB_LIBRARY, "sub library" ) \ 29 | E( LC_TWOLEVEL_HINTS, "two-level namespace lookup hints" ) \ 30 | E( LC_PREBIND_CKSUM, "prebind checksum" ) \ 31 | E( LC_LOAD_WEAK_DYLIB, "load a dynamically linked shared library " \ 32 | "that is allowed to be missing (all " \ 33 | "symbols are weak imported)." ) \ 34 | E( LC_SEGMENT_64, "64-bit segment of this file to be mapped" ) \ 35 | E( LC_ROUTINES_64, "64-bit image routines" ) \ 36 | E( LC_UUID, "the uuid" ) \ 37 | E( LC_RPATH, "runpath additions" ) \ 38 | E( LC_CODE_SIGNATURE, "local of code signature" ) \ 39 | E( LC_SEGMENT_SPLIT_INFO, "local of info to split segments" ) \ 40 | E( LC_REEXPORT_DYLIB, "load and re-export dylib" ) \ 41 | E( LC_LAZY_LOAD_DYLIB, "delay load of dylib until first use" ) \ 42 | E( LC_ENCRYPTION_INFO, "encrypted segment information" ) \ 43 | E( LC_DYLD_INFO, "compressed dyld information" ) \ 44 | E( LC_DYLD_INFO_ONLY, "compressed dyld information only" ) \ 45 | E( LC_LOAD_UPWARD_DYLIB, "load upward dylib" ) \ 46 | E( LC_VERSION_MIN_MACOSX, "build for MacOSX min OS version" ) \ 47 | E( LC_VERSION_MIN_IPHONEOS, "build for iPhoneOS min OS version" ) \ 48 | E( LC_FUNCTION_STARTS, "compressed table of function start " \ 49 | "addresses" ) \ 50 | E( LC_DYLD_ENVIRONMENT, "string for dyld to treat like " \ 51 | "environment variable" ) \ 52 | E( LC_MAIN, "replacement for LC_UNIXTHREAD" ) \ 53 | E( LC_DATA_IN_CODE, "table of non-instructions in __text" ) \ 54 | E( LC_SOURCE_VERSION, "source version used to build binary" ) \ 55 | E( LC_DYLIB_CODE_SIGN_DRS, "Code signing DRs copied from linked " \ 56 | "dylibs" ) \ 57 | E( LC_ENCRYPTION_INFO_64, "64-bit encrypted segment information" ) \ 58 | E( LC_LINKER_OPTION, "linker options in MH_OBJECT files" ) \ 59 | E( LC_LINKER_OPTIMIZATION_HINT, "optimization hints in MH_OBJECT files" ) \ 60 | E( LC_VERSION_MIN_TVOS, "build for AppleTV min OS version" ) \ 61 | E( LC_VERSION_MIN_WATCHOS, "build for Watch min OS version" ) \ 62 | E( LC_NOTE, "arbitrary data included within a Mach-O " \ 63 | "file" ) \ 64 | E( LC_BUILD_VERSION, "build for platform min OS version" ) \ 65 | E( LC_DYLD_EXPORTS_TRIE, "used with linkedit_data_command, payload " \ 66 | "is trie" ) \ 67 | E( LC_DYLD_CHAINED_FIXUPS, "used with linkedit_data_command" ) \ 68 | E( LC_FILESET_ENTRY, "used with fileset_entry_command" ) \ 69 | E( LC_ATOM_INFO, "used with linkedit_data_command" ) 70 | 71 | #define LOAD_COMMAND_TO_TEXT( LOAD_COMMAND, TEXT ) \ 72 | case LOAD_COMMAND: return #LOAD_COMMAND " (" TEXT ")"; 73 | 74 | static inline const char* LoadCommandString( int LoadCommand ) 75 | { 76 | switch( LoadCommand ) 77 | { 78 | LOAD_COMMAND_STRINGS( LOAD_COMMAND_TO_TEXT ) 79 | } 80 | 81 | return "Unknown Load Command!"; 82 | } 83 | 84 | #endif __LCSTRINGS_H__ -------------------------------------------------------------------------------- /SymbolResolve/Darwin/Macho.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MACHO_H__ 3 | #define __MACHO_H__ 4 | 5 | int 6 | BWSR_ResolveSymbol 7 | ( 8 | const char* SymbolName, 9 | const char* ImageName, 10 | uintptr_t* Address 11 | ); 12 | 13 | #endif // __MACHO_H__ 14 | -------------------------------------------------------------------------------- /SymbolResolve/Linux/Elf.c: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // INCLUDES 4 | // ----------------------------------------------------------------------------- 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "utility/debug.h" 21 | #include "utility/error.h" 22 | #include "utility/utility.h" 23 | 24 | #include "Memory/Memory.h" 25 | 26 | // ----------------------------------------------------------------------------- 27 | // STRUCTURES & DEFINITIONS 28 | // ----------------------------------------------------------------------------- 29 | 30 | #ifndef LINE_MAX 31 | #define LINE_MAX ( 1024 ) 32 | #endif 33 | 34 | #define EXTENSION_LENGTH ( 7 ) 35 | #define MODULE_BASE_CAPACITY ( 16 ) 36 | 37 | #if defined(__LP64__) 38 | 39 | typedef Elf64_Shdr elf_shdr_t; 40 | typedef Elf64_Sym elf_sym_t; 41 | typedef Elf64_Addr elf_addr_t; 42 | typedef Elf64_Dyn elf_dyn_t; 43 | typedef Elf64_Phdr elf_phdr_t; 44 | typedef Elf64_Ehdr elf_ehdr_t; 45 | 46 | #else 47 | 48 | typedef Elf32_Shdr elf_shdr_t; 49 | typedef Elf32_Sym elf_sym_t; 50 | typedef Elf32_Addr elf_addr_t; 51 | typedef Elf32_Dyn elf_dyn_t; 52 | typedef Elf32_Phdr elf_phdr_t; 53 | typedef Elf32_Ehdr elf_ehdr_t; 54 | 55 | #endif 56 | 57 | typedef struct elf_ctx { 58 | void* Header; 59 | 60 | uintptr_t LoadBias; 61 | 62 | elf_shdr_t* SymbolSh; 63 | elf_shdr_t* DynamicSymbolSh; 64 | 65 | const char* StringTable; 66 | elf_sym_t* SymbolTable; 67 | 68 | const char* DynamicStringTable; 69 | elf_sym_t* DynamicSymbolTable; 70 | } elf_ctx_t; 71 | 72 | typedef struct runtime_module_t { 73 | void* Base; 74 | char Path[ 1024 ]; 75 | } runtime_module_t; 76 | 77 | // ----------------------------------------------------------------------------- 78 | // GLOBALS 79 | // ----------------------------------------------------------------------------- 80 | 81 | static struct { 82 | runtime_module_t* Data; 83 | size_t Size; 84 | size_t Capacity; 85 | } modules = { 86 | NULL, 87 | 0, 88 | 0 89 | }; 90 | 91 | // ----------------------------------------------------------------------------- 92 | // IMPLEMENTATION 93 | // ----------------------------------------------------------------------------- 94 | 95 | static 96 | BWSR_STATUS 97 | INTERNAL_AppendRuntimeModule 98 | ( 99 | IN runtime_module_t Module 100 | ) 101 | { 102 | BWSR_STATUS retVal = ERROR_FAILURE; 103 | runtime_module_t* runtimeModule = NULL; 104 | size_t allocationSize = 0; 105 | 106 | if( NULL == modules.Data ) 107 | { 108 | modules.Capacity = MODULE_BASE_CAPACITY; 109 | allocationSize = modules.Capacity * sizeof( runtime_module_t ); 110 | 111 | if( NULL == ( modules.Data = BwsrMalloc( allocationSize ) ) ) 112 | { 113 | BWSR_DEBUG( LOG_ERROR, "BwsrMalloc() Failed\n" ); 114 | retVal = ERROR_MEM_ALLOC; 115 | } 116 | else { 117 | retVal = ERROR_SUCCESS; 118 | } // BwsrMalloc() 119 | } 120 | else if( modules.Size >= modules.Capacity ) 121 | { 122 | modules.Capacity *= 2; 123 | allocationSize = modules.Capacity * sizeof( runtime_module_t ); 124 | 125 | if( NULL == ( runtimeModule = BwsrRealloc( modules.Data, allocationSize ) ) ) 126 | { 127 | BWSR_DEBUG( LOG_ERROR, "BwsrRealloc() Failed\n" ); 128 | retVal = ERROR_MEM_ALLOC; 129 | } 130 | else { 131 | modules.Data = runtimeModule; 132 | retVal = ERROR_SUCCESS; 133 | } // BwsrRealloc() 134 | } 135 | else { 136 | retVal = ERROR_SUCCESS; 137 | } // Module Capacity 138 | 139 | if( ERROR_SUCCESS == retVal ) 140 | { 141 | modules.Data[ modules.Size++ ] = Module; 142 | } 143 | 144 | return retVal; 145 | } 146 | 147 | static 148 | void 149 | INTERNAL_ReleaseRuntimeModules 150 | ( 151 | void 152 | ) 153 | { 154 | BwsrFree( modules.Data ); 155 | modules.Data = NULL; 156 | modules.Size = 0; 157 | modules.Capacity = 0; 158 | } 159 | 160 | static 161 | BWSR_STATUS 162 | INTERNAL_GetProcessMap_ProcSelfMaps 163 | ( 164 | void 165 | ) 166 | { 167 | BWSR_STATUS retVal = ERROR_FAILURE; 168 | FILE* fp = NULL; 169 | char line_buffer[ LINE_MAX + 1 ] = { 0 }; 170 | uintptr_t region_start = 0; 171 | uintptr_t region_end = 0; 172 | uintptr_t region_offset = 0; 173 | char permissions[ 5 ] = { 0 }; 174 | uint8_t dev_major = 0; 175 | uint8_t dev_minor = 0; 176 | long inode = 0; 177 | int path_index = 0; 178 | char* path_buffer = NULL; 179 | 180 | if( NULL == ( fp = fopen( "/proc/self/maps", "r" ) ) ) 181 | { 182 | BWSR_DEBUG( LOG_ERROR, "fopen() Failed\n" ); 183 | retVal = ERROR_PROC_SELF_MAPS; 184 | } 185 | else { 186 | retVal = ERROR_SUCCESS; 187 | 188 | while( !feof( fp ) && ERROR_SUCCESS == retVal ) 189 | { 190 | memset( line_buffer, 0, sizeof( line_buffer ) ); 191 | 192 | if( NULL == fgets( line_buffer, 193 | sizeof( line_buffer ), 194 | fp ) ) 195 | { 196 | break; 197 | } 198 | 199 | if( ( LINE_MAX == strnlen( line_buffer, LINE_MAX ) ) && 200 | ( '\n' != line_buffer[ LINE_MAX ] ) ) 201 | { 202 | int c = 0; 203 | 204 | do 205 | { 206 | c = getc( fp ); 207 | } while( ( EOF != c ) && ( '\n' != c ) ); 208 | 209 | if( EOF == c ) 210 | { 211 | break; 212 | } 213 | } 214 | 215 | if( 7 > sscanf( line_buffer, 216 | "%lx-%lx %4c %lx %hhx:%hhx %ld %n", 217 | ®ion_start, 218 | ®ion_end, 219 | permissions, 220 | ®ion_offset, 221 | &dev_major, 222 | &dev_minor, 223 | &inode, 224 | &path_index ) ) 225 | { 226 | BWSR_DEBUG( LOG_ERROR, "sscanf() Failed\n" ); 227 | INTERNAL_ReleaseRuntimeModules( ); 228 | retVal = ERROR_UNEXPECTED_FORMAT; 229 | } 230 | else { 231 | if( ( 0 != strcmp( permissions, "r--p" ) ) && 232 | ( 0 != strcmp( permissions, "r-xp" ) ) ) 233 | { 234 | continue; 235 | } 236 | 237 | if( 0 != memcmp( ( (Elf64_Ehdr*) region_start )->e_ident, 238 | ELFMAG, 239 | SELFMAG ) ) 240 | { 241 | continue; 242 | } 243 | 244 | path_buffer = line_buffer + path_index; 245 | 246 | if( ( 0 == *path_buffer ) || 247 | ( '\n' == *path_buffer ) || 248 | ( '[' == *path_buffer ) ) 249 | { 250 | continue; 251 | } 252 | 253 | if( '\n' == path_buffer[ strlen( path_buffer ) - 1 ] ) 254 | { 255 | path_buffer[ strlen( path_buffer ) - 1 ] = 0x00; 256 | } 257 | 258 | runtime_module_t module; 259 | 260 | strncpy( module.Path, 261 | path_buffer, 262 | sizeof( module.Path ) - 1 ); 263 | 264 | module.Base = (void*) region_start; 265 | 266 | retVal = INTERNAL_AppendRuntimeModule( module ); 267 | } // sscanf() 268 | } // while() 269 | 270 | fclose( fp ); 271 | } // fopen() 272 | 273 | return retVal; 274 | } 275 | 276 | static 277 | void 278 | INTERNAL_ElfContext_Initialize 279 | ( 280 | OUT elf_ctx_t* Context, 281 | IN const void* Header 282 | ) 283 | { 284 | size_t i = 0; 285 | elf_phdr_t* phdr = NULL; 286 | elf_shdr_t* shstr_sh = NULL; 287 | char* shstrtab = NULL; 288 | elf_shdr_t* shdr = NULL; 289 | elf_ehdr_t* ehdr = NULL; 290 | elf_addr_t ehdr_addr = 0; 291 | 292 | __NOT_NULL_RETURN_VOID( Context, Header ); 293 | 294 | ehdr = (elf_ehdr_t*) Header; 295 | ehdr_addr = (elf_addr_t) ehdr; 296 | Context->Header = ehdr; 297 | 298 | // Dynamic Segment 299 | { 300 | phdr = (elf_phdr_t*) ( ehdr_addr + ehdr->e_phoff ); 301 | 302 | for( i = 0; i < ehdr->e_phnum; i++ ) 303 | { 304 | if( ( PT_LOAD == phdr[ i ].p_type ) && 305 | ( 0 == Context->LoadBias ) ) 306 | { 307 | Context->LoadBias = ehdr_addr - ( phdr[ i ].p_vaddr - phdr[ i ].p_offset ); 308 | } 309 | else if( PT_PHDR == phdr[ i ].p_type ) 310 | { 311 | Context->LoadBias = (elf_addr_t) phdr - phdr[ i ].p_vaddr; 312 | } // P Type 313 | } // for() 314 | } // Dynamic Segment 315 | 316 | // Section 317 | { 318 | shdr = (elf_shdr_t*) ( ehdr_addr + ehdr->e_shoff ); 319 | shstr_sh = &shdr[ ehdr->e_shstrndx ]; 320 | shstrtab = (char*) ( (uintptr_t) ehdr_addr + shstr_sh->sh_offset ); 321 | 322 | for( i = 0; i < ehdr->e_shnum; i++ ) 323 | { 324 | if( SHT_SYMTAB == shdr[ i ].sh_type ) 325 | { 326 | Context->SymbolSh = &shdr[ i ]; 327 | Context->SymbolTable = (elf_sym_t*) ( ehdr_addr + shdr[ i ].sh_offset ); 328 | } 329 | else if( ( SHT_STRTAB == shdr[ i ].sh_type ) && 330 | ( 0 == strncmp( ( shstrtab + shdr[ i ].sh_name ), 331 | ".strtab", 332 | EXTENSION_LENGTH ) ) ) 333 | { 334 | Context->StringTable = (const char*) ( ehdr_addr + shdr[ i ].sh_offset ); 335 | } 336 | else if( SHT_DYNSYM == shdr[ i ].sh_type ) 337 | { 338 | Context->DynamicSymbolSh = &shdr[ i ]; 339 | Context->DynamicSymbolTable = (elf_sym_t*) ( ehdr_addr + shdr[ i ].sh_offset ); 340 | } 341 | else if( ( SHT_STRTAB == shdr[ i ].sh_type ) && 342 | ( 0 == strncmp( ( shstrtab + shdr[ i ].sh_name ), 343 | ".dynstr", 344 | EXTENSION_LENGTH ) ) ) 345 | { 346 | Context->DynamicStringTable = (const char*) ( ehdr_addr + shdr[ i ].sh_offset ); 347 | } // SH Type 348 | } // for() 349 | } // Section 350 | } 351 | 352 | static 353 | BWSR_STATUS 354 | INTERNAL_MMapModulePath 355 | ( 356 | OUT uint8_t** MMapBuffer, 357 | OUT size_t* MMapBufferSize, 358 | IN const uint8_t* ModulePath 359 | ) 360 | { 361 | BWSR_STATUS retVal = ERROR_FAILURE; 362 | size_t file_size = 0; 363 | struct stat s = { 0 }; 364 | int fd = 0; 365 | 366 | __NOT_NULL( MMapBuffer, ModulePath ) 367 | 368 | if( 0 != stat( (const char*) ModulePath, &s ) ) 369 | { 370 | BWSR_DEBUG( LOG_ERROR, "stat() Failed\n" ); 371 | retVal = ERROR_FILE_IO; 372 | } 373 | else { 374 | file_size = s.st_size; 375 | 376 | if( 0 > ( fd = open( (const char*) ModulePath, 377 | O_RDONLY, 378 | 0 ) ) ) 379 | { 380 | BWSR_DEBUG( LOG_ERROR, "open() Failed\n" ); 381 | retVal = ERROR_FILE_IO; 382 | } 383 | else { 384 | if( MAP_FAILED == ( *MMapBuffer = (uint8_t*) mmap( 0, 385 | file_size, 386 | ( PROT_READ | PROT_WRITE ), 387 | MAP_PRIVATE, 388 | fd, 389 | 0 ) ) ) 390 | { 391 | BWSR_DEBUG( LOG_ERROR, "mmap() Failed\n" ); 392 | retVal = ERROR_MEMORY_MAPPING; 393 | } 394 | else { 395 | if( NULL != MMapBufferSize ) 396 | { 397 | *MMapBufferSize = file_size; 398 | } // mmap_buffer_size 399 | 400 | retVal = ERROR_SUCCESS; 401 | } // mmap() 402 | 403 | close(fd); 404 | } // open() 405 | } // stat() 406 | 407 | return retVal; 408 | } 409 | 410 | static 411 | BWSR_STATUS 412 | INTERNAL_GetValueFromSymbolTable 413 | ( 414 | IN const char* SymbolName, 415 | IN elf_sym_t* SymbolTable, 416 | IN const char* StringTable, 417 | IN size_t Count, 418 | OUT void** Value 419 | ) 420 | { 421 | BWSR_STATUS retVal = ERROR_FAILURE; 422 | size_t i = 0; 423 | elf_sym_t* sym = NULL; 424 | char* symbol_name = NULL; 425 | 426 | __NOT_NULL( SymbolName, 427 | SymbolTable, 428 | StringTable, 429 | Value ) 430 | __GREATER_THAN_0( Count ) 431 | 432 | retVal = ERROR_NOT_FOUND; 433 | *Value = NULL; 434 | 435 | for( i = 0; ( i < Count ) && ( ERROR_NOT_FOUND == retVal ); ++i ) 436 | { 437 | sym = SymbolTable + i; 438 | symbol_name = (char*) StringTable + sym->st_name; 439 | 440 | if( 0 == strcmp( (const char*) symbol_name, SymbolName ) ) 441 | { 442 | retVal = ERROR_SUCCESS; 443 | *Value = (void*) sym->st_value; 444 | } // strcmp() 445 | } // for() 446 | 447 | return retVal; 448 | } 449 | 450 | static 451 | BWSR_STATUS 452 | INTERNAL_ElfContext_GetValueFromSymbolTable 453 | ( 454 | IN elf_ctx_t* Context, 455 | IN const char* SymbolName, 456 | OUT void** Result 457 | ) 458 | { 459 | BWSR_STATUS retVal = ERROR_FAILURE; 460 | size_t count = 0; 461 | 462 | __NOT_NULL( Context, 463 | SymbolName, 464 | Result ) 465 | 466 | if( ( NULL != Context->SymbolTable ) && 467 | ( NULL != Context->StringTable ) ) 468 | { 469 | count = Context->SymbolSh->sh_size / sizeof( elf_sym_t ); 470 | 471 | retVal = INTERNAL_GetValueFromSymbolTable( SymbolName, 472 | Context->SymbolTable, 473 | Context->StringTable, 474 | count, 475 | Result ); 476 | } 477 | 478 | if( ERROR_SUCCESS != retVal ) 479 | { 480 | if( ( NULL != Context->DynamicSymbolTable ) && 481 | ( NULL != Context->DynamicStringTable ) ) 482 | { 483 | count = Context->DynamicSymbolSh->sh_size / sizeof( elf_sym_t ); 484 | 485 | retVal = INTERNAL_GetValueFromSymbolTable( SymbolName, 486 | Context->DynamicSymbolTable, 487 | Context->DynamicStringTable, 488 | count, 489 | Result ); 490 | } 491 | } 492 | 493 | return retVal; 494 | } 495 | 496 | static 497 | BWSR_STATUS 498 | INTERNAL_ResolveSymbol 499 | ( 500 | IN const char* LibraryName, 501 | IN const char* SymbolName, 502 | OUT uintptr_t* Address 503 | ) 504 | { 505 | BWSR_STATUS retVal = ERROR_FAILURE; 506 | uint8_t* file_mem = NULL; 507 | size_t i = 0; 508 | runtime_module_t* module = NULL; 509 | elf_ctx_t context = { 0 }; 510 | 511 | __NOT_NULL( SymbolName, Address ) 512 | 513 | *Address = 0; 514 | 515 | for( i = 0; ( i < modules.Size ) && ( 0 == *Address ); i++ ) 516 | { 517 | module = &modules.Data[ i ]; 518 | 519 | if( ( NULL != LibraryName ) && 520 | ( 0 != strncmp( LibraryName, 521 | modules.Data[ i ].Path, 522 | PATH_MAX ) ) ) 523 | { 524 | continue; 525 | } // strncmp() 526 | 527 | if( module->Base ) 528 | { 529 | if( ERROR_SUCCESS != ( retVal = INTERNAL_MMapModulePath( &file_mem, 530 | NULL, 531 | (const uint8_t*) module->Path ) ) ) 532 | { 533 | BWSR_DEBUG( LOG_ERROR, "INTERNAL_MMapModulePath() Failed\n" ); 534 | } 535 | else { 536 | memset( &context, 537 | 0, 538 | sizeof( elf_ctx_t ) ); 539 | 540 | INTERNAL_ElfContext_Initialize( &context, file_mem ); 541 | 542 | if( ERROR_SUCCESS != ( retVal = INTERNAL_ElfContext_GetValueFromSymbolTable( &context, 543 | SymbolName, 544 | (void**) Address ) ) ) 545 | { 546 | BWSR_DEBUG( LOG_WARNING, "INTERNAL_ElfContext_GetValueFromSymbolTable() Failed. Retrying.\n" ); 547 | } 548 | else { 549 | if( *Address ) 550 | { 551 | *Address = ( (uintptr_t) *Address 552 | + (uintptr_t) module->Base 553 | - ( (uintptr_t) file_mem - (uintptr_t) context.LoadBias ) ); 554 | retVal = ERROR_SUCCESS; 555 | } // Address 556 | } // INTERNAL_ElfContext_GetValueFromSymbolTable() 557 | } // INTERNAL_MMapModulePath() 558 | } // module->Base 559 | } // for() 560 | 561 | if( 0 == *Address ) 562 | { 563 | retVal = ERROR_NOT_FOUND; 564 | } // Address 565 | 566 | return retVal; 567 | } 568 | 569 | BWSR_API 570 | BWSR_STATUS 571 | BWSR_ResolveSymbol 572 | ( 573 | IN const char* SymbolName, 574 | IN OPTIONAL const char* ImageName, 575 | OUT uintptr_t* Address 576 | ) 577 | { 578 | BWSR_STATUS retVal = ERROR_FAILURE; 579 | 580 | __NOT_NULL( SymbolName, Address ) 581 | 582 | INTERNAL_GetProcessMap_ProcSelfMaps(); 583 | 584 | retVal = INTERNAL_ResolveSymbol( ImageName, 585 | SymbolName, 586 | Address ); 587 | 588 | INTERNAL_ReleaseRuntimeModules(); 589 | 590 | __DEBUG_RETVAL( retVal ) 591 | return retVal; 592 | } 593 | -------------------------------------------------------------------------------- /SymbolResolve/Linux/Elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_H__ 2 | #define __ELF_H__ 3 | 4 | int 5 | BWSR_ResolveSymbol 6 | ( 7 | const char* SymbolName, 8 | const char* ImageName, 9 | uintptr_t* Address 10 | ); 11 | 12 | #endif // __MACHO_H__ -------------------------------------------------------------------------------- /apple/cs_blobs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | 29 | #ifndef _KERN_CODESIGN_H_ 30 | #define _KERN_CODESIGN_H_ 31 | 32 | #include 33 | #include 34 | 35 | /* code signing attributes of a process */ 36 | #define CS_VALID 0x00000001 /* dynamically valid */ 37 | #define CS_ADHOC 0x00000002 /* ad hoc signed */ 38 | #define CS_GET_TASK_ALLOW 0x00000004 /* has get-task-allow entitlement */ 39 | #define CS_INSTALLER 0x00000008 /* has installer entitlement */ 40 | 41 | #define CS_FORCED_LV 0x00000010 /* Library Validation required by Hardened System Policy */ 42 | #define CS_INVALID_ALLOWED 0x00000020 /* (macOS Only) Page invalidation allowed by task port policy */ 43 | 44 | #define CS_HARD 0x00000100 /* don't load invalid pages */ 45 | #define CS_KILL 0x00000200 /* kill process if it becomes invalid */ 46 | #define CS_CHECK_EXPIRATION 0x00000400 /* force expiration checking */ 47 | #define CS_RESTRICT 0x00000800 /* tell dyld to treat restricted */ 48 | 49 | #define CS_ENFORCEMENT 0x00001000 /* require enforcement */ 50 | #define CS_REQUIRE_LV 0x00002000 /* require library validation */ 51 | #define CS_ENTITLEMENTS_VALIDATED 0x00004000 /* code signature permits restricted entitlements */ 52 | #define CS_NVRAM_UNRESTRICTED 0x00008000 /* has com.apple.rootless.restricted-nvram-variables.heritable entitlement */ 53 | 54 | #define CS_RUNTIME 0x00010000 /* Apply hardened runtime policies */ 55 | #define CS_LINKER_SIGNED 0x00020000 /* Automatically signed by the linker */ 56 | 57 | #define CS_ALLOWED_MACHO (CS_ADHOC | CS_HARD | CS_KILL | CS_CHECK_EXPIRATION | \ 58 | CS_RESTRICT | CS_ENFORCEMENT | CS_REQUIRE_LV | CS_RUNTIME | CS_LINKER_SIGNED) 59 | 60 | #define CS_EXEC_SET_HARD 0x00100000 /* set CS_HARD on any exec'ed process */ 61 | #define CS_EXEC_SET_KILL 0x00200000 /* set CS_KILL on any exec'ed process */ 62 | #define CS_EXEC_SET_ENFORCEMENT 0x00400000 /* set CS_ENFORCEMENT on any exec'ed process */ 63 | #define CS_EXEC_INHERIT_SIP 0x00800000 /* set CS_INSTALLER on any exec'ed process */ 64 | 65 | #define CS_KILLED 0x01000000 /* was killed by kernel for invalidity */ 66 | #define CS_NO_UNTRUSTED_HELPERS 0x02000000 /* kernel did not load a non-platform-binary dyld or Rosetta runtime */ 67 | #define CS_DYLD_PLATFORM CS_NO_UNTRUSTED_HELPERS /* old name */ 68 | #define CS_PLATFORM_BINARY 0x04000000 /* this is a platform binary */ 69 | #define CS_PLATFORM_PATH 0x08000000 /* platform binary by the fact of path (osx only) */ 70 | 71 | #define CS_DEBUGGED 0x10000000 /* process is currently or has previously been debugged and allowed to run with invalid pages */ 72 | #define CS_SIGNED 0x20000000 /* process has a signature (may have gone invalid) */ 73 | #define CS_DEV_CODE 0x40000000 /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */ 74 | #define CS_DATAVAULT_CONTROLLER 0x80000000 /* has Data Vault controller entitlement */ 75 | 76 | #define CS_ENTITLEMENT_FLAGS (CS_GET_TASK_ALLOW | CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_NVRAM_UNRESTRICTED) 77 | 78 | /* executable segment flags */ 79 | 80 | #define CS_EXECSEG_MAIN_BINARY 0x1 /* executable segment denotes main binary */ 81 | #define CS_EXECSEG_ALLOW_UNSIGNED 0x10 /* allow unsigned pages (for debugging) */ 82 | #define CS_EXECSEG_DEBUGGER 0x20 /* main binary is debugger */ 83 | #define CS_EXECSEG_JIT 0x40 /* JIT enabled */ 84 | #define CS_EXECSEG_SKIP_LV 0x80 /* OBSOLETE: skip library validation */ 85 | #define CS_EXECSEG_CAN_LOAD_CDHASH 0x100 /* can bless cdhash for execution */ 86 | #define CS_EXECSEG_CAN_EXEC_CDHASH 0x200 /* can execute blessed cdhash */ 87 | 88 | /* 89 | * Magic numbers used by Code Signing 90 | */ 91 | enum { 92 | CSMAGIC_REQUIREMENT = 0xfade0c00, /* single Requirement blob */ 93 | CSMAGIC_REQUIREMENTS = 0xfade0c01, /* Requirements vector (internal requirements) */ 94 | CSMAGIC_CODEDIRECTORY = 0xfade0c02, /* CodeDirectory blob */ 95 | CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, /* embedded form of signature data */ 96 | CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02, /* XXX */ 97 | CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171, /* embedded entitlements */ 98 | CSMAGIC_EMBEDDED_DER_ENTITLEMENTS = 0xfade7172, /* embedded DER encoded entitlements */ 99 | CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1, /* multi-arch collection of embedded signatures */ 100 | CSMAGIC_BLOBWRAPPER = 0xfade0b01, /* CMS Signature, among other things */ 101 | CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT = 0xfade8181, /* Light weight code requirement */ 102 | 103 | CS_SUPPORTSSCATTER = 0x20100, 104 | CS_SUPPORTSTEAMID = 0x20200, 105 | CS_SUPPORTSCODELIMIT64 = 0x20300, 106 | CS_SUPPORTSEXECSEG = 0x20400, 107 | CS_SUPPORTSRUNTIME = 0x20500, 108 | CS_SUPPORTSLINKAGE = 0x20600, 109 | 110 | CSSLOT_CODEDIRECTORY = 0, /* slot index for CodeDirectory */ 111 | CSSLOT_INFOSLOT = 1, 112 | CSSLOT_REQUIREMENTS = 2, 113 | CSSLOT_RESOURCEDIR = 3, 114 | CSSLOT_APPLICATION = 4, 115 | CSSLOT_ENTITLEMENTS = 5, 116 | CSSLOT_DER_ENTITLEMENTS = 7, 117 | CSSLOT_LAUNCH_CONSTRAINT_SELF = 8, 118 | CSSLOT_LAUNCH_CONSTRAINT_PARENT = 9, 119 | CSSLOT_LAUNCH_CONSTRAINT_RESPONSIBLE = 10, 120 | CSSLOT_LIBRARY_CONSTRAINT = 11, 121 | 122 | CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */ 123 | CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, /* max number of alternate CD slots */ 124 | CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */ 125 | 126 | CSSLOT_SIGNATURESLOT = 0x10000, /* CMS Signature */ 127 | CSSLOT_IDENTIFICATIONSLOT = 0x10001, 128 | CSSLOT_TICKETSLOT = 0x10002, 129 | 130 | CSTYPE_INDEX_REQUIREMENTS = 0x00000002, /* compat with amfi */ 131 | CSTYPE_INDEX_ENTITLEMENTS = 0x00000005, /* compat with amfi */ 132 | 133 | CS_HASHTYPE_SHA1 = 1, 134 | CS_HASHTYPE_SHA256 = 2, 135 | CS_HASHTYPE_SHA256_TRUNCATED = 3, 136 | CS_HASHTYPE_SHA384 = 4, 137 | 138 | CS_SHA1_LEN = 20, 139 | CS_SHA256_LEN = 32, 140 | CS_SHA256_TRUNCATED_LEN = 20, 141 | 142 | CS_CDHASH_LEN = 20, /* always - larger hashes are truncated */ 143 | CS_HASH_MAX_SIZE = 48, /* max size of the hash we'll support */ 144 | 145 | /* 146 | * Currently only to support Legacy VPN plugins, and Mac App Store 147 | * but intended to replace all the various platform code, dev code etc. bits. 148 | */ 149 | CS_SIGNER_TYPE_UNKNOWN = 0, 150 | CS_SIGNER_TYPE_LEGACYVPN = 5, 151 | CS_SIGNER_TYPE_MAC_APP_STORE = 6, 152 | 153 | CS_SUPPL_SIGNER_TYPE_UNKNOWN = 0, 154 | CS_SUPPL_SIGNER_TYPE_TRUSTCACHE = 7, 155 | CS_SUPPL_SIGNER_TYPE_LOCAL = 8, 156 | 157 | CS_SIGNER_TYPE_OOPJIT = 9, 158 | 159 | /* Validation categories used for trusted launch environment */ 160 | CS_VALIDATION_CATEGORY_INVALID = 0, 161 | CS_VALIDATION_CATEGORY_PLATFORM = 1, 162 | CS_VALIDATION_CATEGORY_TESTFLIGHT = 2, 163 | CS_VALIDATION_CATEGORY_DEVELOPMENT = 3, 164 | CS_VALIDATION_CATEGORY_APP_STORE = 4, 165 | CS_VALIDATION_CATEGORY_ENTERPRISE = 5, 166 | CS_VALIDATION_CATEGORY_DEVELOPER_ID = 6, 167 | CS_VALIDATION_CATEGORY_LOCAL_SIGNING = 7, 168 | CS_VALIDATION_CATEGORY_ROSETTA = 8, 169 | CS_VALIDATION_CATEGORY_OOPJIT = 9, 170 | CS_VALIDATION_CATEGORY_NONE = 10, 171 | }; 172 | 173 | /* The set of application types we support for linkage signatures */ 174 | enum { 175 | CS_LINKAGE_APPLICATION_INVALID = 0, 176 | CS_LINKAGE_APPLICATION_ROSETTA = 1, 177 | 178 | /* XOJIT has been renamed to OOP-JIT */ 179 | CS_LINKAGE_APPLICATION_XOJIT = 2, 180 | CS_LINKAGE_APPLICATION_OOPJIT = 2, 181 | }; 182 | 183 | /* The set of application sub-types we support for linkage signatures */ 184 | enum { 185 | /* 186 | * For backwards compatibility with older signatures, the AOT sub-type is kept 187 | * as 0. 188 | */ 189 | CS_LINKAGE_APPLICATION_ROSETTA_AOT = 0, 190 | 191 | /* OOP-JIT sub-types -- XOJIT type kept for external dependencies */ 192 | CS_LINKAGE_APPLICATION_XOJIT_PREVIEWS = 1, 193 | CS_LINKAGE_APPLICATION_OOPJIT_INVALID = 0, 194 | CS_LINKAGE_APPLICATION_OOPJIT_PREVIEWS = 1, 195 | CS_LINKAGE_APPLICATION_OOPJIT_MLCOMPILER = 2, 196 | CS_LINKAGE_APPLICATION_OOPJIT_TOTAL, 197 | }; 198 | 199 | /* Integer to string conversion of OOP-JIT types */ 200 | static const char *oop_jit_conversion[CS_LINKAGE_APPLICATION_OOPJIT_TOTAL] = { 201 | [CS_LINKAGE_APPLICATION_OOPJIT_INVALID] = NULL, 202 | [CS_LINKAGE_APPLICATION_OOPJIT_PREVIEWS] = "previews", 203 | [CS_LINKAGE_APPLICATION_OOPJIT_MLCOMPILER] = "ml-compiler", 204 | }; 205 | 206 | #define KERNEL_HAVE_CS_CODEDIRECTORY 1 207 | #define KERNEL_CS_CODEDIRECTORY_HAVE_PLATFORM 1 208 | 209 | /* 210 | * C form of a CodeDirectory. 211 | */ 212 | typedef struct __CodeDirectory { 213 | uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ 214 | uint32_t length; /* total length of CodeDirectory blob */ 215 | uint32_t version; /* compatibility version */ 216 | uint32_t flags; /* setup and mode flags */ 217 | uint32_t hashOffset; /* offset of hash slot element at index zero */ 218 | uint32_t identOffset; /* offset of identifier string */ 219 | uint32_t nSpecialSlots; /* number of special hash slots */ 220 | uint32_t nCodeSlots; /* number of ordinary (code) hash slots */ 221 | uint32_t codeLimit; /* limit to main image signature range */ 222 | uint8_t hashSize; /* size of each hash in bytes */ 223 | uint8_t hashType; /* type of hash (cdHashType* constants) */ 224 | uint8_t platform; /* platform identifier; zero if not platform binary */ 225 | uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */ 226 | uint32_t spare2; /* unused (must be zero) */ 227 | 228 | char end_earliest[0]; 229 | 230 | /* Version 0x20100 */ 231 | uint32_t scatterOffset; /* offset of optional scatter vector */ 232 | char end_withScatter[0]; 233 | 234 | /* Version 0x20200 */ 235 | uint32_t teamOffset; /* offset of optional team identifier */ 236 | char end_withTeam[0]; 237 | 238 | /* Version 0x20300 */ 239 | uint32_t spare3; /* unused (must be zero) */ 240 | uint64_t codeLimit64; /* limit to main image signature range, 64 bits */ 241 | char end_withCodeLimit64[0]; 242 | 243 | /* Version 0x20400 */ 244 | uint64_t execSegBase; /* offset of executable segment */ 245 | uint64_t execSegLimit; /* limit of executable segment */ 246 | uint64_t execSegFlags; /* executable segment flags */ 247 | char end_withExecSeg[0]; 248 | 249 | /* Version 0x20500 */ 250 | uint32_t runtime; 251 | uint32_t preEncryptOffset; 252 | char end_withPreEncryptOffset[0]; 253 | 254 | /* Version 0x20600 */ 255 | uint8_t linkageHashType; 256 | uint8_t linkageApplicationType; 257 | uint16_t linkageApplicationSubType; 258 | uint32_t linkageOffset; 259 | uint32_t linkageSize; 260 | char end_withLinkage[0]; 261 | 262 | /* followed by dynamic content as located by offset fields above */ 263 | } CS_CodeDirectory 264 | __attribute__ ((aligned(1))); 265 | 266 | /* 267 | * Structure of an embedded-signature SuperBlob 268 | */ 269 | 270 | typedef struct __BlobIndex { 271 | uint32_t type; /* type of entry */ 272 | uint32_t offset; /* offset of entry */ 273 | } CS_BlobIndex 274 | __attribute__ ((aligned(1))); 275 | 276 | typedef struct __SC_SuperBlob { 277 | uint32_t magic; /* magic number */ 278 | uint32_t length; /* total length of SuperBlob */ 279 | uint32_t count; /* number of index entries following */ 280 | CS_BlobIndex index[]; /* (count) entries */ 281 | /* followed by Blobs in no particular order as indicated by offsets in index */ 282 | } CS_SuperBlob 283 | __attribute__ ((aligned(1))); 284 | 285 | #define KERNEL_HAVE_CS_GENERICBLOB 1 286 | typedef struct __SC_GenericBlob { 287 | uint32_t magic; /* magic number */ 288 | uint32_t length; /* total length of blob */ 289 | char data[]; 290 | } CS_GenericBlob 291 | __attribute__ ((aligned(1))); 292 | 293 | typedef struct __SC_Scatter { 294 | uint32_t count; // number of pages; zero for sentinel (only) 295 | uint32_t base; // first page number 296 | uint64_t targetOffset; // offset in target 297 | uint64_t spare; // reserved 298 | } SC_Scatter 299 | __attribute__ ((aligned(1))); 300 | 301 | 302 | /* 303 | * Defined launch types 304 | */ 305 | __enum_decl(cs_launch_type_t, uint8_t, { 306 | CS_LAUNCH_TYPE_NONE = 0, 307 | CS_LAUNCH_TYPE_SYSTEM_SERVICE = 1, 308 | CS_LAUNCH_TYPE_SYSDIAGNOSE = 2, 309 | CS_LAUNCH_TYPE_APPLICATION = 3, 310 | }); 311 | 312 | struct launch_constraint_data { 313 | cs_launch_type_t launch_type; 314 | }; 315 | typedef struct launch_constraint_data* launch_constraint_data_t; 316 | 317 | #endif /* _KERN_CODESIGN_H */ 318 | -------------------------------------------------------------------------------- /apple/dyld_cache_format.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 | * 3 | * Copyright (c) 2006-2015 Apple Inc. All rights reserved. 4 | * 5 | * @APPLE_LICENSE_HEADER_START@ 6 | * 7 | * This file contains Original Code and/or Modifications of Original Code 8 | * as defined in and that are subject to the Apple Public Source License 9 | * Version 2.0 (the 'License'). You may not use this file except in 10 | * compliance with the License. Please obtain a copy of the License at 11 | * http://www.opensource.apple.com/apsl/ and read it before using this 12 | * file. 13 | * 14 | * The Original Code and all software distributed under the License are 15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 | * Please see the License for the specific language governing rights and 20 | * limitations under the License. 21 | * 22 | * @APPLE_LICENSE_HEADER_END@ 23 | */ 24 | #ifndef __DYLD_CACHE_FORMAT__ 25 | #define __DYLD_CACHE_FORMAT__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | struct dyld_cache_header 33 | { 34 | char magic[16]; // e.g. "dyld_v0 i386" 35 | uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info 36 | uint32_t mappingCount; // number of dyld_cache_mapping_info entries 37 | uint32_t imagesOffsetOld; // UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing 38 | uint32_t imagesCountOld; // UNUSED: moved to imagesCount to prevent older dsc_extarctors from crashing 39 | uint64_t dyldBaseAddress; // base address of dyld when cache was built 40 | uint64_t codeSignatureOffset; // file offset of code signature blob 41 | uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file) 42 | uint64_t slideInfoOffsetUnused; // unused. Used to be file offset of kernel slid info 43 | uint64_t slideInfoSizeUnused; // unused. Used to be size of kernel slid info 44 | uint64_t localSymbolsOffset; // file offset of where local symbols are stored 45 | uint64_t localSymbolsSize; // size of local symbols information 46 | uint8_t uuid[16]; // unique value for each shared cache file 47 | uint64_t cacheType; // 0 for development, 1 for production, 2 for multi-cache 48 | uint32_t branchPoolsOffset; // file offset to table of uint64_t pool addresses 49 | uint32_t branchPoolsCount; // number of uint64_t entries 50 | uint64_t dyldInCacheMH; // (unslid) address of mach_header of dyld in cache 51 | uint64_t dyldInCacheEntry; // (unslid) address of entry point (_dyld_start) of dyld in cache 52 | uint64_t imagesTextOffset; // file offset to first dyld_cache_image_text_info 53 | uint64_t imagesTextCount; // number of dyld_cache_image_text_info entries 54 | uint64_t patchInfoAddr; // (unslid) address of dyld_cache_patch_info 55 | uint64_t patchInfoSize; // Size of all of the patch information pointed to via the dyld_cache_patch_info 56 | uint64_t otherImageGroupAddrUnused; // unused 57 | uint64_t otherImageGroupSizeUnused; // unused 58 | uint64_t progClosuresAddr; // (unslid) address of list of program launch closures 59 | uint64_t progClosuresSize; // size of list of program launch closures 60 | uint64_t progClosuresTrieAddr; // (unslid) address of trie of indexes into program launch closures 61 | uint64_t progClosuresTrieSize; // size of trie of indexes into program launch closures 62 | uint32_t platform; // platform number (macOS=1, etc) 63 | uint32_t formatVersion : 8, // dyld3::closure::kFormatVersion 64 | dylibsExpectedOnDisk : 1, // dyld should expect the dylib exists on disk and to compare inode/mtime to see if cache is valid 65 | simulator : 1, // for simulator of specified platform 66 | locallyBuiltCache : 1, // 0 for B&I built cache, 1 for locally built cache 67 | builtFromChainedFixups : 1, // some dylib in cache was built using chained fixups, so patch tables must be used for overrides 68 | padding : 20; // TBD 69 | uint64_t sharedRegionStart; // base load address of cache if not slid 70 | uint64_t sharedRegionSize; // overall size required to map the cache and all subCaches, if any 71 | uint64_t maxSlide; // runtime slide of cache can be between zero and this value 72 | uint64_t dylibsImageArrayAddr; // (unslid) address of ImageArray for dylibs in this cache 73 | uint64_t dylibsImageArraySize; // size of ImageArray for dylibs in this cache 74 | uint64_t dylibsTrieAddr; // (unslid) address of trie of indexes of all cached dylibs 75 | uint64_t dylibsTrieSize; // size of trie of cached dylib paths 76 | uint64_t otherImageArrayAddr; // (unslid) address of ImageArray for dylibs and bundles with dlopen closures 77 | uint64_t otherImageArraySize; // size of ImageArray for dylibs and bundles with dlopen closures 78 | uint64_t otherTrieAddr; // (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures 79 | uint64_t otherTrieSize; // size of trie of dylibs and bundles with dlopen closures 80 | uint32_t mappingWithSlideOffset; // file offset to first dyld_cache_mapping_and_slide_info 81 | uint32_t mappingWithSlideCount; // number of dyld_cache_mapping_and_slide_info entries 82 | uint64_t dylibsPBLStateArrayAddrUnused; // unused 83 | uint64_t dylibsPBLSetAddr; // (unslid) address of PrebuiltLoaderSet of all cached dylibs 84 | uint64_t programsPBLSetPoolAddr; // (unslid) address of pool of PrebuiltLoaderSet for each program 85 | uint64_t programsPBLSetPoolSize; // size of pool of PrebuiltLoaderSet for each program 86 | uint64_t programTrieAddr; // (unslid) address of trie mapping program path to PrebuiltLoaderSet 87 | uint32_t programTrieSize; 88 | uint32_t osVersion; // OS Version of dylibs in this cache for the main platform 89 | uint32_t altPlatform; // e.g. iOSMac on macOS 90 | uint32_t altOsVersion; // e.g. 14.0 for iOSMac 91 | uint64_t swiftOptsOffset; // VM offset from cache_header* to Swift optimizations header 92 | uint64_t swiftOptsSize; // size of Swift optimizations header 93 | uint32_t subCacheArrayOffset; // file offset to first dyld_subcache_entry 94 | uint32_t subCacheArrayCount; // number of subCache entries 95 | uint8_t symbolFileUUID[16]; // unique value for the shared cache file containing unmapped local symbols 96 | uint64_t rosettaReadOnlyAddr; // (unslid) address of the start of where Rosetta can add read-only/executable data 97 | uint64_t rosettaReadOnlySize; // maximum size of the Rosetta read-only/executable region 98 | uint64_t rosettaReadWriteAddr; // (unslid) address of the start of where Rosetta can add read-write data 99 | uint64_t rosettaReadWriteSize; // maximum size of the Rosetta read-write region 100 | uint32_t imagesOffset; // file offset to first dyld_cache_image_info 101 | uint32_t imagesCount; // number of dyld_cache_image_info entries 102 | uint32_t cacheSubType; // 0 for development, 1 for production, when cacheType is multi-cache(2) 103 | uint64_t objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header 104 | uint64_t objcOptsSize; // size of ObjC optimizations header 105 | uint64_t cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process introspection 106 | uint64_t cacheAtlasSize; // size of embedded cache atlas 107 | uint64_t dynamicDataOffset; // VM offset from cache_header* to the location of dyld_cache_dynamic_data_header 108 | uint64_t dynamicDataMaxSize; // maximum size of space reserved from dynamic data 109 | }; 110 | 111 | // Uncomment this and check the build errors for the current mapping offset to check against when adding new fields. 112 | // template class A { int x[-size]; }; A a; 113 | 114 | 115 | struct dyld_cache_mapping_info { 116 | uint64_t address; 117 | uint64_t size; 118 | uint64_t fileOffset; 119 | uint32_t maxProt; 120 | uint32_t initProt; 121 | }; 122 | 123 | // Contains the flags for the dyld_cache_mapping_and_slide_info flgs field 124 | enum { 125 | DYLD_CACHE_MAPPING_AUTH_DATA = 1 << 0U, 126 | DYLD_CACHE_MAPPING_DIRTY_DATA = 1 << 1U, 127 | DYLD_CACHE_MAPPING_CONST_DATA = 1 << 2U, 128 | DYLD_CACHE_MAPPING_TEXT_STUBS = 1 << 3U, 129 | DYLD_CACHE_DYNAMIC_CONFIG_DATA = 1 << 4U, 130 | }; 131 | 132 | struct dyld_cache_mapping_and_slide_info { 133 | uint64_t address; 134 | uint64_t size; 135 | uint64_t fileOffset; 136 | uint64_t slideInfoFileOffset; 137 | uint64_t slideInfoFileSize; 138 | uint64_t flags; 139 | uint32_t maxProt; 140 | uint32_t initProt; 141 | }; 142 | 143 | struct dyld_cache_image_info 144 | { 145 | uint64_t address; 146 | uint64_t modTime; 147 | uint64_t inode; 148 | uint32_t pathFileOffset; 149 | uint32_t pad; 150 | }; 151 | 152 | struct dyld_cache_image_info_extra 153 | { 154 | uint64_t exportsTrieAddr; // address of trie in unslid cache 155 | uint64_t weakBindingsAddr; 156 | uint32_t exportsTrieSize; 157 | uint32_t weakBindingsSize; 158 | uint32_t dependentsStartArrayIndex; 159 | uint32_t reExportsStartArrayIndex; 160 | }; 161 | 162 | 163 | struct dyld_cache_accelerator_info 164 | { 165 | uint32_t version; // currently 1 166 | uint32_t imageExtrasCount; // does not include aliases 167 | uint32_t imagesExtrasOffset; // offset into this chunk of first dyld_cache_image_info_extra 168 | uint32_t bottomUpListOffset; // offset into this chunk to start of 16-bit array of sorted image indexes 169 | uint32_t dylibTrieOffset; // offset into this chunk to start of trie containing all dylib paths 170 | uint32_t dylibTrieSize; // size of trie containing all dylib paths 171 | uint32_t initializersOffset; // offset into this chunk to start of initializers list 172 | uint32_t initializersCount; // size of initializers list 173 | uint32_t dofSectionsOffset; // offset into this chunk to start of DOF sections list 174 | uint32_t dofSectionsCount; // size of initializers list 175 | uint32_t reExportListOffset; // offset into this chunk to start of 16-bit array of re-exports 176 | uint32_t reExportCount; // size of re-exports 177 | uint32_t depListOffset; // offset into this chunk to start of 16-bit array of dependencies (0x8000 bit set if upward) 178 | uint32_t depListCount; // size of dependencies 179 | uint32_t rangeTableOffset; // offset into this chunk to start of ss 180 | uint32_t rangeTableCount; // size of dependencies 181 | uint64_t dyldSectionAddr; // address of libdyld's __dyld section in unslid cache 182 | }; 183 | 184 | struct dyld_cache_accelerator_initializer 185 | { 186 | uint32_t functionOffset; // address offset from start of cache mapping 187 | uint32_t imageIndex; 188 | }; 189 | 190 | struct dyld_cache_range_entry 191 | { 192 | uint64_t startAddress; // unslid address of start of region 193 | uint32_t size; 194 | uint32_t imageIndex; 195 | }; 196 | 197 | struct dyld_cache_accelerator_dof 198 | { 199 | uint64_t sectionAddress; // unslid address of start of region 200 | uint32_t sectionSize; 201 | uint32_t imageIndex; 202 | }; 203 | 204 | struct dyld_cache_image_text_info 205 | { 206 | uuid_t uuid; 207 | uint64_t loadAddress; // unslid address of start of __TEXT 208 | uint32_t textSegmentSize; 209 | uint32_t pathOffset; // offset from start of cache file 210 | }; 211 | 212 | 213 | // The rebasing info is to allow the kernel to lazily rebase DATA pages of the 214 | // dyld shared cache. Rebasing is adding the slide to interior pointers. 215 | struct dyld_cache_slide_info 216 | { 217 | uint32_t version; // currently 1 218 | uint32_t toc_offset; 219 | uint32_t toc_count; 220 | uint32_t entries_offset; 221 | uint32_t entries_count; 222 | uint32_t entries_size; // currently 128 223 | // uint16_t toc[toc_count]; 224 | // entrybitmap entries[entries_count]; 225 | }; 226 | 227 | struct dyld_cache_slide_info_entry { 228 | uint8_t bits[4096/(8*4)]; // 128-byte bitmap 229 | }; 230 | 231 | 232 | // The version 2 of the slide info uses a different compression scheme. Since 233 | // only interior pointers (pointers that point within the cache) are rebased 234 | // (slid), we know the possible range of the pointers and thus know there are 235 | // unused bits in each pointer. We use those bits to form a linked list of 236 | // locations needing rebasing in each page. 237 | // 238 | // Definitions: 239 | // 240 | // pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size 241 | // pageStarts[] = info + info->page_starts_offset 242 | // pageExtras[] = info + info->page_extras_offset 243 | // valueMask = ~(info->delta_mask) 244 | // deltaShift = __builtin_ctzll(info->delta_mask) - 2 245 | // 246 | // There are three cases: 247 | // 248 | // 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 249 | // The page contains no values that need rebasing. 250 | // 251 | // 2) (pageStarts[pageIndex] & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA) == 0 252 | // All rebase locations are in one linked list. The offset of the first 253 | // rebase location in the page is pageStarts[pageIndex] * 4. 254 | // 255 | // 3) pageStarts[pageIndex] & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA 256 | // Multiple linked lists are needed for all rebase locations in a page. 257 | // The pagesExtras array contains 2 or more entries each of which is the 258 | // start of a new linked list in the page. The first is at: 259 | // extrasStartIndex = (pageStarts[pageIndex] & 0x3FFF) 260 | // The next is at extrasStartIndex+1. The last is denoted by 261 | // having the high bit (DYLD_CACHE_SLIDE_PAGE_ATTR_END) of the pageExtras[] 262 | // set. 263 | // 264 | // For 64-bit architectures, there is always enough free bits to encode all 265 | // possible deltas. The info->delta_mask field shows where the delta is located 266 | // in the pointer. That value must be masked off (valueMask) before the slide 267 | // is added to the pointer. 268 | // 269 | // For 32-bit architectures, there are only three bits free (the three most 270 | // significant bits). To extract the delta, you must first subtract value_add 271 | // from the pointer value, then AND with delta_mask, then shift by deltaShift. 272 | // That still leaves a maximum delta to the next rebase location of 28 bytes. 273 | // To reduce the number or chains needed, an optimization was added. Turns 274 | // out zero is common in the DATA region. A zero can be turned into a 275 | // non-rebasing entry in the linked list. The can be done because nothing 276 | // in the shared cache should point out of its dylib to the start of the shared 277 | // cache. 278 | // 279 | // The code for processing a linked list (chain) is: 280 | // 281 | // uint32_t delta = 1; 282 | // while ( delta != 0 ) { 283 | // uint8_t* loc = pageStart + pageOffset; 284 | // uintptr_t rawValue = *((uintptr_t*)loc); 285 | // delta = ((rawValue & deltaMask) >> deltaShift); 286 | // uintptr_t newValue = (rawValue & valueMask); 287 | // if ( newValue != 0 ) { 288 | // newValue += valueAdd; 289 | // newValue += slideAmount; 290 | // } 291 | // *((uintptr_t*)loc) = newValue; 292 | // pageOffset += delta; 293 | // } 294 | // 295 | // 296 | struct dyld_cache_slide_info2 297 | { 298 | uint32_t version; // currently 2 299 | uint32_t page_size; // currently 4096 (may also be 16384) 300 | uint32_t page_starts_offset; 301 | uint32_t page_starts_count; 302 | uint32_t page_extras_offset; 303 | uint32_t page_extras_count; 304 | uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location 305 | uint64_t value_add; 306 | //uint16_t page_starts[page_starts_count]; 307 | //uint16_t page_extras[page_extras_count]; 308 | }; 309 | #define DYLD_CACHE_SLIDE_PAGE_ATTRS 0xC000 // high bits of uint16_t are flags 310 | #define DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA 0x8000 // index is into extras array (not starts array) 311 | #define DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 0x4000 // page has no rebasing 312 | #define DYLD_CACHE_SLIDE_PAGE_ATTR_END 0x8000 // last chain entry for page 313 | 314 | 315 | 316 | // The version 3 of the slide info uses a different compression scheme. Since 317 | // only interior pointers (pointers that point within the cache) are rebased 318 | // (slid), we know the possible range of the pointers and thus know there are 319 | // unused bits in each pointer. We use those bits to form a linked list of 320 | // locations needing rebasing in each page. 321 | // 322 | // Definitions: 323 | // 324 | // pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size 325 | // pageStarts[] = info + info->page_starts_offset 326 | // 327 | // There are two cases: 328 | // 329 | // 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE 330 | // The page contains no values that need rebasing. 331 | // 332 | // 2) otherwise... 333 | // All rebase locations are in one linked list. The offset of the first 334 | // rebase location in the page is pageStarts[pageIndex]. 335 | // 336 | // A pointer is one of of the variants in dyld_cache_slide_pointer3 337 | // 338 | // The code for processing a linked list (chain) is: 339 | // 340 | // uint32_t delta = pageStarts[pageIndex]; 341 | // dyld_cache_slide_pointer3* loc = pageStart; 342 | // do { 343 | // loc += delta; 344 | // delta = loc->offsetToNextPointer; 345 | // if ( loc->auth.authenticated ) { 346 | // newValue = loc->offsetFromSharedCacheBase + results->slide + auth_value_add; 347 | // newValue = sign_using_the_various_bits(newValue); 348 | // } 349 | // else { 350 | // uint64_t value51 = loc->pointerValue; 351 | // uint64_t top8Bits = value51 & 0x0007F80000000000ULL; 352 | // uint64_t bottom43Bits = value51 & 0x000007FFFFFFFFFFULL; 353 | // uint64_t targetValue = ( top8Bits << 13 ) | bottom43Bits; 354 | // newValue = targetValue + results->slide; 355 | // } 356 | // loc->raw = newValue; 357 | // } while (delta != 0); 358 | // 359 | // 360 | struct dyld_cache_slide_info3 361 | { 362 | uint32_t version; // currently 3 363 | uint32_t page_size; // currently 4096 (may also be 16384) 364 | uint32_t page_starts_count; 365 | uint64_t auth_value_add; 366 | uint16_t page_starts[/* page_starts_count */]; 367 | }; 368 | 369 | #define DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing 370 | 371 | union dyld_cache_slide_pointer3 372 | { 373 | uint64_t raw; 374 | struct { 375 | uint64_t pointerValue : 51, 376 | offsetToNextPointer : 11, 377 | unused : 2; 378 | } plain; 379 | 380 | struct { 381 | uint64_t offsetFromSharedCacheBase : 32, 382 | diversityData : 16, 383 | hasAddressDiversity : 1, 384 | key : 2, 385 | offsetToNextPointer : 11, 386 | unused : 1, 387 | authenticated : 1; // = 1; 388 | } auth; 389 | }; 390 | 391 | 392 | 393 | // The version 4 of the slide info is optimized for 32-bit caches up to 1GB. 394 | // Since only interior pointers (pointers that point within the cache) are rebased 395 | // (slid), we know the possible range of the pointers takes 30 bits. That 396 | // gives us two bits to use to chain to the next rebase. 397 | // 398 | // Definitions: 399 | // 400 | // pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size 401 | // pageStarts[] = info + info->page_starts_offset 402 | // pageExtras[] = info + info->page_extras_offset 403 | // valueMask = ~(info->delta_mask) 404 | // deltaShift = __builtin_ctzll(info->delta_mask) - 2 405 | // 406 | // There are three cases: 407 | // 408 | // 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE 409 | // The page contains no values that need rebasing. 410 | // 411 | // 2) (pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA) == 0 412 | // All rebase locations are in one linked list. The offset of the first 413 | // rebase location in the page is pageStarts[pageIndex] * 4. 414 | // 415 | // 3) pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA 416 | // Multiple chains are needed for all rebase locations in a page. 417 | // The pagesExtras array contains 2 or more entries each of which is the 418 | // start of a new chain in the page. The first is at: 419 | // extrasStartIndex = (pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_INDEX) 420 | // The next is at extrasStartIndex+1. The last is denoted by 421 | // having the high bit (DYLD_CACHE_SLIDE4_PAGE_EXTRA_END) of the pageExtras[]. 422 | // 423 | // For 32-bit architectures, there are only two bits free (the two most 424 | // significant bits). To extract the delta, you must first subtract value_add 425 | // from the pointer value, then AND with delta_mask, then shift by deltaShift. 426 | // That still leaves a maximum delta to the next rebase location of 12 bytes. 427 | // To reduce the number or chains needed, an optimization was added. Turns 428 | // most of the non-rebased data are small values and can be co-opt'ed into 429 | // being used in the chain. The can be done because nothing 430 | // in the shared cache should point to the first 64KB which are in the shared 431 | // cache header information. So if the resulting pointer points to the 432 | // start of the cache +/-32KB, then it is actually a small number that should 433 | // not be rebased, but just reconstituted. 434 | // 435 | // The code for processing a linked list (chain) is: 436 | // 437 | // uint32_t delta = 1; 438 | // while ( delta != 0 ) { 439 | // uint8_t* loc = pageStart + pageOffset; 440 | // uint32_t rawValue = *((uint32_t*)loc); 441 | // delta = ((rawValue & deltaMask) >> deltaShift); 442 | // uintptr_t newValue = (rawValue & valueMask); 443 | // if ( (newValue & 0xFFFF8000) == 0 ) { 444 | // // small positive non-pointer, use as-is 445 | // } 446 | // else if ( (newValue & 0x3FFF8000) == 0x3FFF8000 ) { 447 | // // small negative non-pointer 448 | // newValue |= 0xC0000000; 449 | // } 450 | // else { 451 | // // pointer that needs rebasing 452 | // newValue += valueAdd; 453 | // newValue += slideAmount; 454 | // } 455 | // *((uint32_t*)loc) = newValue; 456 | // pageOffset += delta; 457 | // } 458 | // 459 | // 460 | struct dyld_cache_slide_info4 461 | { 462 | uint32_t version; // currently 4 463 | uint32_t page_size; // currently 4096 (may also be 16384) 464 | uint32_t page_starts_offset; 465 | uint32_t page_starts_count; 466 | uint32_t page_extras_offset; 467 | uint32_t page_extras_count; 468 | uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location (0xC0000000) 469 | uint64_t value_add; // base address of cache 470 | //uint16_t page_starts[page_starts_count]; 471 | //uint16_t page_extras[page_extras_count]; 472 | }; 473 | #define DYLD_CACHE_SLIDE4_PAGE_NO_REBASE 0xFFFF // page has no rebasing 474 | #define DYLD_CACHE_SLIDE4_PAGE_INDEX 0x7FFF // mask of page_starts[] values 475 | #define DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA 0x8000 // index is into extras array (not a chain start offset) 476 | #define DYLD_CACHE_SLIDE4_PAGE_EXTRA_END 0x8000 // last chain entry for page 477 | 478 | 479 | struct dyld_cache_local_symbols_info 480 | { 481 | uint32_t nlistOffset; // offset into this chunk of nlist entries 482 | uint32_t nlistCount; // count of nlist entries 483 | uint32_t stringsOffset; // offset into this chunk of string pool 484 | uint32_t stringsSize; // byte count of string pool 485 | uint32_t entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry 486 | uint32_t entriesCount; // number of elements in dyld_cache_local_symbols_entry array 487 | }; 488 | 489 | struct dyld_cache_local_symbols_entry 490 | { 491 | uint32_t dylibOffset; // offset in cache file of start of dylib 492 | uint32_t nlistStartIndex; // start index of locals for this dylib 493 | uint32_t nlistCount; // number of local symbols for this dylib 494 | }; 495 | 496 | struct dyld_cache_local_symbols_entry_64 497 | { 498 | uint64_t dylibOffset; // offset in cache buffer of start of dylib 499 | uint32_t nlistStartIndex; // start index of locals for this dylib 500 | uint32_t nlistCount; // number of local symbols for this dylib 501 | }; 502 | 503 | struct dyld_subcache_entry_v1 504 | { 505 | uint8_t uuid[16]; // The UUID of the subCache file 506 | uint64_t cacheVMOffset; // The offset of this subcache from the main cache base address 507 | }; 508 | 509 | struct dyld_subcache_entry 510 | { 511 | uint8_t uuid[16]; // The UUID of the subCache file 512 | uint64_t cacheVMOffset; // The offset of this subcache from the main cache base address 513 | char fileSuffix[32]; // The file name suffix of the subCache file e.g. ".25.data", ".03.development" 514 | }; 515 | 516 | // This struct is a small piece of dynamic data that can be included in the shared region, and contains configuration 517 | // data about the shared cache in use by the process. It is located 518 | struct dyld_cache_dynamic_data_header 519 | { 520 | char magic[16]; // e.g. "dyld_data v0" 521 | uint64_t fsId; // The fsid_t of the shared cache being used by a process 522 | uint64_t fsObjId; // The fs_obj_id_t of the shared cache being used by a process 523 | }; 524 | 525 | // This is the location of the macOS shared cache on macOS 11.0 and later 526 | #define MACOSX_MRM_DYLD_SHARED_CACHE_DIR "/System/Library/dyld/" 527 | 528 | // This is old define for the old location of the dyld cache 529 | #define MACOSX_DYLD_SHARED_CACHE_DIR MACOSX_MRM_DYLD_SHARED_CACHE_DIR 530 | 531 | #define IPHONE_DYLD_SHARED_CACHE_DIR "/System/Library/Caches/com.apple.dyld/" 532 | 533 | #define DRIVERKIT_DYLD_SHARED_CACHE_DIR "/System/DriverKit/System/Library/dyld/" 534 | 535 | #if !TARGET_OS_SIMULATOR 536 | #define DYLD_SHARED_CACHE_BASE_NAME "dyld_shared_cache_" 537 | #else 538 | #define DYLD_SHARED_CACHE_BASE_NAME "dyld_sim_shared_cache_" 539 | #endif 540 | #define DYLD_SHARED_CACHE_DEVELOPMENT_EXT ".development" 541 | 542 | #define DYLD_SHARED_CACHE_DYNAMIC_DATA_MAGIC "dyld_data v0" 543 | 544 | static const char* cryptexPrefixes[] = { 545 | "/System/Volumes/Preboot/Cryptexes/OS/", 546 | "/private/preboot/Cryptexes/OS/", 547 | "/System/Cryptexes/OS" 548 | }; 549 | 550 | static const uint64_t kDyldSharedCacheTypeDevelopment = 0; 551 | static const uint64_t kDyldSharedCacheTypeProduction = 1; 552 | static const uint64_t kDyldSharedCacheTypeUniversal = 2; 553 | 554 | 555 | 556 | 557 | 558 | #endif // __DYLD_CACHE_FORMAT__ 559 | 560 | 561 | -------------------------------------------------------------------------------- /utility/debug.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __DEBUG_H__ 3 | #define __DEBUG_H__ 4 | 5 | #include 6 | #include 7 | #include "utility/error.h" 8 | 9 | // system is unusable 10 | #define LOG_EMERGENCY LOG_EMERG 11 | // critical logging level 12 | #define LOG_CRITICAL LOG_CRIT 13 | // Error logging level 14 | #define LOG_ERROR LOG_ERR 15 | 16 | #define LOG_DEFAULTS ( LOG_CONS | LOG_PERROR | LOG_ODELAY | LOG_NDELAY | LOG_USER | LOG_PID ) 17 | // #define LOG_DEFAULTS ( LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER ) 18 | #define LOG_NAME "No_Name" 19 | #define RET_CODE_8X "0x%08" PRIX8 20 | 21 | #if defined( DEBUG_MODE ) 22 | 23 | #define BWSR_DEBUG( LOG_LEVEL, \ 24 | FORMAT, \ 25 | ARGUMENTS... ) \ 26 | do \ 27 | { \ 28 | openlog( LOG_NAME, \ 29 | LOG_DEFAULTS, \ 30 | LOG_USER ); \ 31 | syslog( LOG_LEVEL, \ 32 | "%s[%d] -> %s(): " FORMAT, \ 33 | __FILE__, \ 34 | __LINE__, \ 35 | __FUNCTION__, \ 36 | ##ARGUMENTS ); \ 37 | closelog(); \ 38 | } \ 39 | while( 0 ); 40 | 41 | #define DEBUG( ... ) \ 42 | BWSR_DEBUG( LOG_DEBUG, __VA_ARGS__ ); 43 | 44 | #define __DEBUG_ENTER \ 45 | BWSR_DEBUG( LOG_DEBUG, "enter\n" ); 46 | 47 | #define __DEBUG_EXIT \ 48 | BWSR_DEBUG( LOG_DEBUG, "exit\n" ); 49 | 50 | #define __DEBUG_RETVAL( RETURN_CODE ) \ 51 | BWSR_DEBUG( LOG_DEBUG, \ 52 | "retVal: " RET_CODE_8X " %s\n", \ 53 | RETURN_CODE, \ 54 | ErrorString( RETURN_CODE ) ); 55 | 56 | #else 57 | 58 | #define BWSR_DEBUG( LOG_LEVEL, FORMAT, ARGUMENTS... ) 59 | #define DEBUG( ... ) 60 | #define __DEBUG_ENTER 61 | #define __DEBUG_EXIT 62 | #define __DEBUG_RETVAL( RETURN_CODE ) 63 | 64 | #endif // DEBUG_MODE 65 | 66 | #endif -------------------------------------------------------------------------------- /utility/error.h: -------------------------------------------------------------------------------- 1 | #ifndef __ERROR_H__ 2 | #define __ERROR_H__ 3 | 4 | // ----------------------------------------------------------------------------- 5 | // BASE ERRORS 6 | // ----------------------------------------------------------------------------- 7 | 8 | #define ERROR_SUCCESS ( 0x00000000 ) 9 | #define ERROR_FAILURE ( 0xFFFFFFFF ) 10 | 11 | // ----------------------------------------------------------------------------- 12 | // GENERIC ERRORS 13 | // ----------------------------------------------------------------------------- 14 | 15 | #define ERROR_ARGUMENT_IS_NULL ( 0x00000010 ) 16 | #define ERROR_INVALID_ARGUMENT_VALUE ( 0x00000011 ) 17 | #define ERROR_NOT_FOUND ( 0x00000012 ) 18 | #define ERROR_UNHANDLED_DATA_TYPE ( 0x00000013 ) 19 | #define ERROR_UNIMPLEMENTED ( 0x00000014 ) 20 | #define ERROR_UNEXPECTED_FORMAT ( 0x00000015 ) 21 | 22 | // ----------------------------------------------------------------------------- 23 | // MEMORY ERRORS 24 | // ----------------------------------------------------------------------------- 25 | 26 | #define ERROR_MEM_ALLOC ( 0x00000100 ) 27 | #define ERROR_MEMORY_MAPPING ( 0x00000101 ) 28 | #define ERROR_MEMORY_PERMISSION ( 0x00000102 ) 29 | #define ERROR_MEMORY_OVERFLOW ( 0x00000103 ) 30 | 31 | // ----------------------------------------------------------------------------- 32 | // I/O ERRROS 33 | // ----------------------------------------------------------------------------- 34 | 35 | #define ERROR_FILE_IO ( 0x00001000 ) 36 | #define ERROR_CACHED_LOCATION ( 0x00001001 ) 37 | #define ERROR_SHARED_CACHE ( 0x00001002 ) 38 | #define ERROR_PROC_SELF_MAPS ( 0x00001003 ) 39 | 40 | // ----------------------------------------------------------------------------- 41 | // OS ERRORS 42 | // ----------------------------------------------------------------------------- 43 | 44 | #define ERROR_SYMBOL_SIZE ( 0x00010000 ) 45 | #define ERROR_TASK_INFO ( 0x00010001 ) 46 | #define ERROR_ROUTING_FAILURE ( 0x00010002 ) 47 | 48 | // ----------------------------------------------------------------------------- 49 | // ERROR STRING CONVERSION 50 | // ----------------------------------------------------------------------------- 51 | 52 | #define ERROR_STRINGS( E ) \ 53 | E( ERROR_SUCCESS, "Success" ) \ 54 | E( ERROR_FAILURE, "Generic Error" ) \ 55 | /* --- GENERICS --- */ \ 56 | E( ERROR_ARGUMENT_IS_NULL, "An argument is NULL" ) \ 57 | E( ERROR_INVALID_ARGUMENT_VALUE, "An argument has a bad value" ) \ 58 | E( ERROR_NOT_FOUND, "Element not found" ) \ 59 | E( ERROR_UNHANDLED_DATA_TYPE, "Unexpected data type" ) \ 60 | E( ERROR_UNIMPLEMENTED, "No implementation for this data type" ) \ 61 | E( ERROR_UNEXPECTED_FORMAT, "Data format did match expectation" ) \ 62 | /* --- MEMORY --- */ \ 63 | E( ERROR_MEM_ALLOC, "Out of memory" ) \ 64 | E( ERROR_MEMORY_MAPPING, "Faied to map memory region" ) \ 65 | E( ERROR_MEMORY_PERMISSION, "Failed to change memory permissions" ) \ 66 | E( ERROR_MEMORY_OVERFLOW, "Allocated memory not large enough" ) \ 67 | /* --- I/O --- */ \ 68 | E( ERROR_FILE_IO, "File I/O" ) \ 69 | E( ERROR_CACHED_LOCATION, "Invalid cache location" ) \ 70 | E( ERROR_SHARED_CACHE, "Failed to initialize shared cache" ) \ 71 | E( ERROR_PROC_SELF_MAPS, "Failed to open proc/self/maps" ) \ 72 | /* --- OS --- */ \ 73 | E( ERROR_SYMBOL_SIZE, "Invalid symbol size" ) \ 74 | E( ERROR_TASK_INFO, "Need to summarize" ) \ 75 | E( ERROR_ROUTING_FAILURE, "Failed to setup VirtualPage routing" ) 76 | 77 | #define ERROR_TEXT( ERROR_CODE, TEXT ) \ 78 | case ERROR_CODE: return #ERROR_CODE " (" TEXT ")"; 79 | 80 | typedef int BWSR_STATUS; 81 | 82 | static inline const char* ErrorString( int ErrorCode ) 83 | { 84 | switch( ErrorCode ) 85 | { 86 | ERROR_STRINGS( ERROR_TEXT ) 87 | } // switch() 88 | 89 | return "Unknown Error code!"; 90 | } 91 | 92 | #endif -------------------------------------------------------------------------------- /utility/utility.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __UTILITY_H__ 3 | #define __UTILITY_H__ 4 | 5 | // ----------------------------------------------------------------------------- 6 | // INCLUDES 7 | // ----------------------------------------------------------------------------- 8 | 9 | #include "utility/debug.h" 10 | #include "utility/error.h" 11 | 12 | // ----------------------------------------------------------------------------- 13 | // BASE 14 | // ----------------------------------------------------------------------------- 15 | 16 | #define IN 17 | #define OUT 18 | #define OPTIONAL 19 | 20 | #define BWSR_API __attribute__( ( visibility( "default" ) ) ) 21 | 22 | #define ARRAY_LENGTH( ARRAY ) ( sizeof( ARRAY ) / sizeof( ARRAY[ 0 ] ) ) 23 | 24 | // ----------------------------------------------------------------------------- 25 | // BIT MANIPULATION 26 | // ----------------------------------------------------------------------------- 27 | 28 | // Truncate address to nearest lower multiple of page size `0x1000`. 29 | #define arm64_trunc_page( x ) \ 30 | ( ( x ) & ( ~( 0x1000 - 1 ) ) ) 31 | 32 | // Align page to boundary 33 | #define ALIGN_FLOOR( ADDRESS, RANGE ) \ 34 | ( (uintptr_t) ADDRESS & ~( (uintptr_t) RANGE - 1 ) ) 35 | 36 | // Left shift `Bits` after masking with `BitMaskShift` least significant bits, 37 | // then shift left by `BitShift` positions. 38 | #define BIT_SHIFT( Bits, BitMaskShift, BitShift ) \ 39 | ( ( ( Bits ) & ( ( 1 << ( BitMaskShift ) ) - 1 ) ) << ( BitShift ) ) 40 | 41 | // Generate a bitmask with `BitShift` bits set to `1`. 42 | #define GENERATE_BIT_MASK( BitShift ) \ 43 | ( ( 1L << ( ( BitShift ) + 1 ) ) - 1 ) 44 | 45 | // Extract bits from `Bits` starting at position `StartBit` to `EndBit`. 46 | #define GET_BITS( Bits, StartBit, EndBit ) \ 47 | ( ( ( Bits ) >> ( StartBit ) ) & GENERATE_BIT_MASK( ( EndBit ) - ( StartBit ) ) ) 48 | 49 | // Extract a single bit from `Bits` at position `BitPos`. 50 | #define GET_BIT( Bits, BitPos ) \ 51 | ( ( ( Bits ) >> ( BitPos ) ) & 1 ) 52 | 53 | // Set a specific bit in `Bits` at position `BitPos` to `Bit` (0 or 1). 54 | #define SET_BIT( Bits, BitPos, Bit ) \ 55 | ( Bits = ( ( ( ~( 1 << ( BitPos ) ) ) & ( Bits ) ) | ( ( Bit ) << ( BitPos ) ) ) ) 56 | 57 | // Set bits in `Bits` from position `StartBit` to `EndBit` with bits 58 | // from `ReplacementBits`. 59 | #define SET_BITS( Bits, StartBit, EndBit, ReplacementBits ) \ 60 | ( Bits = ( ( ( ~( GENERATE_BIT_MASK( ( EndBit ) - ( StartBit ) ) << ( StartBit ) ) ) & ( Bits ) ) \ 61 | | ( ( ReplacementBits ) << ( StartBit ) ) ) ) 62 | 63 | // ----------------------------------------------------------------------------- 64 | // MACRO EXPANSIONS && BASE CONDITIONS 65 | // ----------------------------------------------------------------------------- 66 | 67 | // Bypass compiler warnings about unused parameters. 68 | #define UNUSED_PARAMETER( Parameter ) (void) Parameter; 69 | 70 | // Avoids return value by forcing `return;` 71 | #define VOID_RETURN 72 | 73 | 74 | // Checks if `Parameter` is `NULL`. 75 | // If so, it returns `RETURN_VALUE`. 76 | #define IF_PARAMETER_NULL_RETURN( RETURN_VALUE, Parameter ) \ 77 | if( NULL == Parameter ) \ 78 | { \ 79 | BWSR_DEBUG( LOG_ERROR, #Parameter " is NULL\n" ); \ 80 | return RETURN_VALUE; \ 81 | } 82 | 83 | // Wraps `IF_PARAMETER_NULL_RETURN` 84 | // Returns `ERROR_INVALID_ARGUMENT` if `Parameter` is `NULL` 85 | #define IF_PARAMETER_NULL_RETURN_BWSR( Parameter ) \ 86 | IF_PARAMETER_NULL_RETURN( ERROR_ARGUMENT_IS_NULL, Parameter ) 87 | 88 | // Wraps `IF_PARAMETER_NULL_RETURN` 89 | // Returns `NULL` if `Parameter` is `NULL` 90 | #define IF_PARAMETER_NULL_RETURN_NULL( Parameter ) \ 91 | IF_PARAMETER_NULL_RETURN( NULL, Parameter ) 92 | 93 | // Wraps `IF_PARAMETER_NULL_RETURN` 94 | // Returns `VOID` if `Parameter` is `NULL` 95 | #define IF_PARAMETER_NULL_RETURN_VOID( Parameter ) \ 96 | IF_PARAMETER_NULL_RETURN( VOID_RETURN, Parameter ) 97 | 98 | // Wraps `IF_PARAMETER_NULL_RETURN` 99 | // Returns `0` if `Parameter` is `NULL` 100 | #define IF_PARAMETER_NULL_RETURN_0( Parameter ) \ 101 | IF_PARAMETER_NULL_RETURN( 0, Parameter ) 102 | 103 | 104 | 105 | // Checks if `Parameter` is less than or equal to 0. 106 | // If so, it returns `RETURN_VALUE`. 107 | #define IF_PARAMATER_NOT_GREATER_THAN_0_RETURN( RETURN_VALUE, Parameter ) \ 108 | if( 0 >= Parameter ) \ 109 | { \ 110 | BWSR_DEBUG( LOG_ERROR, #Parameter " is less than 0!\n" ); \ 111 | return RETURN_VALUE; \ 112 | } 113 | 114 | // Wraps `IF_PARAMATER_NOT_GREATER_THAN_0_RETURN` 115 | // Returns `ERROR_INVALID_ARGUMENT` if `Parameter` is less than or equal to 0. 116 | #define IF_PARAMETER_NOT_GREATER_THAN_0_RETURN_BWSR( Parameter ) \ 117 | IF_PARAMATER_NOT_GREATER_THAN_0_RETURN( ERROR_INVALID_ARGUMENT_VALUE, Parameter ) 118 | 119 | // Wraps `IF_PARAMATER_NOT_GREATER_THAN_0_RETURN` 120 | // Returns `NULL` if `Parameter` is less than or equal to 0. 121 | #define IF_PARAMETER_NOT_GREATER_THAN_0_RETURN_NULL( Parameter ) \ 122 | IF_PARAMATER_NOT_GREATER_THAN_0_RETURN( NULL, Parameter ) 123 | 124 | // Wraps `IF_PARAMATER_NOT_GREATER_THAN_0_RETURN` 125 | // Returns `VOID` if `Parameter` is less than or equal to 0. 126 | #define IF_PARAMETER_NOT_GREATER_THAN_0_RETURN_VOID( Parameter ) \ 127 | IF_PARAMATER_NOT_GREATER_THAN_0_RETURN( VOID_RETURN, Parameter ) 128 | 129 | 130 | 131 | // Should be an impossible case 132 | #define MACRO_EXPAND__0__ 133 | 134 | // Should be an impossible case 135 | #define MACRO_EXPAND__1__( Parameter ) 136 | 137 | #define MACRO_EXPAND__2__( MACRO_EXPANSION, Parameter ) \ 138 | MACRO_EXPANSION( Parameter ) 139 | 140 | #define MACRO_EXPAND__3__( MACRO_EXPANSION, Parameter, ... ) \ 141 | MACRO_EXPANSION( Parameter ) \ 142 | MACRO_EXPAND__2__( MACRO_EXPANSION, __VA_ARGS__ ) 143 | 144 | #define MACRO_EXPAND__4__( MACRO_EXPANSION, Parameter, ... ) \ 145 | MACRO_EXPANSION( Parameter ) \ 146 | MACRO_EXPAND__3__( MACRO_EXPANSION, __VA_ARGS__ ) 147 | 148 | #define MACRO_EXPAND__5__( MACRO_EXPANSION, Parameter, ... ) \ 149 | MACRO_EXPANSION( Parameter ) \ 150 | MACRO_EXPAND__4__( MACRO_EXPANSION, __VA_ARGS__ ) 151 | 152 | #define MACRO_EXPAND__6__( MACRO_EXPANSION, Parameter, ... ) \ 153 | MACRO_EXPANSION( Parameter ) \ 154 | MACRO_EXPAND__5__( MACRO_EXPANSION, __VA_ARGS__ ) 155 | 156 | #define MACRO_EXPAND__7__( MACRO_EXPANSION, Parameter, ... ) \ 157 | MACRO_EXPANSION( Parameter ) \ 158 | MACRO_EXPAND__6__( MACRO_EXPANSION, __VA_ARGS__ ) 159 | 160 | #define MACRO_EXPAND__8__( MACRO_EXPANSION, Parameter, ... ) \ 161 | MACRO_EXPANSION( Parameter ) \ 162 | MACRO_EXPAND__7__( MACRO_EXPANSION, __VA_ARGS__ ) 163 | 164 | #define MACRO_EXPAND__9__( MACRO_EXPANSION, Parameter, ... ) \ 165 | MACRO_EXPANSION( Parameter ) \ 166 | MACRO_EXPAND__8__( MACRO_EXPANSION, __VA_ARGS__ ) 167 | 168 | #define MACRO_EXPAND__10__( MACRO_EXPANSION, Parameter, ... ) \ 169 | MACRO_EXPANSION( Parameter ) \ 170 | MACRO_EXPAND__9__( MACRO_EXPANSION, __VA_ARGS__ ) 171 | 172 | #define N_ARGS( ... ) \ 173 | N_ARGS_HELPER1( __VA_ARGS__, \ 174 | __10__, \ 175 | __9__, \ 176 | __8__, \ 177 | __7__, \ 178 | __6__, \ 179 | __5__, \ 180 | __4__, \ 181 | __3__, \ 182 | __2__, \ 183 | __1__, \ 184 | __0__ ) 185 | 186 | #define N_ARGS_HELPER1( ... ) \ 187 | N_ARGS_HELPER2( __VA_ARGS__ ) 188 | 189 | #define N_ARGS_HELPER2( x1, \ 190 | x2, \ 191 | x3, \ 192 | x4, \ 193 | x5, \ 194 | x6, \ 195 | x7, \ 196 | x8, \ 197 | x9, \ 198 | x10, \ 199 | n, \ 200 | ... ) n 201 | 202 | #define CREATE_MACRO_EXPANSION( PREFIX, POSTFIX ) \ 203 | PREFIX ## POSTFIX 204 | 205 | #define BUILD_MACRO( PREFIX, POSTFIX ) \ 206 | CREATE_MACRO_EXPANSION( PREFIX, POSTFIX ) 207 | 208 | // If a parameter is `NULL` returns `ERROR_ARGUMENT_IS_NULL` 209 | #define __NOT_NULL( ... ) \ 210 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NULL_RETURN_BWSR, __VA_ARGS__ ); 211 | 212 | // If a parameter is `NULL` returns `NULL` 213 | #define __NOT_NULL_RETURN_NULL( ... ) \ 214 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NULL_RETURN_NULL, __VA_ARGS__ ); 215 | 216 | // If a parameter is `NULL` returns 217 | #define __NOT_NULL_RETURN_VOID( ... ) \ 218 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NULL_RETURN_VOID, __VA_ARGS__ ); 219 | 220 | // If a parameter is `NULL` returns `0` 221 | #define __NOT_NULL_RETURN_0( ... ) \ 222 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NULL_RETURN_0, __VA_ARGS__ ); 223 | 224 | // If a parameter is not greater than `0` returns `ERROR_INVALID_ARGUMENT_VALUE` 225 | #define __GREATER_THAN_0( ... ) \ 226 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NOT_GREATER_THAN_0_RETURN_BWSR, __VA_ARGS__ ); 227 | 228 | // If a parameter is not greater than `0` returns `NULL` 229 | #define __GREATER_THAN_0_RETURN_NULL( ... ) \ 230 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NOT_GREATER_THAN_0_RETURN_NULL, __VA_ARGS__ ); 231 | 232 | // If a parameter is not greater than `0` returns 233 | #define __GREATER_THAN_0_RETURN_VOID( ... ) \ 234 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( IF_PARAMETER_NOT_GREATER_THAN_0_RETURN_VOID, __VA_ARGS__ ); 235 | 236 | // Avoids unused parameter warning by casting parameters to void 237 | #define __UNUSED( ... ) \ 238 | BUILD_MACRO( MACRO_EXPAND, N_ARGS( 0, __VA_ARGS__ ) )( UNUSED_PARAMETER, __VA_ARGS__ ) 239 | 240 | #endif --------------------------------------------------------------------------------