diff --git a/.github/workflows/build-lkm.yml b/.github/workflows/build-lkm.yml
index 2da532cc0659..e5ed7eac475e 100644
--- a/.github/workflows/build-lkm.yml
+++ b/.github/workflows/build-lkm.yml
@@ -5,6 +5,7 @@ on:
jobs:
build-lkm:
strategy:
+ fail-fast: false
matrix:
kmi:
- android12-5.10
diff --git a/.github/workflows/build-manager.yml b/.github/workflows/build-manager.yml
index 9031b92da45d..e3cd051d5e77 100644
--- a/.github/workflows/build-manager.yml
+++ b/.github/workflows/build-manager.yml
@@ -7,19 +7,24 @@ on:
- '.github/workflows/build-manager.yml'
- '.github/workflows/build-lkm.yml'
- '.github/workflows/ksud.yml'
+ - '.github/workflows/ddl-lkm.yml'
- 'manager/**'
- 'kernel/**'
- 'userspace/**'
+ - 'scripts/ksubot.py'
pull_request:
branches: [ "main", "dev" ]
paths:
- '.github/workflows/build-manager.yml'
- '.github/workflows/build-lkm.yml'
- '.github/workflows/ksud.yml'
+ - '.github/workflows/ddl-lkm.yml'
- 'manager/**'
- 'kernel/**'
- 'userspace/**'
+ - 'scripts/ksubot.py'
workflow_call:
+ workflow_dispatch:
jobs:
build-lkm:
@@ -79,14 +84,14 @@ jobs:
- name: Setup need_upload
id: need_upload
run: |
- if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
+ if [ ! -z "${{ secrets.BOT_TOKEN }}" ] && [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
echo "UPLOAD=true" >> $GITHUB_OUTPUT
else
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- name: Write key
- if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
+ if: ${{ github.event_name != 'pull_request' || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
{
@@ -95,7 +100,7 @@ jobs:
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
echo KEYSTORE_FILE='key.jks'
} >> gradle.properties
- echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
+ echo "${{ secrets.KEYSTORE }}" | base64 -d > key.jks
fi
- name: Setup Java
@@ -157,11 +162,10 @@ jobs:
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
- CHAT_ID: ${{ secrets.CHAT_ID }}
+ CHAT_ID: ${{ vars.CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
- MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
- COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
- COMMIT_URL: ${{ github.event.head_commit.url }}
+ MESSAGE_THREAD_ID: ${{ vars.MESSAGE_THREAD_ID }}
+ GITHUB_EVENT: ${{ toJson(github.event) }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
TITLE: Manager
BRANCH: ${{ github.ref_name }}
diff --git a/.github/workflows/ddk-lkm.yml b/.github/workflows/ddk-lkm.yml
index 4e8e041b39ff..b51722720d91 100644
--- a/.github/workflows/ddk-lkm.yml
+++ b/.github/workflows/ddk-lkm.yml
@@ -31,6 +31,21 @@ jobs:
cd kernel
+ if [[ "${{ inputs.kmi }}" == *"5.1"* ]]; then
+ echo "=== fix modpost ==="
+ sed -i '/s->module = exp->module;/s/^/\/\//' /opt/ddk/src/*/scripts/mod/modpost.c
+ pushd /opt/ddk/kdir/*
+ CMD_O=$(grep 'cmd_scripts/mod/modpost.o := ' scripts/mod/.modpost.o.cmd | sed 's/cmd_scripts\/mod\/modpost.o := //g')
+ CMD_2=$(grep 'cmd_scripts/mod/file2alias.o := ' scripts/mod/.file2alias.o.cmd | sed 's/cmd_scripts\/mod\/file2alias.o := //g')
+ CMD_3=$(grep 'cmd_scripts/mod/sumversion.o := ' scripts/mod/.sumversion.o.cmd | sed 's/cmd_scripts\/mod\/sumversion.o := //g')
+ CMD_L=$(grep 'cmd_scripts/mod/modpost := ' scripts/mod/.modpost.cmd | sed 's/cmd_scripts\/mod\/modpost := //g')
+ $CMD_O
+ $CMD_2
+ $CMD_3
+ $CMD_L
+ popd
+ fi
+
echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ==="
CONFIG_KSU=m CC=clang make
diff --git a/.gitignore b/.gitignore
index 9e7e95876351..79d923791aec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
.idea
-.vscode
+/.vscode
CLAUDE.md
AGENTS.md
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index 03a9346ea904..87d081a804e1 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,10 +1,10 @@
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md)
-# KernelSU
+# My KernelSU
-A kernel-based root solution for Android devices.
+A [KernelSU](https://github.com/tiann/KernelSU/commit/6bac4b1bd1825a7902502425cdfb07ca6d6256a6)-based root solution for Android devices.
[](https://github.com/tiann/KernelSU/releases/latest)
[](https://hosted.weblate.org/engage/kernelsu)
diff --git a/kernel/.gitignore b/kernel/.gitignore
index 15547df1c7de..85fecbf8cdb4 100644
--- a/kernel/.gitignore
+++ b/kernel/.gitignore
@@ -12,7 +12,7 @@ compile_commands.json
*.mod.c
*.symvers*
*.order
-.*.ko.cmd
+.*.cmd
.tmp_versions/
libs/
obj/
diff --git a/kernel/.vscode/generate_compdb.py b/kernel/.vscode/generate_compdb.py
index 8866913868f4..22c5a0007d8c 100755
--- a/kernel/.vscode/generate_compdb.py
+++ b/kernel/.vscode/generate_compdb.py
@@ -44,6 +44,8 @@ def gen_compile_commands(cmd_file_search_path, out_dir):
if not cmd_file_search_path:
cmd_file_search_path = [out_dir]
+ else:
+ cmd_file_search_path += [out_dir]
cmd_files = []
for search_path in cmd_file_search_path:
diff --git a/kernel/Kbuild b/kernel/Kbuild
index 70511859bd85..5f7157e62ce0 100644
--- a/kernel/Kbuild
+++ b/kernel/Kbuild
@@ -14,7 +14,10 @@ kernelsu-objs += feature.o
kernelsu-objs += ksud.o
kernelsu-objs += seccomp_cache.o
kernelsu-objs += file_wrapper.o
-kernelsu-objs += util.o
+kernelsu-objs += pte.o
+kernelsu-objs += patch.o
+kernelsu-objs += inline_hook.o
+kernelsu-objs += trampoline.o
kernelsu-objs += selinux/selinux.o
kernelsu-objs += selinux/sepolicy.o
@@ -60,12 +63,35 @@ $(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git repo
ccflags-y += -DKSU_VERSION=16
endif
+KSU_NEW_DCACHE_FLUSH := $(shell grep -q __flush_dcache_area $(srctree)/arch/arm64/include/asm/cacheflush.h ; echo $$?)
+$(info -- KSU_NEW_DCACHE_FLUSH: $(KSU_NEW_DCACHE_FLUSH))
+
+KSU_MTE_SYNC_TAGS_DEF := $(shell grep 'void mte_sync_tags' $(srctree)/arch/arm64/include/asm/mte.h | grep -v 'static inline')
+# 6.6
+KSU_MTE_SYNC_TAGS_NR_PAGES := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q 'nr_pages' && echo 1 || echo 0)
+# 6.1
+KSU_MTE_SYNC_TAGS_NORMAL := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q '(pte_t pte)' && echo 1 || echo 0)
+# 13-5.10
+KSU_MTE_SYNC_TAGS_OLD_PTE := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q 'old_pte' && echo 1 || echo 0)
+# 12-5.10
+KSU_MTE_SYNC_TAGS_PTEP := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q '*ptep' && echo 1 || echo 0)
+KSU_DEF_MTE_SYNC_TAGS := 'extern $(KSU_MTE_SYNC_TAGS_DEF)'
+
+$(info -- KSU_DEF_MTE_SYNC_TAGS: $(KSU_DEF_MTE_SYNC_TAGS))
+$(info -- KSU_MTE_SYNC_TAGS_NR_PAGES: $(KSU_MTE_SYNC_TAGS_NR_PAGES))
+$(info -- KSU_MTE_SYNC_TAGS_PTEP: $(KSU_MTE_SYNC_TAGS_PTEP))
+$(info -- KSU_MTE_SYNC_TAGS_OLD_PTE: $(KSU_MTE_SYNC_TAGS_OLD_PTE))
+$(info -- KSU_MTE_SYNC_TAGS_NORMAL: $(KSU_MTE_SYNC_TAGS_NORMAL))
+
+OFFICIAL_EXPECTED_SIZE := 0x033b
+OFFICIAL_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6
+
ifndef KSU_EXPECTED_SIZE
-KSU_EXPECTED_SIZE := 0x033b
+KSU_EXPECTED_SIZE := 384
endif
ifndef KSU_EXPECTED_HASH
-KSU_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6
+KSU_EXPECTED_HASH := 7e0c6d7278a3bb8e364e0fcba95afaf3666cf5ff3c245a3b63c8833bd0445cc4
endif
ifdef KSU_MANAGER_PACKAGE
@@ -78,6 +104,16 @@ $(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
+ccflags-y += -DOFFICIAL_EXPECTED_SIZE=$(OFFICIAL_EXPECTED_SIZE)
+ccflags-y += -DOFFICIAL_EXPECTED_HASH=\"$(OFFICIAL_EXPECTED_HASH)\"
+
+ccflags-y += -DKSU_NEW_DCACHE_FLUSH=$(KSU_NEW_DCACHE_FLUSH)
+
+ccflags-y += -DKSU_DEF_MTE_SYNC_TAGS=$(KSU_DEF_MTE_SYNC_TAGS)
+ccflags-y += -DKSU_MTE_SYNC_TAGS_NR_PAGES=$(KSU_MTE_SYNC_TAGS_NR_PAGES)
+ccflags-y += -DKSU_MTE_SYNC_TAGS_PTEP=$(KSU_MTE_SYNC_TAGS_PTEP)
+ccflags-y += -DKSU_MTE_SYNC_TAGS_OLD_PTE=$(KSU_MTE_SYNC_TAGS_OLD_PTE)
+ccflags-y += -DKSU_MTE_SYNC_TAGS_NORMAL=$(KSU_MTE_SYNC_TAGS_NORMAL)
ccflags-y += -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat -Wno-missing-prototypes
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
diff --git a/kernel/Makefile b/kernel/Makefile
index 28e5a3a802d6..4cda37033424 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -7,7 +7,7 @@ $(info -- MDIR: $(MDIR))
.PHONY: all compdb clean format check-format
all: check_symbol
- make -C $(KDIR) M=$(MDIR) modules
+ CONFIG_KSU=m make -C $(KDIR) M=$(MDIR) modules
./check_symbol kernelsu.ko $(KDIR)/vmlinux
compdb:
python3 $(MDIR)/.vscode/generate_compdb.py -O $(KDIR) $(MDIR)
diff --git a/kernel/allowlist.c b/kernel/allowlist.c
index 25de2a7ffd9a..cd1a6eb978dd 100644
--- a/kernel/allowlist.c
+++ b/kernel/allowlist.c
@@ -284,6 +284,10 @@ bool __ksu_is_allow_uid(uid_t uid)
return true;
}
+ if (unlikely(allow_shell) && uid == 2000) {
+ return true;
+ }
+
if (likely(uid <= BITMAP_UID_MAX)) {
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] &
(1 << (uid % BITS_PER_BYTE)));
@@ -340,6 +344,10 @@ void ksu_get_root_profile(uid_t uid, struct root_profile *profile)
goto use_default;
}
+ if (unlikely(allow_shell && uid == SHELL_UID)) {
+ goto use_default;
+ }
+
rcu_read_lock();
list_for_each_entry_rcu (p, &allow_list, list) {
if (uid == p->profile.current_uid && p->profile.allow_su) {
diff --git a/kernel/allowlist.h b/kernel/allowlist.h
index 2afc303836c2..d8d122e9a74b 100644
--- a/kernel/allowlist.h
+++ b/kernel/allowlist.h
@@ -53,3 +53,5 @@ static inline bool is_isolated_process(uid_t uid)
return appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID;
}
#endif
+
+extern bool allow_shell;
diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c
index 1c84127bd367..65a2f3fe26db 100644
--- a/kernel/apk_sign.c
+++ b/kernel/apk_sign.c
@@ -360,5 +360,7 @@ bool is_manager_apk(char *path)
return false;
}
#endif
- return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
+ return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH) ||
+ check_v2_signature(path, OFFICIAL_EXPECTED_SIZE,
+ OFFICIAL_EXPECTED_HASH);
}
\ No newline at end of file
diff --git a/kernel/app_profile.c b/kernel/app_profile.c
index f544dd8de4a3..befe352b5fd4 100644
--- a/kernel/app_profile.c
+++ b/kernel/app_profile.c
@@ -66,7 +66,7 @@ static void disable_seccomp(void)
{
struct task_struct *fake;
- fake = kmalloc(sizeof(*fake), GFP_ATOMIC);
+ fake = kmalloc(sizeof(*fake), GFP_KERNEL);
if (!fake) {
pr_warn("failed to alloc fake task_struct\n");
return;
diff --git a/kernel/hook.h b/kernel/hook.h
new file mode 100644
index 000000000000..fab52d5a77ea
--- /dev/null
+++ b/kernel/hook.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 bmax121. All Rights Reserved.
+ */
+
+#ifndef __KSU_H_HOOK_
+#define __KSU_H_HOOK_
+#include "linux/types.h" // IWYU pragma: keep
+#include "linux/version.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+#include "asm/patching.h" // IWYU pragma: keep
+#else
+#include "asm/insn.h" // IWYU pragma: keep
+#endif
+
+// https://github.com/bmax121/KernelPatch/blob/94e5be9cc3f8a6fbd9574155e3e9753200ab9bfb/kernel/include/hook.h#L54
+
+#define HOOK_INTO_BRANCH_FUNC
+
+typedef enum {
+ HOOK_NO_ERR = 0,
+ HOOK_BAD_ADDRESS = 4095,
+ HOOK_DUPLICATED = 4094,
+ HOOK_NO_MEM = 4093,
+ HOOK_BAD_RELO = 4092,
+ HOOK_TRANSIT_NO_MEM = 4091,
+ HOOK_CHAIN_FULL = 4090,
+} hook_err_t;
+
+#define HOOK_MEM_REGION_NUM 4
+#define TRAMPOLINE_MAX_NUM 6
+#define RELOCATE_INST_NUM (4 * 8 + 8 - 4)
+
+#define HOOK_CHAIN_NUM 0x10
+
+#define ARM64_NOP 0xd503201f
+#define ARM64_BTI_C 0xd503245f
+#define ARM64_BTI_J 0xd503249f
+#define ARM64_BTI_JC 0xd50324df
+#define ARM64_PACIASP 0xd503233f
+#define ARM64_PACIBSP 0xd503237f
+
+typedef struct {
+ // in
+ uint64_t func_addr;
+ uint64_t origin_addr;
+ uint64_t replace_addr;
+ uint64_t relo_addr;
+ // out
+ int32_t tramp_insts_num;
+ int32_t relo_insts_num;
+ uint32_t origin_insts[TRAMPOLINE_MAX_NUM] __attribute__((aligned(8)));
+ uint32_t tramp_insts[TRAMPOLINE_MAX_NUM] __attribute__((aligned(8)));
+ uint32_t relo_insts[RELOCATE_INST_NUM] __attribute__((aligned(8)));
+} hook_t __attribute__((aligned(8)));
+
+static inline int is_bad_address(void *addr)
+{
+ return ((uint64_t)addr & 0x8000000000000000) != 0x8000000000000000;
+}
+
+int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr,
+ uint64_t dst_addr);
+int32_t branch_relative(uint32_t *buf, uint64_t src_addr, uint64_t dst_addr);
+int32_t branch_absolute(uint32_t *buf, uint64_t addr);
+int32_t ret_absolute(uint32_t *buf, uint64_t addr);
+
+hook_err_t hook_prepare(hook_t *hook);
+int hook_install(hook_t *hook);
+
+/**
+ * @brief Inline-hook function which address is @param func with function @param replace,
+ * after hook, original @param func is backuped in @param backup.
+ *
+ * @note If multiple modules hook this function simultaneously,
+ * it will cause abnormality when unload the modules. Please use hook_wrap instead
+ *
+ * @see hook_wrap
+ *
+ * @param func
+ * @param replace
+ * @param backup
+ * @return hook_err_t
+ */
+hook_err_t hook(void *func, void *replace, void **backup);
+
+#define KSU_PATCH_TEXT_FLUSH_DCACHE 1
+#define KSU_PATCH_TEXT_FLUSH_ICACHE 2
+
+int ksu_patch_text(void *dst, void *src, size_t len, int flags);
+
+#endif
diff --git a/kernel/inline_hook.c b/kernel/inline_hook.c
new file mode 100644
index 000000000000..9a991db17799
--- /dev/null
+++ b/kernel/inline_hook.c
@@ -0,0 +1,607 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 bmax121. All Rights Reserved.
+ */
+#include "hook.h"
+#include "klog.h" // IWYU pragma: keep
+#include "linux/compiler.h"
+#include "linux/cpumask.h"
+#include "linux/gfp.h" // IWYU pragma: keep
+#include "linux/uaccess.h"
+#include "linux/vmalloc.h"
+#include "linux/stop_machine.h"
+#include "asm/cacheflush.h"
+#include "asm-generic/fixmap.h"
+#include "asm/pgtable.h"
+
+#include "pte.h"
+
+// https://github.com/bmax121/KernelPatch/blob/94e5be9cc3f8a6fbd9574155e3e9753200ab9bfb/kernel/base/hook.c#L562-L603
+
+#define bits32(n, high, low) \
+ ((uint32_t)((n) << (31u - (high))) >> (31u - (high) + (low)))
+#define bit(n, st) (((n) >> (st)) & 1)
+#define sign64_extend(n, len) \
+ (((uint64_t)((n) << (63u - (len - 1))) >> 63u) ? \
+ ((n) | (0xFFFFFFFFFFFFFFFF << (len))) : \
+ n)
+#define align_ceil(x, align) \
+ (((u64)(x) + (u64)(align) - 1) & ~((u64)(align) - 1))
+
+typedef uint32_t inst_type_t;
+typedef uint32_t inst_mask_t;
+
+#define INST_B 0x14000000
+#define INST_BC 0x54000000
+#define INST_BL 0x94000000
+#define INST_ADR 0x10000000
+#define INST_ADRP 0x90000000
+#define INST_LDR_32 0x18000000
+#define INST_LDR_64 0x58000000
+#define INST_LDRSW_LIT 0x98000000
+#define INST_PRFM_LIT 0xD8000000
+#define INST_LDR_SIMD_32 0x1C000000
+#define INST_LDR_SIMD_64 0x5C000000
+#define INST_LDR_SIMD_128 0x9C000000
+#define INST_CBZ 0x34000000
+#define INST_CBNZ 0x35000000
+#define INST_TBZ 0x36000000
+#define INST_TBNZ 0x37000000
+#define INST_HINT 0xD503201F
+#define INST_IGNORE 0x0
+
+#define MASK_B 0xFC000000
+#define MASK_BC 0xFF000010
+#define MASK_BL 0xFC000000
+#define MASK_ADR 0x9F000000
+#define MASK_ADRP 0x9F000000
+#define MASK_LDR_32 0xFF000000
+#define MASK_LDR_64 0xFF000000
+#define MASK_LDRSW_LIT 0xFF000000
+#define MASK_PRFM_LIT 0xFF000000
+#define MASK_LDR_SIMD_32 0xFF000000
+#define MASK_LDR_SIMD_64 0xFF000000
+#define MASK_LDR_SIMD_128 0xFF000000
+#define MASK_CBZ 0x7F000000u
+#define MASK_CBNZ 0x7F000000u
+#define MASK_TBZ 0x7F000000u
+#define MASK_TBNZ 0x7F000000u
+#define MASK_HINT 0xFFFFF01F
+#define MASK_IGNORE 0x0
+
+static inst_mask_t masks[] = {
+ MASK_B, MASK_BC, MASK_BL, MASK_ADR,
+ MASK_ADRP, MASK_LDR_32, MASK_LDR_64, MASK_LDRSW_LIT,
+ MASK_PRFM_LIT, MASK_LDR_SIMD_32, MASK_LDR_SIMD_64, MASK_LDR_SIMD_128,
+ MASK_CBZ, MASK_CBNZ, MASK_TBZ, MASK_TBNZ,
+ MASK_IGNORE,
+};
+static inst_type_t types[] = {
+ INST_B, INST_BC, INST_BL, INST_ADR,
+ INST_ADRP, INST_LDR_32, INST_LDR_64, INST_LDRSW_LIT,
+ INST_PRFM_LIT, INST_LDR_SIMD_32, INST_LDR_SIMD_64, INST_LDR_SIMD_128,
+ INST_CBZ, INST_CBNZ, INST_TBZ, INST_TBNZ,
+ INST_IGNORE,
+};
+
+static int32_t relo_len[] = {
+ 6, 8, 8, 4, 4, 6, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 2
+};
+
+// static uint64_t sign_extend(uint64_t x, uint32_t len)
+// {
+// char sign_bit = bit(x, len - 1);
+// unsigned long sign_mask = 0 - sign_bit;
+// x |= ((sign_mask >> len) << len);
+// return x;
+// }
+
+static int is_in_tramp(hook_t *hook, uint64_t addr)
+{
+ uint64_t tramp_start = hook->origin_addr;
+ uint64_t tramp_end = tramp_start + hook->tramp_insts_num * 4;
+ if (addr >= tramp_start && addr < tramp_end) {
+ return 1;
+ }
+ return 0;
+}
+
+static uint64_t relo_in_tramp(hook_t *hook, uint64_t addr)
+{
+ uint64_t tramp_start = hook->origin_addr;
+ uint64_t tramp_end = tramp_start + hook->tramp_insts_num * 4;
+ if (!(addr >= tramp_start && addr < tramp_end))
+ return addr;
+ uint32_t addr_inst_index = (addr - tramp_start) / 4;
+ uint64_t fix_addr = hook->relo_addr;
+ for (int i = 0; i < addr_inst_index; i++) {
+ inst_type_t inst = hook->origin_insts[i];
+ for (int j = 0; j < sizeof(relo_len) / sizeof(relo_len[0]); j++) {
+ if ((inst & masks[j]) == types[j]) {
+ fix_addr += relo_len[j] * 4;
+ break;
+ }
+ }
+ }
+ return fix_addr;
+}
+
+#ifdef HOOK_INTO_BRANCH_FUNC
+
+#endif
+
+static hook_err_t relo_b(hook_t *hook, uint64_t inst_addr, uint32_t inst,
+ inst_type_t type)
+{
+ uint32_t *buf = hook->relo_insts + hook->relo_insts_num;
+ uint64_t imm64;
+ if (type == INST_BC) {
+ uint64_t imm19 = bits32(inst, 23, 5);
+ imm64 = sign64_extend(imm19 << 2u, 21u);
+ } else {
+ uint64_t imm26 = bits32(inst, 25, 0);
+ imm64 = sign64_extend(imm26 << 2u, 28u);
+ }
+ uint64_t addr = inst_addr + imm64;
+ addr = relo_in_tramp(hook, addr);
+
+ uint32_t idx = 0;
+ if (type == INST_BC) {
+ buf[idx++] = (inst & 0xFF00001F) | 0x40u; // B. #8
+ buf[idx++] = 0x14000006; // B #24
+ }
+ buf[idx++] = 0x58000051; // LDR X17, #8
+ buf[idx++] = 0x14000003; // B #12
+ buf[idx++] = addr & 0xFFFFFFFF;
+ buf[idx++] = addr >> 32u;
+ if (type == INST_BL) {
+ buf[idx++] = 0x1000001E; // ADR X30, .
+ buf[idx++] = 0x910033DE; // ADD X30, X30, #12
+ buf[idx++] = 0xD65F0220; // RET X17
+ } else {
+ buf[idx++] = 0xD65F0220; // RET X17
+ }
+ buf[idx++] = ARM64_NOP;
+ return HOOK_NO_ERR;
+}
+
+static hook_err_t relo_adr(hook_t *hook, uint64_t inst_addr, uint32_t inst,
+ inst_type_t type)
+{
+ uint32_t *buf = hook->relo_insts + hook->relo_insts_num;
+
+ uint32_t xd = bits32(inst, 4, 0);
+ uint64_t immlo = bits32(inst, 30, 29);
+ uint64_t immhi = bits32(inst, 23, 5);
+ uint64_t addr;
+
+ if (type == INST_ADR) {
+ addr = inst_addr + sign64_extend((immhi << 2u) | immlo, 21u);
+ } else {
+ addr =
+ (inst_addr + sign64_extend((immhi << 14u) | (immlo << 12u), 33u)) &
+ 0xFFFFFFFFFFFFF000;
+ if (is_in_tramp(hook, addr))
+ return -HOOK_BAD_RELO;
+ }
+ buf[0] = 0x58000040u | xd; // LDR Xd, #8
+ buf[1] = 0x14000003; // B #12
+ buf[2] = addr & 0xFFFFFFFF;
+ buf[3] = addr >> 32u;
+ return HOOK_NO_ERR;
+}
+
+static hook_err_t relo_ldr(hook_t *hook, uint64_t inst_addr, uint32_t inst,
+ inst_type_t type)
+{
+ uint32_t *buf = hook->relo_insts + hook->relo_insts_num;
+
+ uint32_t rt = bits32(inst, 4, 0);
+ uint64_t imm19 = bits32(inst, 23, 5);
+ uint64_t offset = sign64_extend((imm19 << 2u), 21u);
+ uint64_t addr = inst_addr + offset;
+
+ if (is_in_tramp(hook, addr) && type != INST_PRFM_LIT)
+ return -HOOK_BAD_RELO;
+
+ addr = relo_in_tramp(hook, addr);
+
+ if (type == INST_LDR_32 || type == INST_LDR_64 || type == INST_LDRSW_LIT) {
+ buf[0] = 0x58000060u | rt; // LDR Xt, #12
+ if (type == INST_LDR_32) {
+ buf[1] = 0xB9400000 | rt | (rt << 5u); // LDR Wt, [Xt]
+ } else if (type == INST_LDR_64) {
+ buf[1] = 0xF9400000 | rt | (rt << 5u); // LDR Xt, [Xt]
+ } else {
+ // LDRSW_LIT
+ buf[1] = 0xB9800000 | rt | (rt << 5u); // LDRSW Xt, [Xt]
+ }
+ buf[2] = 0x14000004; // B #16
+ buf[3] = ARM64_NOP;
+ buf[4] = addr & 0xFFFFFFFF;
+ buf[5] = addr >> 32u;
+ } else {
+ buf[0] = 0xA93F47F0; // STP X16, X17, [SP, -0x10]
+ buf[1] = 0x58000091; // LDR X17, #16
+ if (type == INST_PRFM_LIT) {
+ buf[2] = 0xF9800220 | rt; // PRFM Rt, [X17]
+ } else if (type == INST_LDR_SIMD_32) {
+ buf[2] = 0xBD400220 | rt; // LDR St, [X17]
+ } else if (type == INST_LDR_SIMD_64) {
+ buf[2] = 0xFD400220 | rt; // LDR Dt, [X17]
+ } else {
+ // LDR_SIMD_128
+ buf[2] = 0x3DC00220u | rt; // LDR Qt, [X17]
+ }
+ buf[3] = 0xF85F83F1; // LDR X17, [SP, -0x8]
+ buf[4] = 0x14000004; // B #16
+ buf[5] = ARM64_NOP;
+ buf[6] = addr & 0xFFFFFFFF;
+ buf[7] = addr >> 32u;
+ }
+ return HOOK_NO_ERR;
+}
+
+static hook_err_t relo_cb(hook_t *hook, uint64_t inst_addr, uint32_t inst,
+ inst_type_t type)
+{
+ uint32_t *buf = hook->relo_insts + hook->relo_insts_num;
+
+ uint64_t imm19 = bits32(inst, 23, 5);
+ uint64_t offset = sign64_extend((imm19 << 2u), 21u);
+ uint64_t addr = inst_addr + offset;
+ addr = relo_in_tramp(hook, addr);
+
+ buf[0] = (inst & 0xFF00001F) | 0x40u; // CB(N)Z Rt, #8
+ buf[1] = 0x14000005; // B #20
+ buf[2] = 0x58000051; // LDR X17, #8
+ buf[3] = 0xD65F0220; // RET X17
+ buf[4] = addr & 0xFFFFFFFF;
+ buf[5] = addr >> 32u;
+ return HOOK_NO_ERR;
+}
+
+static hook_err_t relo_tb(hook_t *hook, uint64_t inst_addr, uint32_t inst,
+ inst_type_t type)
+{
+ uint32_t *buf = hook->relo_insts + hook->relo_insts_num;
+
+ uint64_t imm14 = bits32(inst, 18, 5);
+ uint64_t offset = sign64_extend((imm14 << 2u), 16u);
+ uint64_t addr = inst_addr + offset;
+ addr = relo_in_tramp(hook, addr);
+
+ buf[0] = (inst & 0xFFF8001F) | 0x40u; // TB(N)Z Rt, #, #8
+ buf[1] = 0x14000005; // B #20
+ buf[2] = 0x58000051; // LDR X17, #8
+ buf[3] = 0xd65f0220; // RET X17
+ buf[4] = addr & 0xFFFFFFFF;
+ buf[5] = addr >> 32u;
+ return HOOK_NO_ERR;
+}
+
+static hook_err_t relo_ignore(hook_t *hook, uint64_t inst_addr, uint32_t inst,
+ inst_type_t type)
+{
+ uint32_t *buf = hook->relo_insts + hook->relo_insts_num;
+ buf[0] = inst;
+ buf[1] = ARM64_NOP;
+ return HOOK_NO_ERR;
+}
+
+static uint32_t can_b_rel(uint64_t src_addr, uint64_t dst_addr)
+{
+#define B_REL_RANGE ((1 << 25) << 2)
+ return ((dst_addr >= src_addr) && (dst_addr - src_addr <= B_REL_RANGE)) ||
+ ((src_addr >= dst_addr) && (src_addr - dst_addr <= B_REL_RANGE));
+}
+
+int32_t branch_relative(uint32_t *buf, uint64_t src_addr, uint64_t dst_addr)
+{
+ if (can_b_rel(src_addr, dst_addr)) {
+ buf[0] = 0x14000000u |
+ (((dst_addr - src_addr) & 0x0FFFFFFFu) >> 2u); // B