├── .gitignore ├── README.md ├── Cargo.toml ├── src ├── main.rs └── loader.rs ├── .github └── workflows │ └── build-ksuinit.yml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.idea 3 | .cargo -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ksuinit ko loader 2 | 3 | The real ksuinit has already been integrated into the main KernelSU repository, and this repository retains only a minimal ko loader. 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ksuinit" 3 | version = "2.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | # for elf parsing 8 | goblin = { git = "https://github.com/tiann/goblin" } 9 | scroll = "0.12" 10 | anyhow = "1" 11 | rustix = { git = "https://github.com/Kernel-SU/rustix.git", rev = "4a53fbc", features = ["fs", "system"] } 12 | 13 | [profile.release] 14 | strip = true 15 | lto = true 16 | opt-level = "z" 17 | panic = "abort" 18 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod loader; 2 | 3 | use std::env; 4 | use std::process::ExitCode; 5 | 6 | fn main() -> ExitCode { 7 | let args: Vec = env::args().collect(); 8 | 9 | if args.len() < 2 { 10 | eprintln!("Usage: {} ", args[0]); 11 | return ExitCode::from(1); 12 | } 13 | 14 | let ko_path = &args[1]; 15 | 16 | match loader::load_module(ko_path) { 17 | Ok(_) => { 18 | println!("Module {} loaded successfully", ko_path); 19 | ExitCode::SUCCESS 20 | } 21 | Err(e) => { 22 | eprintln!("Failed to load module {}: {:?}", ko_path, e); 23 | ExitCode::FAILURE 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/build-ksuinit.yml: -------------------------------------------------------------------------------- 1 | name: Build ksuinit 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | tags: [ 'v*.*.*' ] 7 | paths: 8 | - '.github/workflows/build-ksuinit.yml' 9 | - 'src/**' 10 | pull_request: 11 | branches: [ "main" ] 12 | paths: 13 | - 'src/**' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | build-ksuinit: 18 | name: Build ksuinit 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout source code 23 | uses: actions/checkout@v4 24 | 25 | - name: Install Rust target 26 | run: | 27 | rustup update stable 28 | rustup target add aarch64-linux-android 29 | rustup target add x86_64-linux-android 30 | RUSTFLAGS="" cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1 31 | 32 | - name: Build for aarch64 33 | run: cross build --target aarch64-linux-android --release 34 | 35 | - name: Build for x86_64 36 | run: cross build --target x86_64-linux-android --release 37 | 38 | - name: Upload aarch64 binary 39 | uses: actions/upload-artifact@v4 40 | with: 41 | name: ksuinit-aarch64 42 | path: target/aarch64-linux-android/release/ksuinit 43 | 44 | - name: Upload x86_64 binary 45 | uses: actions/upload-artifact@v4 46 | with: 47 | name: ksuinit-x86_64 48 | path: target/x86_64-linux-android/release/ksuinit 49 | 50 | - name: Prepare release assets 51 | if: startsWith(github.ref, 'refs/tags/') 52 | run: | 53 | mkdir -p release 54 | cp target/aarch64-linux-android/release/ksuinit release/ksuinit-aarch64 55 | cp target/x86_64-linux-android/release/ksuinit release/ksuinit-x86_64 56 | 57 | - name: Upload release assets 58 | if: startsWith(github.ref, 'refs/tags/') 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: release-assets 62 | path: release/ 63 | 64 | release: 65 | name: Publish GitHub Release 66 | needs: build-ksuinit 67 | if: startsWith(github.ref, 'refs/tags/') 68 | runs-on: ubuntu-latest 69 | 70 | steps: 71 | - name: Download artifacts 72 | uses: actions/download-artifact@v4 73 | with: 74 | name: release-assets 75 | path: release/ 76 | 77 | - name: Create Release 78 | uses: softprops/action-gh-release@v2 79 | with: 80 | files: | 81 | release/ksuinit-aarch64 82 | release/ksuinit-x86_64 83 | env: 84 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /src/loader.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use goblin::elf::{section_header, sym::Sym, Elf}; 3 | use rustix::{cstr, system::init_module}; 4 | use scroll::{ctx::SizeWith, Pwrite}; 5 | use std::collections::HashMap; 6 | use std::fs; 7 | 8 | struct Kptr { 9 | value: String, 10 | } 11 | 12 | impl Kptr { 13 | pub fn new() -> Result { 14 | let value = fs::read_to_string("/proc/sys/kernel/kptr_restrict")?; 15 | fs::write("/proc/sys/kernel/kptr_restrict", "1")?; 16 | Ok(Kptr { value }) 17 | } 18 | } 19 | 20 | impl Drop for Kptr { 21 | fn drop(&mut self) { 22 | let _ = fs::write("/proc/sys/kernel/kptr_restrict", self.value.as_bytes()); 23 | } 24 | } 25 | 26 | fn parse_kallsyms() -> Result> { 27 | let _dontdrop = Kptr::new()?; 28 | 29 | let allsyms = fs::read_to_string("/proc/kallsyms")? 30 | .lines() 31 | .map(|line| line.split_whitespace()) 32 | .filter_map(|mut splits| { 33 | splits 34 | .next() 35 | .and_then(|addr| u64::from_str_radix(addr, 16).ok()) 36 | .and_then(|addr| splits.nth(1).map(|symbol| (symbol, addr))) 37 | }) 38 | .map(|(symbol, addr)| { 39 | ( 40 | symbol 41 | .find("$").or_else(|| symbol.find(".llvm.")) 42 | .map_or(symbol, |pos| &symbol[0..pos]) 43 | .to_owned(), 44 | addr, 45 | ) 46 | }) 47 | .collect::>(); 48 | 49 | Ok(allsyms) 50 | } 51 | 52 | pub fn load_module(path: &str) -> Result<()> { 53 | let mut buffer = 54 | fs::read(path).with_context(|| format!("Cannot read file {}", path))?; 55 | let elf = Elf::parse(&buffer)?; 56 | 57 | let kernel_symbols = 58 | parse_kallsyms().context("Cannot parse kallsyms")?; 59 | 60 | let mut modifications = Vec::new(); 61 | for (index, mut sym) in elf.syms.iter().enumerate() { 62 | if index == 0 { 63 | continue; 64 | } 65 | 66 | if sym.st_shndx != section_header::SHN_UNDEF as usize { 67 | continue; 68 | } 69 | 70 | let Some(name) = elf.strtab.get_at(sym.st_name) else { 71 | continue; 72 | }; 73 | 74 | let offset = elf.syms.offset() + index * Sym::size_with(elf.syms.ctx()); 75 | let Some(real_addr) = kernel_symbols.get(name) else { 76 | eprintln!("Warning: Cannot find symbol: {}", &name); 77 | continue; 78 | }; 79 | sym.st_shndx = section_header::SHN_ABS as usize; 80 | sym.st_value = *real_addr; 81 | modifications.push((sym, offset)); 82 | } 83 | 84 | let ctx = *elf.syms.ctx(); 85 | for ele in modifications { 86 | buffer.pwrite_with(ele.0, ele.1, ctx)?; 87 | } 88 | init_module(&buffer, cstr!("")).context("init_module failed.")?; 89 | Ok(()) 90 | } 91 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.80" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "2.4.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" 16 | 17 | [[package]] 18 | name = "errno" 19 | version = "0.3.8" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 22 | dependencies = [ 23 | "libc", 24 | "windows-sys", 25 | ] 26 | 27 | [[package]] 28 | name = "goblin" 29 | version = "0.8.0" 30 | source = "git+https://github.com/tiann/goblin#138d40d4c36471cfbb611eb493f0378ee9fc63f5" 31 | dependencies = [ 32 | "log", 33 | "plain", 34 | "scroll", 35 | ] 36 | 37 | [[package]] 38 | name = "ksuinit" 39 | version = "2.1.0" 40 | dependencies = [ 41 | "anyhow", 42 | "goblin", 43 | "rustix", 44 | "scroll", 45 | ] 46 | 47 | [[package]] 48 | name = "libc" 49 | version = "0.2.153" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 52 | 53 | [[package]] 54 | name = "linux-raw-sys" 55 | version = "0.4.15" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 58 | 59 | [[package]] 60 | name = "log" 61 | version = "0.4.21" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 64 | 65 | [[package]] 66 | name = "plain" 67 | version = "0.2.3" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 70 | 71 | [[package]] 72 | name = "proc-macro2" 73 | version = "1.0.78" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 76 | dependencies = [ 77 | "unicode-ident", 78 | ] 79 | 80 | [[package]] 81 | name = "quote" 82 | version = "1.0.35" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 85 | dependencies = [ 86 | "proc-macro2", 87 | ] 88 | 89 | [[package]] 90 | name = "rustix" 91 | version = "0.38.34" 92 | source = "git+https://github.com/Kernel-SU/rustix.git?rev=4a53fbc#4a53fbc7cb7a07cabe87125cc21dbc27db316259" 93 | dependencies = [ 94 | "bitflags", 95 | "errno", 96 | "libc", 97 | "linux-raw-sys", 98 | "windows-sys", 99 | ] 100 | 101 | [[package]] 102 | name = "scroll" 103 | version = "0.12.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" 106 | dependencies = [ 107 | "scroll_derive", 108 | ] 109 | 110 | [[package]] 111 | name = "scroll_derive" 112 | version = "0.12.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" 115 | dependencies = [ 116 | "proc-macro2", 117 | "quote", 118 | "syn", 119 | ] 120 | 121 | [[package]] 122 | name = "syn" 123 | version = "2.0.52" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" 126 | dependencies = [ 127 | "proc-macro2", 128 | "quote", 129 | "unicode-ident", 130 | ] 131 | 132 | [[package]] 133 | name = "unicode-ident" 134 | version = "1.0.12" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 137 | 138 | [[package]] 139 | name = "windows-sys" 140 | version = "0.52.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 143 | dependencies = [ 144 | "windows-targets", 145 | ] 146 | 147 | [[package]] 148 | name = "windows-targets" 149 | version = "0.52.4" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 152 | dependencies = [ 153 | "windows_aarch64_gnullvm", 154 | "windows_aarch64_msvc", 155 | "windows_i686_gnu", 156 | "windows_i686_msvc", 157 | "windows_x86_64_gnu", 158 | "windows_x86_64_gnullvm", 159 | "windows_x86_64_msvc", 160 | ] 161 | 162 | [[package]] 163 | name = "windows_aarch64_gnullvm" 164 | version = "0.52.4" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 167 | 168 | [[package]] 169 | name = "windows_aarch64_msvc" 170 | version = "0.52.4" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 173 | 174 | [[package]] 175 | name = "windows_i686_gnu" 176 | version = "0.52.4" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 179 | 180 | [[package]] 181 | name = "windows_i686_msvc" 182 | version = "0.52.4" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 185 | 186 | [[package]] 187 | name = "windows_x86_64_gnu" 188 | version = "0.52.4" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 191 | 192 | [[package]] 193 | name = "windows_x86_64_gnullvm" 194 | version = "0.52.4" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 197 | 198 | [[package]] 199 | name = "windows_x86_64_msvc" 200 | version = "0.52.4" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 203 | --------------------------------------------------------------------------------