Skip to content

Commit 14a3e5a

Browse files
committed
added arg check and improved error log
1 parent 2354cb1 commit 14a3e5a

13 files changed

Lines changed: 79 additions & 46 deletions

File tree

.clang-format

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
---
21
# We'll use defaults from the LLVM style, but with 4 columns indentation.
32
BasedOnStyle: LLVM
43
IndentWidth: 4
5-
---
6-
Language: Cpp
7-
# Force pointers to the type for C++.
84
ColumnLimit: 120
95
AlignConsecutiveMacros: AcrossEmptyLines
106
AllowShortFunctionsOnASingleLine: false

.clangd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ Diagnostics:
1313
Add: [bugprone-*, cert-*, modernize-*, performance-*]
1414
Remove: [bugprone-easily-swappable-parameters]
1515
FastCheckFilter: None
16+
17+
Completion:
18+
HeaderInsertion: Never

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2026 Antibiotics
3+
Copyright (c) 2024-2026 Antibiotics
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
55
## Features
66

7-
- inline hook
8-
- symbol interposing
9-
- symbol resolving
10-
- objc runtime hook
7+
- inline hook
8+
- symbol interposing
9+
- symbol resolving
10+
- objc runtime hook
1111

1212
## Building
1313

@@ -22,18 +22,20 @@ make
2222
```
2323

2424
Available targets:
25-
- `static` (default) build static library
26-
- `shared` build shared library
27-
- `all` build both static and shared libraries
28-
- `test` run tinyhook tests
25+
26+
- `static` (default) build static library
27+
- `shared` build shared library
28+
- `all` build both static and shared libraries
29+
- `test` run tinyhook tests
2930

3031
Available variables:
31-
- `ARCH` the arch to build: `arm64`, `arm64e`, `x86_64`
32-
- `TARGET` targeting os: `macosx`(default), `iphoneos`
33-
- `MIN_OSVER` minimum os version requirement
34-
- `DEBUG` generate debug infomation
35-
- `COMPACT` no error log output (not recommended!)
36-
- `NO_EXPORT` hide all symbols (don't use this for dynamic library)
32+
33+
- `ARCH` the arch to build: `arm64`, `arm64e`, `x86_64`
34+
- `TARGET` targeting os: `macosx`(default), `iphoneos`
35+
- `MIN_OSVER` minimum os version requirement
36+
- `DEBUG` generate debug infomation
37+
- `COMPACT` no error log output (not recommended!)
38+
- `NO_EXPORT` hide all symbols (don't use this for dynamic library)
3739

3840
For example, building shared library for iOS 18.0+ `arm64e` binary with `DEBUG` enabled
3941

src/exhook.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ static int get_jump_size(const void *src, const void *dst) {
1111
}
1212

1313
int tiny_hook_ex(th_bak_t *bak, void *function, void *destination, void **origin) {
14+
ARG_CHECK(bak != NULL);
15+
ARG_CHECK(function != NULL);
16+
ARG_CHECK(destination != NULL);
1417
bak->address = function;
1518
bak->jump_size = get_jump_size(function, destination);
1619
read_mem(bak->head_bak, bak->address, bak->jump_size);
1720
return tiny_hook(function, destination, origin);
1821
}
1922

2023
int tiny_unhook_ex(const th_bak_t *bak) {
24+
ARG_CHECK(bak != 0);
2125
return write_mem(bak->address, bak->head_bak, bak->jump_size);
2226
}

src/interpose.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#endif
1212

1313
int tiny_interpose(uint32_t image_index, const char *symbol_name, void *replacement, void **origin) {
14+
ARG_CHECK(symbol_name != NULL);
15+
ARG_CHECK(replacement != NULL);
1416
intptr_t image_slide = _dyld_get_image_vmaddr_slide(image_index);
1517
struct mach_header_64 *mh_header = (struct mach_header_64 *)_dyld_get_image_header(image_index);
1618
struct load_command *ld_command = (void *)mh_header + sizeof(struct mach_header_64);
@@ -52,7 +54,7 @@ int tiny_interpose(uint32_t image_index, const char *symbol_name, void *replacem
5254
ld_command = (void *)ld_command + ld_command->cmdsize;
5355
}
5456
if (linkedit_cmd == NULL || symtab_cmd == NULL || dysymtab_cmd == NULL) {
55-
LOG_ERROR("tiny_interpose: bad mach-o structure!");
57+
LOG_ERROR("tiny_interpose: bad mach-o structure for image_index %d!", image_index);
5658
return 1;
5759
}
5860
void *linkedit_base = (void *)image_slide + linkedit_cmd->vmaddr - linkedit_cmd->fileoff;
@@ -80,7 +82,7 @@ int tiny_interpose(uint32_t image_index, const char *symbol_name, void *replacem
8082
err = mach_vm_protect(mach_task_self(), (mach_vm_address_t)sym_ptrs, sym_sec->size, FALSE,
8183
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
8284
if (err != 0) {
83-
LOG_ERROR("mach_vm_protect: %s", mach_error_string(err));
85+
LOG_ERROR("mach_vm_protect failed for address %p: %s", sym_ptrs, mach_error_string(err));
8486
break;
8587
}
8688
}
@@ -93,7 +95,7 @@ int tiny_interpose(uint32_t image_index, const char *symbol_name, void *replacem
9395

9496
if (!found) {
9597
err = -1;
96-
LOG_ERROR("tiny_interpose: no matching indirect symbol found!");
98+
LOG_ERROR("tiny_interpose: symbol '%s' not found in image_index %d!", symbol_name, image_index);
9799
}
98100
return err;
99101
}

src/memory.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,35 +39,39 @@ static inline void copy_mem(void *destination, const void *source, size_t len) {
3939
}
4040

4141
int read_mem(void *destination, const void *source, size_t len) {
42+
ARG_CHECK(destination != NULL);
43+
ARG_CHECK(source != NULL);
44+
ARG_CHECK(len != 0);
4245
int kr = 0;
4346
vm_offset_t data;
4447
mach_msg_type_number_t dataCnt;
45-
kr = mach_vm_read(mach_task_self(), (mach_vm_address_t)source, len, &data, &dataCnt);
48+
mach_port_t task = mach_task_self();
49+
kr = mach_vm_read(task, (mach_vm_address_t)source, len, &data, &dataCnt);
4650
if (kr != 0) {
47-
LOG_ERROR("mach_vm_read: %s", mach_error_string(kr));
51+
LOG_ERROR("mach_vm_read failed for address %p: %s", source, mach_error_string(kr));
4852
return kr;
4953
}
50-
memcpy((void *)destination, (void *)data, dataCnt);
51-
kr = mach_vm_deallocate(mach_task_self(), data, dataCnt);
54+
memcpy(destination, (void *)data, dataCnt);
55+
kr = mach_vm_deallocate(task, data, dataCnt);
5256
if (kr != 0) {
5357
LOG_ERROR("mach_vm_deallocate: %s", mach_error_string(kr));
5458
}
5559
return kr;
5660
}
5761

5862
int write_mem(void *destination, const void *source, size_t len) {
59-
int kr = 0;
60-
kr = mach_vm_protect_trap(mach_task_self(), (mach_vm_address_t)destination, len, FALSE,
61-
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
63+
ARG_CHECK(destination != NULL);
64+
ARG_CHECK(source != NULL);
65+
ARG_CHECK(len != 0);
66+
mach_port_t task = mach_task_self();
67+
mach_vm_address_t dst = (mach_vm_address_t)destination;
68+
int kr = mach_vm_protect_trap(task, dst, len, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
6269
if (kr != 0) {
63-
LOG_ERROR("mach_vm_protect: %s", mach_error_string(kr));
70+
LOG_ERROR("mach_vm_protect failed for address %p: %s", destination, mach_error_string(kr));
6471
return kr;
6572
}
6673
copy_mem(destination, source, len);
67-
kr = mach_vm_protect_trap(mach_task_self(), (mach_vm_address_t)destination, len, FALSE,
68-
VM_PROT_READ | VM_PROT_EXECUTE);
69-
if (kr != 0) {
70-
LOG_ERROR("mach_vm_protect: %s", mach_error_string(kr));
71-
}
72-
return kr;
74+
mach_vm_protect_trap(task, dst, len, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
75+
// might fail when editing __DATA, but not a big deal
76+
return 0;
7377
}

src/objcrt.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <objc/runtime.h> // objc_*, ...
55

66
Method ocrt_method(char type, const char *cls, const char *sel) {
7+
ARG_CHECK(cls != NULL);
8+
ARG_CHECK(sel != NULL);
79
Method oc_method = NULL;
810
Class oc_class = objc_getClass(cls);
911
SEL oc_selector = sel_registerName(sel);
@@ -22,6 +24,8 @@ Method ocrt_method(char type, const char *cls, const char *sel) {
2224
}
2325

2426
void *ocrt_impl(char type, const char *cls, const char *sel) {
27+
ARG_CHECK(cls != NULL);
28+
ARG_CHECK(sel != NULL);
2529
return method_getImplementation(ocrt_method(type, cls, sel));
2630
}
2731

@@ -31,7 +35,7 @@ static Method ensure_method(const char *cls, const char *sel) {
3135
oc_method = ocrt_method('-', cls, sel);
3236
}
3337
if (oc_method == NULL) {
34-
LOG_ERROR("ensure_method: method not found!");
38+
LOG_ERROR("ensure_method: method '[%s %s]' not found!", cls, sel);
3539
}
3640
return oc_method;
3741
}
@@ -47,6 +51,9 @@ int ocrt_swap(const char *cls1, const char *sel1, const char *cls2, const char *
4751
}
4852

4953
int ocrt_hook(const char *cls, const char *sel, void *destination, void **origin) {
54+
ARG_CHECK(cls != NULL);
55+
ARG_CHECK(sel != NULL);
56+
ARG_CHECK(destination != NULL);
5057
Method oc_method = ensure_method(cls, sel);
5158
if (oc_method == NULL) {
5259
return 1;

src/private.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#ifdef COMPACT
2020
#define LOG_ERROR(fmt, ...) ((void)0)
21+
#define ARG_CHECK(x) ((void)0)
2122
#else
2223
#if TARGET_OS_OSX
2324
#include <printf.h> // fprintf()
@@ -28,6 +29,11 @@
2829
os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_ERROR, "ERROR [%s:%d]: " fmt "\n", __FILE__, __LINE__, \
2930
##__VA_ARGS__)
3031
#endif
32+
#define ARG_CHECK(x) \
33+
if (!(x)) { \
34+
LOG_ERROR("ARG_CHECK '%s' failed", #x); \
35+
abort(); \
36+
}
3137
#endif
3238

3339
#define MB (1ll << 20)

src/symsolve/symexport.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,13 @@ static void *trie_query(const uint8_t *export, const char *name) {
5959
}
6060

6161
void *symexp_solve(uint32_t image_index, const char *symbol_name) {
62+
ARG_CHECK(symbol_name != NULL);
6263
void *symbol_address = NULL;
6364
intptr_t image_slide = _dyld_get_image_vmaddr_slide(image_index);
6465
struct mach_header_64 *mh_header = (struct mach_header_64 *)_dyld_get_image_header(image_index);
6566
struct load_command *ld_command = (void *)mh_header + sizeof(struct mach_header_64);
6667
if (mh_header == NULL) {
67-
LOG_ERROR("symexp_solve: image_index out of range!");
68+
LOG_ERROR("symexp_solve: image_index %d out of range!", image_index);
6869
}
6970
struct dyld_info_command *dyldinfo_cmd = NULL;
7071
struct segment_command_64 *linkedit_cmd = NULL;
@@ -87,7 +88,7 @@ void *symexp_solve(uint32_t image_index, const char *symbol_name) {
8788
ld_command = (void *)ld_command + ld_command->cmdsize;
8889
}
8990
if (linkedit_cmd == NULL) {
90-
LOG_ERROR("symexp_solve: __LINKEDIT segment not found!");
91+
LOG_ERROR("symexp_solve: __LINKEDIT segment not found for image_index %d!", image_index);
9192
return NULL;
9293
}
9394
// stroff and strtbl are in the __LINKEDIT segment
@@ -99,7 +100,9 @@ void *symexp_solve(uint32_t image_index, const char *symbol_name) {
99100
else if (export_trie != NULL)
100101
export_offset = linkedit_base + export_trie->dataoff;
101102
else {
102-
LOG_ERROR("symexp_solve: neither LC_DYLD_INFO_ONLY nor LC_DYLD_EXPORTS_TRIE load command found!");
103+
LOG_ERROR(
104+
"symexp_solve: neither LC_DYLD_INFO_ONLY nor LC_DYLD_EXPORTS_TRIE load command found for image_index %d!",
105+
image_index);
103106
return NULL;
104107
}
105108
symbol_address = trie_query(export_offset, symbol_name);
@@ -108,7 +111,7 @@ void *symexp_solve(uint32_t image_index, const char *symbol_name) {
108111
symbol_address += (uint64_t)mh_header;
109112
}
110113
else {
111-
LOG_ERROR("symexp_solve: symbol not found!");
114+
LOG_ERROR("symexp_solve: symbol '%s' not found in image_index %d!", symbol_name, image_index);
112115
}
113116
return symbol_address;
114117
}

0 commit comments

Comments
 (0)