79825927

Date: 2025-11-20 20:09:19
Score: 1.5
Natty:
Report link

You're using your disassembler wrong.

Right off the bat, we can tell that the load and the jump don't target the same address, because adrp generates addresses aligned to 0x1000 bytes, so the bottom 12 bits of the load are 0x6c8 whereas the bottom 12 bits of the jump are 0x068. They can't possibly be the same.

Going deeper: you're on macOS 26.0.1 (25A362) and this is the function you're looking at:

;-- __malloc_zone_calloc:
0x1802f9ff0      085435b0       adrp x8, sym._ctr_des
0x1802f9ff4      08dd41f9       ldr x8, [x8, 0x3b8]
0x1802f9ff8      095435f0       adrp x9, 0x1ead7c000
0x1802f9ffc      296943f9       ldr x9, [x9, 0x6d0]
0x1802fa000      1f0100eb       cmp x8, x0
0x1802fa004      200940fa       ccmp x9, 0, 0, eq
0x1802fa008      81000054       b.ne 0x1802fa018
0x1802fa00c      085c36d0       adrp x8, 0x1ece7c000
0x1802fa010      083540f9       ldr x8, [x8, 0x68]
0x1802fa014      000140f9       ldr x0, [x8]
0x1802fa018      085435d0       adrp x8, 0x1ead7c000
0x1802fa01c      08215b39       ldrb w8, [x8, 0x6c8]
0x1802fa020      48020037       tbnz w8, 0, 0x1802fa068
0x1802fa024      085435d0       adrp x8, 0x1ead7c000
0x1802fa028      085143f9       ldr x8, [x8, 0x6a0]
0x1802fa02c      e80100b5       cbnz x8, 0x1802fa068
0x1802fa030      086840b9       ldr w8, [x0, 0x68]
0x1802fa034      1f310071       cmp w8, 0xc
0x1802fa038      89010054       b.ls 0x1802fa068
0x1802fa03c      1f410071       cmp w8, 0x10
0x1802fa040      e3000054       b.lo 0x1802fa05c
0x1802fa044      045440f9       ldr x4, [x0, 0xa8]
0x1802fa048      e8031eaa       mov x8, x30
0x1802fa04c      e843c1da       xpaci x8
0x1802fa050      038542d3       ubfx x3, x8, 2, 0x20
0x1802fa054      50c68dd2       mov x16, 0x6e32
0x1802fa058      90081fd7       braa x4, x16
0x1802fa05c      031040f9       ldr x3, [x0, 0x20]
0x1802fa060      f03688d2       mov x16, 0x41b7
0x1802fa064      70081fd7       braa x3, x16
0x1802fa068      01000014       b sym.__malloc_zone_calloc_instrumented_or_legacy

To prove that, let's look at these three instructions:

0x1802fa018      085435d0       adrp x8, 0x1ead7c000
0x1802fa01c      08215b39       ldrb w8, [x8, 0x6c8]
0x1802fa020      48020037       tbnz w8, 0, 0x1802fa068
  1. The ldrb is the exact same as in your snippet, that's how I found this in the first place.
  2. The adrp has a page delta encoding of 0x6aa82000, which your disassembler shows as 0x6aa82 in decimal, i.e. 436866. Together, these two are almost guaranteed to uniquely identify your dyld_shared_cache, since there's over 3000 libraries merged in there (you'll notice that the full delta of 0x6aa826c8 is almost 1.8GB away from the instruction performing the load).
  3. The bottom 14 bits of the tbnz address matches (i.e. 0x18c2b6068 & 0x3fff == 0x1802fa068 & 0x3fff == 0x2068).

This tells us that your cache is running with an ASLR slide of 0xbfbc000 versus the unslid image on disk. So your slid address of 0x18c2b6068 would correspond to unslid 0x1802fa068 - which is the last instruction of the function above, which is exactly what - and that's what makes sense, jumps within functions are what tb[n]z are usually used for, with their rather limited bits for jump distance. It's also what my disassembler is showing.

So how did you get to malloc_logger? Well that's the next load after that:

0x1802fa024      085435d0       adrp x8, 0x1ead7c000
0x1802fa028      085143f9       ldr x8, [x8, 0x6a0]
0x1802fa02c      e80100b5       cbnz x8, 0x1802fa068

The variable that's loaded for the tbnz check is malloc_slowpath, and if I got there and print a bunch of surrounding stuff as instructions, I see this:

[0x1ead7c6c8]> pd -10
         ;-- _malloc_logger:
         0x1ead7c6a0      00000000       invalid
         0x1ead7c6a4      00000000       invalid
         0x1ead7c6a8      00000000       invalid
         ;-- _malloc_tracing_enabled:
         0x1ead7c6ac  ~   00000000       invalid
         ;-- _malloc_interposition_compat:
         0x1ead7c6af      00             unaligned
         0x1ead7c6b0      00000000       invalid
         ;-- _malloc_sec_transition_policy:
         0x1ead7c6b4      00000000       invalid
         ;-- _malloc_sec_transition_early_malloc_support:
         0x1ead7c6b8      00000000       invalid
         0x1ead7c6bc      00000000       invalid
         ;-- _malloc_check_start:
         0x1ead7c6c0      00000000       invalid
[0x1ead7c6c8]> pd 10
         ;-- _malloc_slowpath:
         0x1ead7c6c8      00000000       invalid
         0x1ead7c6cc      00000000       invalid
         ;-- _lite_zone:
         0x1ead7c6d0      00000000       invalid
         0x1ead7c6d4      00000000       invalid
         ;-- _malloc_zero_on_free_sample_period:
         0x1ead7c6d8      00000000       invalid
         0x1ead7c6dc      00000000       invalid
         ;-- ___mach_stack_logging_shared_memory_address:
         0x1ead7c6e0      00000000       invalid
         0x1ead7c6e4      00000000       invalid
         ;-- _stack_logging_enable_logging:
         0x1ead7c6e8      00000000       invalid
         0x1ead7c6ec      00000000       invalid

So the first load is for malloc_slowpath, which is not too far from malloc_logger, which is the target of the load right after that. But either way, we are in the DATA segment here, these are variables, not functions, there is no code here!

As an aside, your disassembler may not be particularly good (or suited to arm64 or Darwin) either, based off the poor display of the adrp immediate, and the ; <+120> comment on tbnz, which is entirely wrong (it's probably meant to say 0x120, but it's a 0x48 bytes delta, which implies a shift of << 2, except that has already been applied to the value in the instruction encoding... it's a mess).

But hey, did you know that this code is open source?

Reasons:
  • RegEx Blacklisted phrase (3): did you get to
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • High reputation (-2):
Posted by: Siguza