├── 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
--------------------------------------------------------------------------------