Skip to content

Commit

Permalink
Deal with breakage caused by macOS 12.5, fixes issue steven-michaud#35
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-michaud committed Jul 30, 2022
1 parent ff7a66c commit cf7054e
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 29 deletions.
22 changes: 18 additions & 4 deletions 0-whats-new.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# What's New in Version 6.0.4

macOS 12.5 and macOS 10.15.7 build 19H2026 both broke HookCase. The
Catalina breakage was minor and easily fixed. The Monterey breakage
was larger, and once again resulted from a change of the kind that
normally only happens in major releases. This time none of the
internal kernel structures used by HookCase were altered. But the
interpretation of `vm_map_entry.vme_object` did change -- from a
union of simple pointers to one of "packed" pointers.

For more information see
[Issue #35](https://github.com/steven-michaud/HookCase/issues/35)
and [Issue #36](https://github.com/steven-michaud/HookCase/issues/36).

# What's New in Version 6.0.3

macOS 12.4 once again broke HookCase, by making changes that normally
Expand Down Expand Up @@ -59,7 +73,7 @@ information see

This version of HookCase fixes a bug that caused intermittent
instability, though not kernel panics. I fixed it by tweaking the
[code at the heart of HookCase's watchpoint support](HookCase/HookCase/HookCase.cpp#L13001).
[code at the heart of HookCase's watchpoint support](HookCase/HookCase/HookCase.cpp#L13077).
See [Issue #26](https://github.com/steven-michaud/HookCase/issues/26)
for more information.

Expand Down Expand Up @@ -242,7 +256,7 @@ HookCase now supports macOS Mojave (10.14).

But Mojave's Debug kernel is currently very flaky -- lots of panics,
with and without HookCase. So support for the Debug kernel
[has been disabled](HookCase/HookCase/HookCase.cpp#L469), at least
[has been disabled](HookCase/HookCase/HookCase.cpp#L487), at least
temporarily.

# What's New in Version 2.1
Expand Down Expand Up @@ -272,12 +286,12 @@ can now hook methods that aren't in their module's symbol table. For
more information see
[Hooked_sub_123abc() in the hook library template](HookLibraryTemplate/hook.mm#L1125).

* Version 2.0 [fixes a bug](HookCase/HookCase/HookCase.cpp#L11065) that
* Version 2.0 [fixes a bug](HookCase/HookCase/HookCase.cpp#L11141) that
prevented interpose hooks from working outside the shared cache of
system modules.

* Version 2.0
[fixes a previously undiscovered edge case](HookCase/HookCase/HookCase.cpp#L12735)
[fixes a previously undiscovered edge case](HookCase/HookCase/HookCase.cpp#L12811)
of an Apple kernel panic bug that was partially fixed in version 1.

* Version 2.0
Expand Down
2 changes: 1 addition & 1 deletion 1-more-about.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ hook that method as a process starts up, perform our own
initialization, then allow the original method to run.

For more information, the best place to start is the
[long series of comments](HookCase/HookCase/HookCase.cpp#L7979)
[long series of comments](HookCase/HookCase/HookCase.cpp#L8055)
in `HookCase.cpp` before the definition of `C_64_REDZONE_LEN`.
4 changes: 2 additions & 2 deletions HookCase/HookCase.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@
MODULE_NAME = org.smichaud.HookCase;
MODULE_START = HookCase_start;
MODULE_STOP = HookCase_stop;
MODULE_VERSION = 6.0.3;
MODULE_VERSION = 6.0.4;
PRODUCT_BUNDLE_IDENTIFIER = org.smichaud.HookCase;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = kext;
Expand All @@ -247,7 +247,7 @@
MODULE_NAME = org.smichaud.HookCase;
MODULE_START = HookCase_start;
MODULE_STOP = HookCase_stop;
MODULE_VERSION = 6.0.3;
MODULE_VERSION = 6.0.4;
PRODUCT_BUNDLE_IDENTIFIER = org.smichaud.HookCase;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = kext;
Expand Down
114 changes: 95 additions & 19 deletions HookCase/HookCase/HookCase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,24 @@ bool macOS_Monterey_4_or_greater()
return ((OSX_Version() & 0xFF) >= 0x50);
}

bool macOS_Monterey_less_than_5()
{
if (!((OSX_Version() & 0xFF00) == MAC_OS_X_VERSION_12_HEX)) {
return false;
}
// The output of "uname -r" for macOS 12.5 is actually "21.6.0".
return ((OSX_Version() & 0xFF) < 0x60);
}

bool macOS_Monterey_5_or_greater()
{
if (!((OSX_Version() & 0xFF00) == MAC_OS_X_VERSION_12_HEX)) {
return false;
}
// The output of "uname -r" for macOS 12.5 is actually "21.6.0".
return ((OSX_Version() & 0xFF) >= 0x60);
}

bool OSX_Version_Unsupported()
{
return (((OSX_Version() & 0xFF00) < MAC_OS_X_VERSION_10_9_HEX) ||
Expand Down Expand Up @@ -2315,13 +2333,71 @@ vm_map_offset_t map_entry_end(vm_map_entry_t entry)
return entry_local->vme_end;
}

vm_object_t map_entry_object(vm_map_entry_t entry)
// As of macOS 12.5, a flag in the 'vm_map_entry' structure's
// 'vme_object' member is used to determine whether or not the
// map entry is for a submap.
bool map_entry_is_submap(vm_map_entry_t entry)
{
if (!entry) {
return NULL;
return false;
}

bool retval = false;
vm_map_entry_fake_t entry_local = (vm_map_entry_fake_t) entry;
if (macOS_Monterey_less_than_5()) {
retval = entry_local->is_sub_map;
} else {
uintptr_t value = (uintptr_t) entry_local->vme_object.vmo_object;
uintptr_t flag = (value & 0xffff);
retval = ((flag & 2) != 0);
}

return retval;
}

// What's returned may be either an "object" or a "submap". As of macOS 12.5,
// the 'vm_map_entry' structure's 'vme_object' member is "packed". I don't
// know why -- no space seems to have been saved.
union vm_map_object map_entry_object_unpack_ptr(vm_object_t p)
{
uintptr_t value = (uintptr_t) p;

union vm_map_object retval;
retval.vmo_object = p;

if (macOS_Monterey_less_than_5()) {
return retval;
}

uintptr_t flag = (value & 0xffff);
bool is_sub_map = ((flag & 2) != 0);

if (is_sub_map) {
value &= 0xfffffffffffffffc;
} else {
uintptr_t raw = (value >> 32);
if (raw != 0) {
value = ((value >> 26) & 0xffffffffffffffc0);
value += 0xffffff7f80000000;
} else {
value = 0;
}
}

retval.vmo_object = (vm_object_t) value;
return retval;
}

// What's returned may be either an "object" or a "submap".
union vm_map_object map_entry_object(vm_map_entry_t entry)
{
if (!entry) {
union vm_map_object retval;
retval.vmo_object = NULL;
return retval;
}
vm_map_entry_fake_t entry_local = (vm_map_entry_fake_t) entry;
return entry_local->vme_object.vmo_object;
return map_entry_object_unpack_ptr(entry_local->vme_object.vmo_object);
}

vm_object_offset_t map_entry_offset(vm_map_entry_t entry)
Expand Down Expand Up @@ -5150,6 +5226,12 @@ typedef struct uthread_fake_monterey_1
int uu_flag; // Offset 0xf8
} *uthread_fake_monterey_1_t;

typedef struct uthread_fake_monterey_3
{
uint64_t pad[30];
int uu_flag; // Offset 0xf0
} *uthread_fake_monterey_3_t;

typedef struct uthread_fake_catalina
{
uint64_t pad[33];
Expand Down Expand Up @@ -5200,7 +5282,9 @@ int get_uu_flag(uthread_t uthread)

static vm_map_offset_t offset_in_struct = -1;
if (offset_in_struct == -1) {
if (macOS_Monterey_1_or_greater()) {
if (macOS_Monterey_3_or_greater()) {
offset_in_struct = offsetof(struct uthread_fake_monterey_3, uu_flag);
} else if (macOS_Monterey_1_or_greater()) {
offset_in_struct = offsetof(struct uthread_fake_monterey_1, uu_flag);
} else if (macOS_Monterey()) {
offset_in_struct = offsetof(struct uthread_fake_monterey, uu_flag);
Expand Down Expand Up @@ -5402,13 +5486,11 @@ void vm_submap_iterate_entries(vm_map_t submap, vm_map_offset_t start,
}

while ((entry != vm_map_to_entry(submap)) && (entry_start < end_fixed)) {
vm_map_entry_fake_t an_entry = (vm_map_entry_fake_t) entry;

if (an_entry->is_sub_map) {
if (map_entry_is_submap(entry)) {
vm_map_offset_t submap_start = map_entry_offset(entry);
vm_map_offset_t submap_end =
map_entry_offset(entry) + end_fixed - entry_start;
vm_submap_iterate_entries(an_entry->vme_object.vmo_submap,
vm_submap_iterate_entries(map_entry_object(entry).vmo_submap,
submap_start, submap_end, submap_level + 1,
iterator, info);
} else {
Expand Down Expand Up @@ -5465,13 +5547,11 @@ void vm_map_iterate_entries(vm_map_t map, vm_map_offset_t start,
}

while ((entry != vm_map_to_entry(map)) && (entry_start < end_fixed)) {
vm_map_entry_fake_t an_entry = (vm_map_entry_fake_t) entry;

if (an_entry->is_sub_map) {
if (map_entry_is_submap(entry)) {
vm_map_offset_t submap_start = map_entry_offset(entry);
vm_map_offset_t submap_end =
map_entry_offset(entry) + end_fixed - entry_start;
vm_submap_iterate_entries(an_entry->vme_object.vmo_submap,
vm_submap_iterate_entries(map_entry_object(entry).vmo_submap,
submap_start, submap_end, 1, iterator, info);
} else {
iterator(map, entry, 0, info);
Expand Down Expand Up @@ -7765,7 +7845,7 @@ void report_region_iterator(vm_map_t map, vm_map_entry_t entry,
entry_start = an_entry->vme_start;
entry_end = an_entry->vme_end;
entry_size = entry_end - entry_start;
object = an_entry->vme_object.vmo_object;
object = map_entry_object(entry).vmo_object;
offset = map_entry_offset(entry);

if (object) {
Expand Down Expand Up @@ -7837,9 +7917,7 @@ void user_region_codesigned_iterator(vm_map_t map, vm_map_entry_t entry,

bool is_signed = false;

vm_map_entry_fake_t an_entry = (vm_map_entry_fake_t) entry;

vm_object_t object = an_entry->vme_object.vmo_object;
vm_object_t object = map_entry_object(entry).vmo_object;
vm_object_offset_t offset = map_entry_offset(entry);

if (object) {
Expand Down Expand Up @@ -7895,9 +7973,7 @@ void sign_user_pages_iterator(vm_map_t map, vm_map_entry_t entry,

bool sign = (bool) info;

vm_map_entry_fake_t an_entry = (vm_map_entry_fake_t) entry;

vm_object_t object = an_entry->vme_object.vmo_object;
vm_object_t object = map_entry_object(entry).vmo_object;
vm_object_offset_t offset = map_entry_offset(entry);

if (!object) {
Expand Down
4 changes: 2 additions & 2 deletions HookCase/HookCase/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string>6.0.3</string>
<string>6.0.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>6.0.3</string>
<string>6.0.4</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2021 Steven Michaud. All rights reserved.</string>
<key>OSBundleLibraries</key>
Expand Down
2 changes: 1 addition & 1 deletion examples-kernel-logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ kernel extensions whose `start()` method fails.

Note that there's a workaround, which involves installing a serial
port and using `kprintf()` to write to it. For more information see
[HookCase_start()](HookCase/HookCase/HookCase.cpp#L14054).
[HookCase_start()](HookCase/HookCase/HookCase.cpp#L14130).

The root of the problem is that the messages received by Apple's new
logging subsystem no longer contain full strings. Instead each
Expand Down

0 comments on commit cf7054e

Please sign in to comment.