├── code ├── .gitignore ├── src │ ├── core │ │ ├── unicorn │ │ │ ├── arch │ │ │ │ ├── mod.rs │ │ │ │ └── arm64.rs │ │ │ ├── ffi.rs │ │ │ ├── unicorn_const.rs │ │ │ └── mod.rs │ │ ├── android │ │ │ ├── mod.rs │ │ │ ├── syscalls │ │ │ │ ├── ioctl.rs │ │ │ │ ├── prctl.rs │ │ │ │ ├── sched.rs │ │ │ │ ├── random.rs │ │ │ │ ├── fnctl.rs │ │ │ │ ├── futex.rs │ │ │ │ ├── signal.rs │ │ │ │ ├── unistd.rs │ │ │ │ ├── stat.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── mman.rs │ │ │ │ └── syscalls.rs │ │ │ └── fs │ │ │ │ ├── mod.rs │ │ │ │ └── fserrors.rs │ │ ├── loaders │ │ │ ├── mod.rs │ │ │ ├── elfRunner.rs │ │ │ └── elfLoader.rs │ │ ├── mod.rs │ │ ├── rudroid.rs │ │ ├── hooks.rs │ │ └── mmu.rs │ ├── main.rs │ └── utilities.rs ├── Cargo.toml ├── Makefile └── Cargo.lock ├── imgs ├── final.png ├── make.png ├── make2.png ├── make3.png ├── tree.png ├── cpu_exec.png ├── strich.png ├── emulator-cpu-loop.png ├── aarch64-system-call.jpeg ├── kernel-architecture.jpg ├── kernel-architecture.png ├── qemu_linux-user_main.png ├── rudroid-architecture.png └── linux-kernel-architecture.png ├── resources └── Hello │ └── jni │ ├── Application.mk │ ├── Makefile │ ├── hello.cpp │ └── Android.mk ├── .gitignore ├── run.sh ├── Dockerfile ├── LICENSE └── Readme.md /code/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /code/src/core/unicorn/arch/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod arm64; -------------------------------------------------------------------------------- /code/src/core/android/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod fs; 2 | pub mod syscalls; -------------------------------------------------------------------------------- /code/src/core/loaders/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod elfLoader; 2 | pub mod elfRunner; -------------------------------------------------------------------------------- /imgs/final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/final.png -------------------------------------------------------------------------------- /imgs/make.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/make.png -------------------------------------------------------------------------------- /imgs/make2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/make2.png -------------------------------------------------------------------------------- /imgs/make3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/make3.png -------------------------------------------------------------------------------- /imgs/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/tree.png -------------------------------------------------------------------------------- /resources/Hello/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_MODULES := hello 2 | APP_ABI := arm64-v8a -------------------------------------------------------------------------------- /imgs/cpu_exec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/cpu_exec.png -------------------------------------------------------------------------------- /imgs/strich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/strich.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | resources/rootfs/ 2 | resources/Hello/obj/ 3 | resources/Hello/libs/ 4 | code/target/ 5 | -------------------------------------------------------------------------------- /imgs/emulator-cpu-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/emulator-cpu-loop.png -------------------------------------------------------------------------------- /imgs/aarch64-system-call.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/aarch64-system-call.jpeg -------------------------------------------------------------------------------- /imgs/kernel-architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/kernel-architecture.jpg -------------------------------------------------------------------------------- /imgs/kernel-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/kernel-architecture.png -------------------------------------------------------------------------------- /imgs/qemu_linux-user_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/qemu_linux-user_main.png -------------------------------------------------------------------------------- /imgs/rudroid-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/rudroid-architecture.png -------------------------------------------------------------------------------- /imgs/linux-kernel-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant4g0nist/rudroid/HEAD/imgs/linux-kernel-architecture.png -------------------------------------------------------------------------------- /resources/Hello/jni/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | arch -x86_64 /Users/ant4g0nist/Downloads/AndroidNDK7599858.app/Contents/NDK/ndk-build 3 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | image=amulator 3 | docker build -t $image . 4 | docker run --rm -v `pwd`:/home -v `pwd`/resources/:/setup/ -it $image bash -------------------------------------------------------------------------------- /resources/Hello/jni/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) 4 | { 5 | printf("Hello World\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /resources/Hello/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | # LOCAL_XOM := false 3 | 4 | 5 | # ### build the main ### 6 | include $(CLEAR_VARS) 7 | LOCAL_MODULE := hello 8 | LOCAL_SRC_FILES := hello.cpp 9 | 10 | include $(BUILD_EXECUTABLE) -------------------------------------------------------------------------------- /code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Rudroid" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | libc = "0.2.101" 8 | bitflags = ">=1.1.0" 9 | xmas-elf = "0.8.0" 10 | byteorder = "1.4.3" 11 | keystone = "0.9.0" 12 | capstone="0.10.0" 13 | nix = "0.22.1" -------------------------------------------------------------------------------- /code/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | RUSTFLAGS="-L /usr/lib/ -lunicorn -L /usr/local/lib/ -lkeystone -Awarnings" cargo run -- /setup/hello /setup/rootfs/ 3 | 4 | release: 5 | RUSTFLAGS="-L /usr/lib/ -lunicorn -L /usr/local/lib/ -lkeystone -Awarnings" cargo run --release -- /home/resources/boo /system/lib64/libgifimage.so /home/resources/rootfs/ /home/resources/seeds/ -------------------------------------------------------------------------------- /code/src/core/android/syscalls/ioctl.rs: -------------------------------------------------------------------------------- 1 | use libc::ioctl; 2 | use crate::core::rudroid::Emulator; 3 | 4 | impl Emulator { 5 | pub fn sys_ioctl(&mut self) { 6 | // sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); 7 | let fd = self.get_arg(0); 8 | let cmd = self.get_arg(1); 9 | let arg = self.get_arg(2); 10 | 11 | unsafe { 12 | let res = ioctl(fd as i32, cmd, arg); 13 | // println!("res: {}", res); 14 | } 15 | self.set_return_val(0xffff_ffff) 16 | } 17 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest 2 | 3 | RUN apt update -y 4 | RUN apt install -y nano cmake 5 | 6 | WORKDIR /setup 7 | RUN git clone https://github.com/unicorn-engine/unicorn/ 8 | WORKDIR /setup/unicorn/ 9 | RUN ./make.sh 10 | RUN ./make.sh install 11 | 12 | WORKDIR /setup/ 13 | RUN git clone https://github.com/keystone-engine/keystone/ 14 | RUN mkdir build 15 | WORKDIR /setup/keystone/build 16 | RUN ../make-share.sh 17 | RUN make install 18 | 19 | RUN cp /usr/local/lib/libkeystone.so* /usr/lib/ 20 | 21 | RUN apt-get install -y clang llvm binutils-dev libunwind-dev 22 | WORKDIR /home/ 23 | -------------------------------------------------------------------------------- /code/src/core/android/syscalls/prctl.rs: -------------------------------------------------------------------------------- 1 | use crate::core::rudroid::Emulator; 2 | 3 | const PR_SET_NAME : u64 = 15; 4 | const BIONIC_PR_SET_VMA : u64 = 0x53564d41; 5 | const PR_SET_PTRACER : u64 = 0x59616d61; 6 | 7 | impl Emulator { 8 | pub fn prctl(&mut self) { 9 | // sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) 10 | 11 | let option = self.get_arg(0); 12 | let arg2 = self.get_arg(1); 13 | 14 | self.debug_print(format!("prctl option = 0x{:x}, arg2=0x{:x}",option, arg2)); 15 | self.set_return_val(0); 16 | } 17 | } -------------------------------------------------------------------------------- /code/src/core/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod mmu; 2 | pub mod hooks; 3 | pub mod android; 4 | pub mod loaders; 5 | pub mod rudroid; 6 | pub mod unicorn; 7 | 8 | 9 | const ram_size : u64 = 0xa00000; 10 | const entry_point : u64 = 0x1000000; 11 | 12 | #[repr(u64)] 13 | pub enum OS64 { 14 | stack_address = 0x4ffffffde000, 15 | stack_size = 0x30000, 16 | load_address = 0x555555554000, 17 | interp_address = 0x7fffb7dd5000, 18 | mmap_address = 0x7ffff7dd6000, 19 | vsyscall_address = 0xffffffffff600000, 20 | vsyscall_size = 0x1000, 21 | } 22 | 23 | // [KERNEL] 24 | pub const uid : u32 = 0; 25 | pub const gid : u32 = 0; -------------------------------------------------------------------------------- /code/src/core/android/syscalls/sched.rs: -------------------------------------------------------------------------------- 1 | use crate::core::android::fs::fserrors; 2 | use crate::core::rudroid::Emulator; 3 | 4 | impl Emulator { 5 | pub fn sys_sched_getscheduler(&mut self) { 6 | // sys_sched_getscheduler(pid_t pid); 7 | let pid = self.get_arg(0) as u32; 8 | let pid_s = pid as i32; 9 | 10 | if pid_s < 0 { 11 | self.set_return_val(fserrors::EINVAL as u64); 12 | return; 13 | } 14 | 15 | let res = unsafe { libc::sched_getscheduler(pid_s) }; 16 | self.set_return_val(res as u64); 17 | self.debug_print(format!("sys_sched_getscheduler: {:} = {:}", pid, res)); 18 | } 19 | } -------------------------------------------------------------------------------- /code/src/core/android/syscalls/random.rs: -------------------------------------------------------------------------------- 1 | use std::{io::Read, fs::File}; 2 | use crate::core::rudroid::Emulator; 3 | 4 | impl Emulator { 5 | pub fn sys_getrandom(&mut self) { 6 | // sys_getrandom(char __user *buf, size_t count, unsigned int flags); 7 | let buf_ptr = self.get_arg(0); 8 | let count = self.get_arg(1); 9 | let flags = self.get_arg(2); 10 | 11 | let mut f = File::open("/dev/urandom").unwrap(); 12 | let mut buf = vec![0; count as usize]; 13 | f.read_exact(&mut buf).unwrap(); 14 | 15 | if self.debug { 16 | self.debug_print(format!("sys_getrandom {:x} {} {}", buf_ptr, count, flags)); 17 | } 18 | 19 | let res = self.mem_write(buf_ptr, &buf); 20 | match res.ok() { 21 | Some(v) => { 22 | self.set_return_val(count); 23 | }, 24 | None => { 25 | self.set_return_val(0xffff_ffff); 26 | } 27 | }; 28 | } 29 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Chaithu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | extern crate capstone; 3 | extern crate keystone; 4 | extern crate nix; 5 | extern crate xmas_elf; 6 | 7 | mod utilities; 8 | mod core; 9 | 10 | use std::env; 11 | use xmas_elf::ElfFile; 12 | 13 | use crate::utilities::context_title; 14 | 15 | fn parse_args() -> env::Args { 16 | //! Parse Command line arguments 17 | let mut args = env::args(); 18 | 19 | if args.len() != 3 { 20 | panic!("Please provide an ELF library and rootfs folder"); 21 | } 22 | args 23 | } 24 | 25 | fn main() 26 | { 27 | utilities::context_title(Some("Hello, world!")); 28 | let mut args = parse_args(); 29 | let mut elf_filename = args.nth(1).unwrap(); 30 | let rootfs = args.next().unwrap(); 31 | 32 | let mut elf_data = std::fs::read(&mut elf_filename).unwrap(); 33 | let mut elf: ElfFile = ElfFile::new(&mut elf_data).unwrap(); 34 | 35 | //our hello world program takes no arguments or environment variables 36 | let program_args: Vec = vec![]; 37 | let program_env: Vec = Vec::new(); 38 | 39 | let endian = elf.header.pt1.data(); 40 | let mut emu = core::rudroid::Emulator::new( &elf_filename, &rootfs, &mut elf, endian, program_args, program_env, 0, true).expect("Emulator initialisation failed"); 41 | 42 | context_title(Some("Emulator created")) 43 | 44 | //set up hooks 45 | core::hooks::add_hooks(&mut emu); 46 | 47 | context_title(Some("Running linker...")) 48 | //run linker to load dependencies of ELF and then run the main from ELF 49 | emu.run_linker(); 50 | 51 | context_title(Some("Executing target ELF...")) 52 | emu.run_elf(); 53 | 54 | context_title(Some("The End")) 55 | } 56 | -------------------------------------------------------------------------------- /code/src/core/android/syscalls/fnctl.rs: -------------------------------------------------------------------------------- 1 | use crate::core::rudroid::Emulator; 2 | 3 | impl Emulator { 4 | pub fn sys_openat(&mut self) { 5 | // sys_openat(int dfd, const char __user *filename, int flags, umode_t mode); 6 | let dfd = self.get_arg(0); 7 | let filename_ptr = self.get_arg(1); 8 | let flags = self.get_arg(2); 9 | let mode = self.get_arg(3); 10 | 11 | let filename = self.get_string(filename_ptr); 12 | let fullpath = self.filesystem.change_path_if_special(&filename); 13 | let path: &str = &fullpath; 14 | 15 | let fd = self.filesystem.openat(dfd as i32, &filename, flags as i32, mode as i32); 16 | 17 | // let fd = self.filesystem.open(&filename, flags as i32); 18 | self.set_return_val(fd as u64); 19 | 20 | if self.debug { 21 | self.debug_print(format!("sys_openat in: {:x} {} {} {} = {}", dfd, filename, flags, mode, fd)); 22 | } 23 | } 24 | 25 | pub fn sys_fcntl(&mut self) { 26 | // sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); 27 | let fd = self.get_arg(0); 28 | let cmd = self.get_arg(1); 29 | let arg = self.get_arg(2); 30 | let res = unsafe {libc::fcntl(fd as i32, cmd as i32)}; 31 | 32 | if self.debug { 33 | self.debug_print(format!("sys_fcntl in: {:x} {:x} {} = {}", fd, cmd, arg, res)); 34 | } 35 | 36 | self.set_return_val(res as u64); 37 | } 38 | 39 | pub fn sys_close(&mut self) { 40 | let fd = self.get_arg(0); 41 | self.filesystem.close(fd as i32); 42 | 43 | if self.debug { 44 | self.debug_print(format!("sys_close in: {:x} = {}", fd, 0)); 45 | } 46 | 47 | self.set_return_val(0); 48 | } 49 | } -------------------------------------------------------------------------------- /code/src/core/android/syscalls/futex.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use crate::core::rudroid::Emulator; 3 | 4 | const FUTEX_WAIT : u64 = 0; 5 | const FUTEX_WAKE : u64 = 1; 6 | const FUTEX_FD : u64 = 2; 7 | const FUTEX_REQUEUE : u64 = 3; 8 | const FUTEX_CMP_REQUEUE : u64 = 4; 9 | const FUTEX_WAKE_OP : u64 = 5; 10 | const FUTEX_LOCK_PI : u64 = 6; 11 | const FUTEX_UNLOCK_PI : u64 = 7; 12 | const FUTEX_TRYLOCK_PI : u64 = 8; 13 | const FUTEX_WAIT_BITSET : u64 = 9; 14 | const FUTEX_WAKE_BITSET : u64 = 10; 15 | const FUTEX_WAIT_REQUEUE_PI : u64 = 11; 16 | const FUTEX_CMP_REQUEUE_PI : u64 = 12; 17 | const FUTEX_PRIVATE_FLAG : u64 = 128; 18 | 19 | 20 | impl Emulator { 21 | pub fn sys_futex(&mut self) { 22 | // sys_futex(u32 __user *uaddr, int op, u32 val, 23 | // struct timespec __user *utime, u32 __user *uaddr2, 24 | // u32 val3); 25 | 26 | let uaddr = self.get_arg(0); 27 | let op = self.get_arg(1); 28 | let val = self.get_arg(2); 29 | let mut old_val = self.mem_read_as_vec(uaddr, 4).unwrap(); 30 | let mut old_val = self.unpack(&old_val); 31 | 32 | println!("sys_futex: {:x} {} {} op & 0x7f: {}", uaddr, op, val, op & 0x7f); 33 | 34 | match op & 0x7f { 35 | FUTEX_WAIT => { 36 | println!("sys_futex: futex_wait {:x} {} {} op & 0x7f: {}", uaddr, op, val, op & 0x7f); 37 | if old_val == val { 38 | if self.debug { 39 | println!("futex old = {:x} val = {:x}", old_val, val); 40 | } 41 | self.emu_stop(); 42 | self.set_return_val(0); 43 | } 44 | 45 | thread::yield_now(); 46 | let timeout = self.get_arg(3); 47 | let mytype = val & 0xc000; 48 | let shared = val & 0x2000; 49 | // uaddr.setInt(0, mytype | shared); 50 | let res = mytype | shared; 51 | self.mem_write(uaddr, &self.pack(res)); 52 | self.set_return_val(0); 53 | }, 54 | 55 | FUTEX_WAKE => { 56 | self.set_return_val(0); 57 | }, 58 | _ => { 59 | 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /code/src/core/android/syscalls/signal.rs: -------------------------------------------------------------------------------- 1 | use crate::core::rudroid::Emulator; 2 | 3 | impl Emulator { 4 | pub fn sys_sigaltstack(&mut self) { 5 | // sys_sigaltstack(const struct sigaltstack __user *uss, struct sigaltstack __user *uoss); 6 | let ss = self.get_arg(0); 7 | let old_ss = self.get_arg(1); 8 | self.set_return_val(0); 9 | } 10 | 11 | pub fn sys_rt_sigaction(&mut self) { 12 | // sys_rt_sigaction(int, const struct sigaction __user *, struct sigaction __user *, size_t); 13 | let sig_num = self.get_arg(0); 14 | let sigaction = self.get_arg(1); //pointer 15 | let oldaction = self.get_arg(2); //pointer 16 | 17 | // sigaction(signum, sigaction, oldaction); 18 | self.sigaction(sig_num, sigaction, oldaction); 19 | self.set_return_val(0); 20 | } 21 | 22 | pub fn sigaction(&mut self, signum: u64, act: u64, oldact : u64) { 23 | let mut sig_num = signum; 24 | let mut prefix = "Unknown"; 25 | 26 | self.debug_print(format!("sigaction signum={}, act={:x}, oldact={:x} prefix={}", sig_num, act, oldact, prefix)); 27 | 28 | if oldact != 0 { 29 | let last_act = self.sigmap.get(&sig_num); 30 | 31 | let data = match last_act { 32 | Some(v) => { 33 | last_act.unwrap().clone() 34 | }, 35 | None => { 36 | let res = vec![0u8; 20]; 37 | res.clone() 38 | } 39 | }; 40 | 41 | self.write(oldact, &data); 42 | } 43 | 44 | if act != 0 { 45 | let mut data = Vec::new(); 46 | for i in 0..5 { 47 | let addr = act + 4*i; 48 | let val = self.mem_read_as_vec(addr, 4).unwrap(); 49 | // let val = self.unpack_32(&val); 50 | data.extend_from_slice(&val); 51 | } 52 | self.sigmap.insert(signum, data); 53 | } 54 | } 55 | 56 | pub fn sys_rt_sigprocmask(&mut self) { 57 | // sys_rt_sigprocmask(int how, sigset_t __user *set, sigset_t __user *oset, size_t sigsetsize); 58 | let how = self.get_arg(0); 59 | let set = self.get_arg(1); 60 | let oset = self.get_arg(2); 61 | let sigsetsize = self.get_arg(3); 62 | 63 | self.set_return_val(0); 64 | } 65 | 66 | pub fn sys_exit_group(&mut self) { 67 | // sys_exit_group(int error_code) 68 | let error_code = self.get_arg(0); 69 | self.debug_print(format!("sys_exit_group code: {}", error_code)); 70 | self.emu_stop(); 71 | std::process::exit(1); 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /code/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "Rudroid" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "bitflags 1.2.1", 10 | "byteorder", 11 | "capstone", 12 | "keystone", 13 | "libc", 14 | "nix", 15 | "xmas-elf", 16 | ] 17 | 18 | [[package]] 19 | name = "autocfg" 20 | version = "1.0.1" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 23 | 24 | [[package]] 25 | name = "bitflags" 26 | version = "0.7.0" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 29 | 30 | [[package]] 31 | name = "bitflags" 32 | version = "1.2.1" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 35 | 36 | [[package]] 37 | name = "byteorder" 38 | version = "1.4.3" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 41 | 42 | [[package]] 43 | name = "capstone" 44 | version = "0.10.0" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "66b5d1f14c3539b6ff22fcb602fea5f1c4416148c8b7965a2e74860aa169b7b5" 47 | dependencies = [ 48 | "capstone-sys", 49 | "libc", 50 | ] 51 | 52 | [[package]] 53 | name = "capstone-sys" 54 | version = "0.14.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "df653a22d0ad34b0d91cc92a6289d96e44aac1c9a96250a094c9aeec4a91084f" 57 | dependencies = [ 58 | "cc", 59 | "libc", 60 | ] 61 | 62 | [[package]] 63 | name = "cc" 64 | version = "1.0.70" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" 67 | 68 | [[package]] 69 | name = "cfg-if" 70 | version = "1.0.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 73 | 74 | [[package]] 75 | name = "keystone" 76 | version = "0.9.0" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "0409d156f77bf2a5fc3a9f78233b0594ca5cf7a6021fa617403e6c7a2dd421fe" 79 | dependencies = [ 80 | "bitflags 0.7.0", 81 | "libc", 82 | ] 83 | 84 | [[package]] 85 | name = "libc" 86 | version = "0.2.101" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" 89 | 90 | [[package]] 91 | name = "memoffset" 92 | version = "0.6.4" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" 95 | dependencies = [ 96 | "autocfg", 97 | ] 98 | 99 | [[package]] 100 | name = "nix" 101 | version = "0.22.1" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031" 104 | dependencies = [ 105 | "bitflags 1.2.1", 106 | "cc", 107 | "cfg-if", 108 | "libc", 109 | "memoffset", 110 | ] 111 | 112 | [[package]] 113 | name = "xmas-elf" 114 | version = "0.8.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "8d29b4d8e7beaceb4e77447ba941a7600d23d0319ab52da0461abea214832d5a" 117 | dependencies = [ 118 | "zero", 119 | ] 120 | 121 | [[package]] 122 | name = "zero" 123 | version = "0.1.2" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" 126 | -------------------------------------------------------------------------------- /code/src/core/rudroid.rs: -------------------------------------------------------------------------------- 1 | 2 | use xmas_elf::header; 3 | use xmas_elf::ElfFile; 4 | use std::collections::HashMap; 5 | 6 | use super::mmu; 7 | use super::android::fs; 8 | use super::unicorn::ffi; 9 | 10 | use super::unicorn::unicorn_const::{Arch, Mode, uc_error}; 11 | 12 | // #[derive(Debug)] 13 | pub struct Emulator { 14 | pub debug : bool, 15 | 16 | pub rootfs : String, 17 | pub elf_path : String, 18 | 19 | pub machine : header::Machine, 20 | pub endian : header::Data, 21 | pub arch : Arch, 22 | 23 | pub uc : ffi::uc_handle, 24 | pub uc_type : D, 25 | 26 | pub filesystem : fs::FsScheme, 27 | 28 | // mmu stuff 29 | pub load_address : u64, 30 | pub mmap_address : u64, 31 | pub new_stack : u64, 32 | pub interp_address : u64, 33 | pub entry_point : u64, 34 | pub elf_entry : u64, 35 | pub brk_address : u64, 36 | 37 | //elf arguments 38 | pub args : Vec, 39 | pub env : Vec, 40 | 41 | pub map_infos : HashMap, 42 | 43 | //hook 44 | pub code_hooks : HashMap<*mut libc::c_void, Box>>, 45 | pub mem_hooks : HashMap<*mut libc::c_void, Box>>, 46 | pub intr_hooks : HashMap<*mut libc::c_void, Box>>, 47 | pub insn_in_hooks : HashMap<*mut libc::c_void, Box>>, 48 | pub insn_out_hooks : HashMap<*mut libc::c_void, Box>>, 49 | pub insn_sys_hooks : HashMap<*mut libc::c_void, Box>>, 50 | 51 | // syscalls stuff 52 | pub sigmap : HashMap>, 53 | 54 | _pin : std::marker::PhantomPinned, 55 | } 56 | 57 | 58 | impl Emulator 59 | { 60 | pub fn new(elf_path: &str, rootfs: &str, elf: &mut ElfFile, endian: header::Data, args: Vec, env: Vec, data: D, debug: bool) -> Result, uc_error> { 61 | let mut machine = elf.header.pt2.machine().as_machine(); 62 | let (arch, mode) = match machine { 63 | header::Machine::AArch64 => { 64 | (Arch::ARM64, Mode::LITTLE_ENDIAN) 65 | }, 66 | _ => { 67 | panic!("Not implemented yet!") 68 | } 69 | }; 70 | 71 | let mut handle = std::ptr::null_mut(); 72 | let err = unsafe { ffi::uc_open(arch, mode, &mut handle) }; 73 | let mut emu = Emulator { 74 | debug : debug, 75 | rootfs : String::from(rootfs), 76 | 77 | elf_path : String::from(elf_path), 78 | args : args, 79 | env : env, 80 | 81 | uc : handle, 82 | uc_type : data, 83 | 84 | arch : arch, 85 | machine : machine, 86 | endian : endian, 87 | 88 | map_infos : HashMap::new(), 89 | entry_point : 0, 90 | elf_entry : 0, 91 | brk_address : 0, 92 | mmap_address : 0, 93 | interp_address : 0, 94 | new_stack : 0, 95 | load_address : 0, 96 | 97 | //hooks 98 | code_hooks : HashMap::new(), 99 | mem_hooks : HashMap::new(), 100 | intr_hooks : HashMap::new(), 101 | insn_in_hooks : HashMap::new(), 102 | insn_out_hooks : HashMap::new(), 103 | insn_sys_hooks : HashMap::new(), 104 | 105 | _pin : std::marker::PhantomPinned, 106 | 107 | filesystem : fs::FsScheme::new(String::from(rootfs)), 108 | sigmap : HashMap::new(), 109 | }; 110 | 111 | emu.load(elf); 112 | emu.display_mapped(); 113 | 114 | if err == uc_error::OK { 115 | Ok(emu) 116 | } else { 117 | Err(err) 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /code/src/utilities.rs: -------------------------------------------------------------------------------- 1 | use xmas_elf::program; 2 | use crate::core::unicorn::unicorn_const::Protection; 3 | 4 | pub struct TerminalSize { 5 | width : u16, 6 | height : u16 7 | } 8 | 9 | impl Default for TerminalSize { 10 | fn default() -> Self { 11 | use libc::ioctl; 12 | use libc::isatty; 13 | use libc::{winsize as WinSize, TIOCGWINSZ}; 14 | 15 | let mut winsize = WinSize { 16 | ws_row: 0, 17 | ws_col: 0, 18 | ws_xpixel: 0, 19 | ws_ypixel: 0, 20 | }; 21 | 22 | if unsafe { ioctl(libc::STDOUT_FILENO, TIOCGWINSZ.into(), &mut winsize) } == -1 { 23 | TerminalSize { 24 | width : 20, 25 | height : 20 26 | } 27 | } 28 | 29 | else { 30 | TerminalSize { 31 | width : winsize.ws_col-1, 32 | height : winsize.ws_row-1 33 | } 34 | } 35 | } 36 | } 37 | 38 | enum Colors { 39 | RESET, 40 | BLACK, 41 | RED, 42 | GREEN, 43 | YELLOW, 44 | BLUE, 45 | MAGENTA, 46 | CYAN, 47 | WHITE, 48 | DEFAULT 49 | } 50 | 51 | fn give_me_color(color: Colors) -> String { 52 | 53 | match color { 54 | Colors::RESET => { 55 | "\x1b[0m".to_string() 56 | }, 57 | Colors::BLACK => { 58 | "\x1b[30m".to_string() 59 | }, 60 | Colors::RED => { 61 | "\x1b[31m".to_string() 62 | }, 63 | Colors::GREEN => { 64 | "\x1b[32m".to_string() 65 | }, 66 | Colors::YELLOW => { 67 | "\x1b[33m".to_string() 68 | }, 69 | Colors::BLUE => { 70 | "\x1b[34m".to_string() 71 | }, 72 | Colors::MAGENTA => { 73 | "\x1b[35m".to_string() 74 | }, 75 | Colors::CYAN => { 76 | "\x1b[36m".to_string() 77 | }, 78 | Colors::WHITE => { 79 | "\x1b[37m".to_string() 80 | }, 81 | Colors::DEFAULT => { 82 | "\x1b[39m".to_string() 83 | }, 84 | } 85 | } 86 | 87 | pub fn draw_line() { 88 | let horizontal_line = "-"; 89 | let terminal_size : TerminalSize = Default::default(); 90 | 91 | let line_color = give_me_color(Colors::GREEN); 92 | let msg_color = give_me_color(Colors::RED); 93 | let reset = give_me_color(Colors::RESET); 94 | 95 | println!("{} {} {}", line_color, (0..terminal_size.width-2).map(|_|horizontal_line).collect::() , reset); 96 | } 97 | 98 | pub fn context_title(msg: Option<&str>) { 99 | let horizontal_line = "-"; 100 | let terminal_size : TerminalSize = Default::default(); 101 | let line_color = give_me_color(Colors::GREEN); 102 | let msg_color = give_me_color(Colors::RED); 103 | let reset = give_me_color(Colors::RESET); 104 | 105 | match msg { 106 | Some(msg) => { 107 | 108 | let trail_len: u16 = (msg.len() + 12) as u16; 109 | let mut title = String::new(); 110 | 111 | title.push_str(&give_me_color(Colors::GREEN)); 112 | title.push_str(&format!(" {} [ ", (0..4).map(|_|horizontal_line).collect::())); 113 | title.push_str(&msg_color); 114 | title.push_str(msg); 115 | title.push_str(&give_me_color(Colors::GREEN)); 116 | title.push_str(" ] "); 117 | if terminal_size.width > trail_len { 118 | title.push_str(&(0..terminal_size.width - trail_len).map(|_|horizontal_line).collect::()); 119 | } 120 | else { 121 | title.push_str(&(0..20).map(|_|horizontal_line).collect::()); 122 | } 123 | 124 | println!("{} {}", title, reset); 125 | 126 | }, 127 | 128 | None => println!("{} {} {}", line_color, (0..terminal_size.width-2).map(|_|horizontal_line).collect::() , reset), 129 | } 130 | } 131 | 132 | pub enum DebugLevel { 133 | DEBUG, 134 | INFO, 135 | ERROR 136 | } 137 | 138 | pub fn log(msg: &str, level: DebugLevel) { 139 | let mut debug_color = give_me_color(Colors::MAGENTA); 140 | let mut debug_type = "DEFAULT"; 141 | let reset = give_me_color(Colors::RESET); 142 | 143 | match level { 144 | DebugLevel::DEBUG => { 145 | debug_color = give_me_color(Colors::GREEN); 146 | debug_type = "DEBUG"; 147 | }, 148 | DebugLevel::INFO => { 149 | debug_color = give_me_color(Colors::CYAN); 150 | debug_type = "INFO"; 151 | }, 152 | DebugLevel::ERROR => { 153 | debug_color = give_me_color(Colors::RED); 154 | debug_type = "ERROR"; 155 | } 156 | } 157 | println!("{}[{}]: {} {}", debug_color, debug_type, reset, msg); 158 | } 159 | 160 | pub fn to_uc_permissions(perms: program::Flags) -> Protection { 161 | let mut uc_perms: Protection = Protection::NONE; 162 | 163 | if perms.is_execute() { 164 | uc_perms = uc_perms | Protection::EXEC; 165 | // assumes read if execute 166 | uc_perms = uc_perms | Protection::READ; 167 | } 168 | 169 | if perms.is_write() { 170 | uc_perms = uc_perms | Protection::WRITE; 171 | } 172 | 173 | if perms.is_read() { 174 | uc_perms = uc_perms | Protection::READ; 175 | } 176 | 177 | uc_perms 178 | } -------------------------------------------------------------------------------- /code/src/core/android/syscalls/unistd.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | use crate::core::{uid, gid}; 3 | use crate::core::rudroid::Emulator; 4 | 5 | impl Emulator { 6 | pub fn sys_getpid(&mut self) { 7 | let pid = 1337; 8 | self.set_return_val(pid as u64); 9 | } 10 | 11 | pub fn sys_set_tid_address(&mut self) { 12 | let tidptr = self.get_arg(0); 13 | 14 | let pid = process::id(); 15 | let pid_buf = self.pack_32(pid); 16 | 17 | self.mem_write(tidptr, &pid_buf); 18 | self.set_return_val(pid as u64); 19 | } 20 | 21 | pub fn sys_faccessat(&mut self) { 22 | // faccessat(int dfd, const char __user *filename, int mode); 23 | let dfd = self.get_arg(0); 24 | let filename_ptr = self.get_arg(1); 25 | let mode = self.get_arg(2); 26 | let path = self.get_string(filename_ptr); 27 | 28 | let fd = self.filesystem.open(&path, libc::O_RDONLY); 29 | 30 | if self.debug { 31 | self.debug_print(format!("sys_faccessat {:x} {} {} = {}", dfd, path, mode, fd)); 32 | } 33 | 34 | self.set_return_val(fd as u64); 35 | } 36 | 37 | pub fn sys_readlinkat(&mut self) { 38 | // sys_readlinkat(int dfd, const char __user *path, char __user *buf, int bufsiz); 39 | let dfd = self.get_arg(0); 40 | let path_ptr = self.get_arg(1); 41 | let buf = self.get_arg(2); 42 | let buf_size = self.get_arg(3); 43 | 44 | let path = self.get_string(path_ptr); 45 | let fullpath = format!("{}/{}", self.rootfs, path); 46 | 47 | if path == "/proc/self/exe" { 48 | // todo!(); 49 | let mut path = self.elf_path.clone(); 50 | let mut size = self.elf_path.len() as u64; 51 | 52 | let mut path_buf = Vec::new(); 53 | 54 | path_buf.extend_from_slice(&path.as_bytes()); 55 | path_buf.push(0); 56 | 57 | self.debug_print(format!("readlink at {} = {}", path, (self.elf_path.len()))); 58 | 59 | self.mem_write(buf, &path_buf); 60 | self.set_return_val((path_buf.len()-1) as u64); 61 | } 62 | 63 | else if path.contains("/proc/self/fd") { 64 | self.mem_write(buf, &path.as_bytes()); 65 | self.set_return_val((path.len()-1) as u64); 66 | } 67 | 68 | else { 69 | let mut data = vec![0u8; buf_size as usize]; 70 | self.set_return_val(0); 71 | } 72 | } 73 | 74 | pub fn sys_read(&mut self) { 75 | // sys_read(unsigned int fd, char __user *buf, size_t count); 76 | let fd = self.get_arg(0); 77 | let buf = self.get_arg(1); 78 | let count = self.get_arg(2); 79 | 80 | let mut data = vec![0u8; count as usize]; 81 | let res = self.filesystem.read(fd as i32, &mut data); 82 | 83 | match res.ok() { 84 | Some(v) => { 85 | if self.debug == true { 86 | println!("sys_read {} {:x} {:x} = {:x}",fd, buf, count, v); 87 | } 88 | self.mem_write(buf, &data); 89 | self.set_return_val(v as u64); 90 | }, 91 | None => { 92 | // println!("sys_read fail {} {:x} {:x} = {:x}",fd, buf, count, -1); 93 | self.set_return_val(0xffff_ffff); 94 | } 95 | } 96 | } 97 | 98 | pub fn sys_pread64(&mut self) { 99 | // sys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos); 100 | let fd = self.get_arg(0); 101 | let read_buf = self.get_arg(1); 102 | let read_count = self.get_arg(2); 103 | let read_pos = self.get_arg(3); 104 | 105 | let mut data = vec![0u8; read_count as usize]; 106 | if read_pos != 0 { 107 | let res = self.filesystem.pread(fd as i32, &mut data, read_pos).unwrap(); 108 | // println!("sys_pread {} {:x} {:x} {} = {:x}", fd, read_buf, read_count, read_pos, res); 109 | self.set_return_val(res as u64); 110 | } 111 | 112 | else { 113 | self.sys_read(); 114 | } 115 | } 116 | 117 | pub fn sys_getuid(&mut self) { 118 | self.set_return_val(uid as u64); 119 | } 120 | 121 | pub fn sys_write(&mut self) { 122 | // sys_write(unsigned int fd, const char __user *buf, size_t count); 123 | let fd = self.get_arg(0); 124 | let buf_ptr = self.get_arg(1); 125 | let count = self.get_arg(2); 126 | 127 | let mut data = self.mem_read_as_vec(buf_ptr, count as usize).unwrap(); 128 | let res = self.filesystem.write(fd as i32, &mut data); 129 | 130 | match res.ok() { 131 | Some(v) => { 132 | self.set_return_val(v as u64); 133 | }, 134 | None => { 135 | self.set_return_val(0xffff_ffff); 136 | } 137 | } 138 | } 139 | 140 | } -------------------------------------------------------------------------------- /code/src/core/unicorn/ffi.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(dead_code)] 3 | 4 | use std::fmt; 5 | use std::ffi::c_void; 6 | use std::pin::Pin; 7 | use libc::{c_char, c_int}; 8 | use crate::core::rudroid; 9 | use super::unicorn_const::*; 10 | 11 | pub type uc_handle = *mut c_void; 12 | pub type uc_hook = *mut c_void; 13 | pub type uc_context = libc::size_t; 14 | 15 | extern "C" { 16 | pub fn uc_version(major: *mut u32, minor: *mut u32) -> u32; 17 | pub fn uc_arch_supported(arch: Arch) -> bool; 18 | pub fn uc_open(arch: Arch, mode: Mode, engine: *mut uc_handle) -> uc_error; 19 | pub fn uc_close(engine: uc_handle) -> uc_error; 20 | pub fn uc_free(mem: uc_context) -> uc_error; 21 | pub fn uc_errno(engine: uc_handle) -> uc_error; 22 | pub fn uc_strerror(error_code: uc_error) -> *const c_char; 23 | pub fn uc_reg_write(engine: uc_handle, regid: c_int, value: *const c_void) -> uc_error; 24 | pub fn uc_reg_read(engine: uc_handle, regid: c_int, value: *mut c_void) -> uc_error; 25 | pub fn uc_mem_write( 26 | engine: uc_handle, 27 | address: u64, 28 | bytes: *const u8, 29 | size: libc::size_t, 30 | ) -> uc_error; 31 | pub fn uc_mem_read( 32 | engine: uc_handle, 33 | address: u64, 34 | bytes: *mut u8, 35 | size: libc::size_t, 36 | ) -> uc_error; 37 | pub fn uc_mem_map(engine: uc_handle, address: u64, size: libc::size_t, perms: u32) -> uc_error; 38 | pub fn uc_mem_map_ptr( 39 | engine: uc_handle, 40 | address: u64, 41 | size: libc::size_t, 42 | perms: u32, 43 | ptr: *mut c_void, 44 | ) -> uc_error; 45 | pub fn uc_mem_unmap(engine: uc_handle, address: u64, size: libc::size_t) -> uc_error; 46 | pub fn uc_mem_protect(engine: uc_handle, address: u64, size: libc::size_t, perms: u32) 47 | -> uc_error; 48 | pub fn uc_mem_regions( 49 | engine: uc_handle, 50 | regions: *const *const MemRegion, 51 | count: *mut u32, 52 | ) -> uc_error; 53 | pub fn uc_emu_start( 54 | engine: uc_handle, 55 | begin: u64, 56 | until: u64, 57 | timeout: u64, 58 | count: libc::size_t, 59 | ) -> uc_error; 60 | pub fn uc_emu_stop(engine: uc_handle) -> uc_error; 61 | pub fn uc_hook_add( 62 | engine: uc_handle, 63 | hook: *mut uc_hook, 64 | hook_type: HookType, 65 | callback: *mut c_void, 66 | user_data: *mut c_void, 67 | begin: u64, 68 | end: u64, 69 | ... 70 | ) -> uc_error; 71 | pub fn uc_hook_del(engine: uc_handle, hook: uc_hook) -> uc_error; 72 | pub fn uc_query(engine: uc_handle, query_type: Query, result: *mut libc::size_t) -> uc_error; 73 | pub fn uc_context_alloc(engine: uc_handle, context: *mut uc_context) -> uc_error; 74 | pub fn uc_context_save(engine: uc_handle, context: uc_context) -> uc_error; 75 | pub fn uc_context_restore(engine: uc_handle, context: uc_context) -> uc_error; 76 | } 77 | 78 | pub struct CodeHook { 79 | pub unicorn: *mut rudroid::Emulator, 80 | pub callback: Box, u64, u32)> 81 | } 82 | 83 | pub struct MemHook { 84 | pub unicorn: *mut rudroid::Emulator, 85 | pub callback: Box, MemType, u64, usize, i64)> 86 | } 87 | 88 | pub struct InterruptHook { 89 | pub unicorn: *mut rudroid::Emulator, 90 | pub callback: Box, u32)> 91 | } 92 | 93 | pub struct InstructionInHook { 94 | pub unicorn: *mut rudroid::Emulator, 95 | pub callback: Box, u32, usize)> 96 | } 97 | 98 | pub struct InstructionOutHook { 99 | pub unicorn: *mut rudroid::Emulator, 100 | pub callback: Box, u32, usize, u32)> 101 | } 102 | 103 | pub struct InstructionSysHook { 104 | pub unicorn: *mut rudroid::Emulator, 105 | pub callback: Box)> 106 | } 107 | 108 | 109 | pub extern "C" fn code_hook_proxy(uc: uc_handle, address: u64, size: u32, user_data: *mut CodeHook) { 110 | let mut unicorn = unsafe { &mut *(*user_data).unicorn }; 111 | let callback = &mut unsafe { &mut *(*user_data).callback }; 112 | assert_eq!(uc, unicorn.uc); 113 | callback(&mut unicorn , address, size); 114 | } 115 | 116 | pub extern "C" fn mem_hook_proxy(uc: uc_handle, 117 | mem_type: MemType, 118 | address: u64, 119 | size: u32, 120 | value: i64, 121 | user_data: *mut MemHook) 122 | { 123 | let mut unicorn = unsafe { &mut *(*user_data).unicorn }; 124 | let callback = &mut unsafe { &mut *(*user_data).callback }; 125 | assert_eq!(uc, unicorn.uc); 126 | callback(&mut unicorn , mem_type, address, size as usize, value); 127 | } 128 | 129 | pub extern "C" fn intr_hook_proxy(uc: uc_handle, value: u32, user_data: *mut InterruptHook) { 130 | let mut unicorn = unsafe { &mut *(*user_data).unicorn }; 131 | let callback = &mut unsafe { &mut *(*user_data).callback }; 132 | assert_eq!(uc, unicorn.uc); 133 | callback(&mut unicorn , value); 134 | } -------------------------------------------------------------------------------- /code/src/core/unicorn/arch/arm64.rs: -------------------------------------------------------------------------------- 1 | // ARM64 registers 2 | #[repr(C)] 3 | #[derive(PartialEq, Debug, Clone, Copy)] 4 | pub enum RegisterARM64 { 5 | INVALID = 0, 6 | FP = 1, 7 | LR = 2, 8 | NZCV = 3, 9 | SP = 4, 10 | WSP = 5, 11 | WZR = 6, 12 | XZR = 7, 13 | B0 = 8, 14 | B1 = 9, 15 | B2 = 10, 16 | B3 = 11, 17 | B4 = 12, 18 | B5 = 13, 19 | B6 = 14, 20 | B7 = 15, 21 | B8 = 16, 22 | B9 = 17, 23 | B10 = 18, 24 | B11 = 19, 25 | B12 = 20, 26 | B13 = 21, 27 | B14 = 22, 28 | B15 = 23, 29 | B16 = 24, 30 | B17 = 25, 31 | B18 = 26, 32 | B19 = 27, 33 | B20 = 28, 34 | B21 = 29, 35 | B22 = 30, 36 | B23 = 31, 37 | B24 = 32, 38 | B25 = 33, 39 | B26 = 34, 40 | B27 = 35, 41 | B28 = 36, 42 | B29 = 37, 43 | B30 = 38, 44 | B31 = 39, 45 | D0 = 40, 46 | D1 = 41, 47 | D2 = 42, 48 | D3 = 43, 49 | D4 = 44, 50 | D5 = 45, 51 | D6 = 46, 52 | D7 = 47, 53 | D8 = 48, 54 | D9 = 49, 55 | D10 = 50, 56 | D11 = 51, 57 | D12 = 52, 58 | D13 = 53, 59 | D14 = 54, 60 | D15 = 55, 61 | D16 = 56, 62 | D17 = 57, 63 | D18 = 58, 64 | D19 = 59, 65 | D20 = 60, 66 | D21 = 61, 67 | D22 = 62, 68 | D23 = 63, 69 | D24 = 64, 70 | D25 = 65, 71 | D26 = 66, 72 | D27 = 67, 73 | D28 = 68, 74 | D29 = 69, 75 | D30 = 70, 76 | D31 = 71, 77 | H0 = 72, 78 | H1 = 73, 79 | H2 = 74, 80 | H3 = 75, 81 | H4 = 76, 82 | H5 = 77, 83 | H6 = 78, 84 | H7 = 79, 85 | H8 = 80, 86 | H9 = 81, 87 | H10 = 82, 88 | H11 = 83, 89 | H12 = 84, 90 | H13 = 85, 91 | H14 = 86, 92 | H15 = 87, 93 | H16 = 88, 94 | H17 = 89, 95 | H18 = 90, 96 | H19 = 91, 97 | H20 = 92, 98 | H21 = 93, 99 | H22 = 94, 100 | H23 = 95, 101 | H24 = 96, 102 | H25 = 97, 103 | H26 = 98, 104 | H27 = 99, 105 | H28 = 100, 106 | H29 = 101, 107 | H30 = 102, 108 | H31 = 103, 109 | Q0 = 104, 110 | Q1 = 105, 111 | Q2 = 106, 112 | Q3 = 107, 113 | Q4 = 108, 114 | Q5 = 109, 115 | Q6 = 110, 116 | Q7 = 111, 117 | Q8 = 112, 118 | Q9 = 113, 119 | Q10 = 114, 120 | Q11 = 115, 121 | Q12 = 116, 122 | Q13 = 117, 123 | Q14 = 118, 124 | Q15 = 119, 125 | Q16 = 120, 126 | Q17 = 121, 127 | Q18 = 122, 128 | Q19 = 123, 129 | Q20 = 124, 130 | Q21 = 125, 131 | Q22 = 126, 132 | Q23 = 127, 133 | Q24 = 128, 134 | Q25 = 129, 135 | Q26 = 130, 136 | Q27 = 131, 137 | Q28 = 132, 138 | Q29 = 133, 139 | Q30 = 134, 140 | Q31 = 135, 141 | S0 = 136, 142 | S1 = 137, 143 | S2 = 138, 144 | S3 = 139, 145 | S4 = 140, 146 | S5 = 141, 147 | S6 = 142, 148 | S7 = 143, 149 | S8 = 144, 150 | S9 = 145, 151 | S10 = 146, 152 | S11 = 147, 153 | S12 = 148, 154 | S13 = 149, 155 | S14 = 150, 156 | S15 = 151, 157 | S16 = 152, 158 | S17 = 153, 159 | S18 = 154, 160 | S19 = 155, 161 | S20 = 156, 162 | S21 = 157, 163 | S22 = 158, 164 | S23 = 159, 165 | S24 = 160, 166 | S25 = 161, 167 | S26 = 162, 168 | S27 = 163, 169 | S28 = 164, 170 | S29 = 165, 171 | S30 = 166, 172 | S31 = 167, 173 | W0 = 168, 174 | W1 = 169, 175 | W2 = 170, 176 | W3 = 171, 177 | W4 = 172, 178 | W5 = 173, 179 | W6 = 174, 180 | W7 = 175, 181 | W8 = 176, 182 | W9 = 177, 183 | W10 = 178, 184 | W11 = 179, 185 | W12 = 180, 186 | W13 = 181, 187 | W14 = 182, 188 | W15 = 183, 189 | W16 = 184, 190 | W17 = 185, 191 | W18 = 186, 192 | W19 = 187, 193 | W20 = 188, 194 | W21 = 189, 195 | W22 = 190, 196 | W23 = 191, 197 | W24 = 192, 198 | W25 = 193, 199 | W26 = 194, 200 | W27 = 195, 201 | W28 = 196, 202 | W29 = 197, 203 | W30 = 198, 204 | X0 = 199, 205 | X1 = 200, 206 | X2 = 201, 207 | X3 = 202, 208 | X4 = 203, 209 | X5 = 204, 210 | X6 = 205, 211 | X7 = 206, 212 | X8 = 207, 213 | X9 = 208, 214 | X10 = 209, 215 | X11 = 210, 216 | X12 = 211, 217 | X13 = 212, 218 | X14 = 213, 219 | X15 = 214, 220 | IP1 = 215, 221 | IP0 = 216, 222 | X18 = 217, 223 | X19 = 218, 224 | X20 = 219, 225 | X21 = 220, 226 | X22 = 221, 227 | X23 = 222, 228 | X24 = 223, 229 | X25 = 224, 230 | X26 = 225, 231 | X27 = 226, 232 | X28 = 227, 233 | V0 = 228, 234 | V1 = 229, 235 | V2 = 230, 236 | V3 = 231, 237 | V4 = 232, 238 | V5 = 233, 239 | V6 = 234, 240 | V7 = 235, 241 | V8 = 236, 242 | V9 = 237, 243 | V10 = 238, 244 | V11 = 239, 245 | V12 = 240, 246 | V13 = 241, 247 | V14 = 242, 248 | V15 = 243, 249 | V16 = 244, 250 | V17 = 245, 251 | V18 = 246, 252 | V19 = 247, 253 | V20 = 248, 254 | V21 = 249, 255 | V22 = 250, 256 | V23 = 251, 257 | V24 = 252, 258 | V25 = 253, 259 | V26 = 254, 260 | V27 = 255, 261 | V28 = 256, 262 | V29 = 257, 263 | V30 = 258, 264 | V31 = 259, 265 | 266 | // pseudo registers 267 | PC = 260, 268 | CPACR_EL1 = 261, 269 | } 270 | 271 | pub const PAGE_ALIGN: u64 = 0x1000; -------------------------------------------------------------------------------- /code/src/core/unicorn/unicorn_const.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | use bitflags::bitflags; 3 | 4 | pub const API_MAJOR: u64 = 1; 5 | pub const API_MINOR: u64 = 0; 6 | pub const VERSION_MAJOR: u64 = 1; 7 | pub const VERSION_MINOR: u64 = 0; 8 | pub const VERSION_EXTRA: u64 = 2; 9 | pub const SECOND_SCALE: u64 = 1000000; 10 | pub const MILISECOND_SCALE: u64 = 1000; 11 | 12 | pub const MAX_FDS: i32 = 256; 13 | 14 | #[repr(C)] 15 | #[derive(PartialEq, Debug, Clone, Copy)] 16 | pub enum uc_error { 17 | OK = 0, 18 | NOMEM = 1, 19 | ARCH = 2, 20 | HANDLE = 3, 21 | MODE = 4, 22 | VERSION = 5, 23 | READ_UNMAPPED = 6, 24 | WRITE_UNMAPPED = 7, 25 | FETCH_UNMAPPED = 8, 26 | HOOK = 9, 27 | INSN_INVALID = 10, 28 | MAP = 11, 29 | WRITE_PROT = 12, 30 | READ_PROT = 13, 31 | FETCH_PROT = 14, 32 | ARG = 15, 33 | READ_UNALIGNED = 16, 34 | WRITE_UNALIGNED = 17, 35 | FETCH_UNALIGNED = 18, 36 | HOOK_EXIST = 19, 37 | RESOURCE = 20, 38 | EXCEPTION = 21, 39 | } 40 | 41 | #[repr(C)] 42 | #[derive(PartialEq, Debug, Clone, Copy)] 43 | pub enum MemType { 44 | READ = 16, 45 | WRITE = 17, 46 | FETCH = 18, 47 | READ_UNMAPPED = 19, 48 | WRITE_UNMAPPED = 20, 49 | FETCH_UNMAPPED = 21, 50 | WRITE_PROT = 22, 51 | READ_PROT = 23, 52 | FETCH_PROT = 24, 53 | READ_AFTER = 25, 54 | } 55 | 56 | #[repr(i32)] 57 | #[derive(PartialEq, Debug, Clone, Copy)] 58 | pub enum HookType { 59 | INTR = 1, 60 | INSN = 2, 61 | CODE = 4, 62 | BLOCK = 8, 63 | MEM_READ_UNMAPPED = 16, 64 | MEM_WRITE_UNMAPPED = 32, 65 | MEM_FETCH_UNMAPPED = 64, 66 | MEM_READ_PROT = 128, 67 | MEM_WRITE_PROT = 256, 68 | MEM_FETCH_PROT = 512, 69 | MEM_READ = 1024, 70 | MEM_WRITE = 2048, 71 | MEM_FETCH = 4096, 72 | MEM_READ_AFTER = 8192, 73 | INSN_INVALID = 16384, 74 | MEM_UNMAPPED = 112, 75 | MEM_PROT = 896, 76 | MEM_READ_INVALID = 144, 77 | MEM_WRITE_INVALID = 288, 78 | MEM_FETCH_INVALID = 576, 79 | MEM_INVALID = 1008, 80 | MEM_VALID = 7168, 81 | MEM_ALL = 8176, 82 | } 83 | 84 | #[repr(C)] 85 | #[derive(PartialEq, Debug, Clone, Copy)] 86 | pub enum Query { 87 | MODE = 1, 88 | PAGE_SIZE = 2, 89 | ARCH = 3, 90 | } 91 | 92 | bitflags! { 93 | #[repr(C)] 94 | pub struct Protection : u32 { 95 | const NONE = 0; 96 | const READ = 1; 97 | const WRITE = 2; 98 | const EXEC = 4; 99 | const ALL = 7; 100 | } 101 | } 102 | 103 | impl Protection { 104 | pub fn from_u32(perms: u32) -> Protection { 105 | 106 | let mut res = Protection::NONE; 107 | 108 | if perms|1 != 0 { 109 | res|= Protection::READ; 110 | } 111 | 112 | if perms|2 != 0 { 113 | res|= Protection::WRITE; 114 | } 115 | 116 | if perms|4 != 0 { 117 | res|= Protection::EXEC; 118 | } 119 | 120 | if perms|7 != 0 { 121 | return Protection::ALL; 122 | } 123 | 124 | res 125 | } 126 | } 127 | 128 | impl std::fmt::Display for Protection { 129 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 130 | let mut res = String::new(); 131 | let value = self.bits; 132 | let checks = [ (1, 'r'), (2, 'w'), (4, 'x')]; 133 | 134 | for (k,v) in checks.iter() { 135 | if k & value !=0 { 136 | res.push(*v); 137 | } 138 | else { 139 | res.push('-'); 140 | } 141 | } 142 | 143 | write!(f, "{}", res) 144 | } 145 | } 146 | 147 | #[repr(C)] 148 | #[derive(Debug, Clone)] 149 | pub struct MemRegion { 150 | pub begin: u64, 151 | pub end: u64, 152 | pub perms: Protection, 153 | } 154 | 155 | #[repr(C)] 156 | #[derive(PartialEq, Debug, Clone, Copy)] 157 | pub enum Arch { 158 | ARM = 1, 159 | ARM64 = 2, 160 | MIPS = 3, 161 | X86 = 4, 162 | PPC = 5, 163 | SPARC = 6, 164 | M68K = 7, 165 | MAX = 8, 166 | } 167 | 168 | #[repr(C)] 169 | #[derive(PartialEq, Debug, Clone, Copy)] 170 | pub enum Mode { 171 | 172 | LITTLE_ENDIAN = 0, 173 | BIG_ENDIAN = 1073741824, 174 | 175 | // use LITTLE_ENDIAN. 176 | // MODE_ARM = 0, 177 | THUMB = 16, 178 | MCLASS = 32, 179 | V8 = 64, 180 | ARM926 = 128, 181 | ARM946 = 256, 182 | ARM1176 = 512, 183 | // (assoc) MICRO = 16, 184 | // (assoc) MIPS3 = 32, 185 | // (assoc) MIPS32R6 = 64, 186 | MIPS32 = 4, 187 | MIPS64 = 8, 188 | MODE_16 = 2, 189 | // (assoc) MODE_32 = 4, 190 | // (assoc) MODE_64 = 8, 191 | // (assoc) PPC32 = 4, 192 | // (assoc) PPC64 = 8, 193 | // (assoc) QPX = 16, 194 | // (assoc) SPARC32 = 4, 195 | // (assoc) SPARC64 = 8, 196 | // (assoc) V9 = 16, 197 | } 198 | 199 | impl Mode { 200 | pub const MICRO: Mode = Mode::THUMB; 201 | pub const MIPS3: Mode = Mode::MCLASS; 202 | pub const MIPS32R6: Mode = Mode::V8; 203 | pub const MODE_32: Mode = Mode::MIPS32; 204 | pub const MODE_64: Mode = Mode::MIPS64; 205 | pub const PPC32: Mode = Mode::MIPS32; 206 | pub const PPC64: Mode = Mode::MIPS64; 207 | pub const QPX: Mode = Mode::THUMB; 208 | pub const SPARC32: Mode = Mode::MIPS32; 209 | pub const SPARC64: Mode = Mode::MIPS64; 210 | pub const V9: Mode = Mode::THUMB; 211 | } -------------------------------------------------------------------------------- /code/src/core/android/syscalls/stat.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use crate::core::{uid, gid}; 3 | use crate::core::rudroid::Emulator; 4 | use nix::sys::stat::{fstatat, fstat}; 5 | use nix::sys::statfs::{Statfs, fstatfs}; 6 | 7 | impl Emulator { 8 | pub fn sys_fstatat(&mut self) { 9 | // sys_fstatat64(int dfd, const char __user *filename, struct stat64 __user *statbuf, int flag); 10 | let dirfd = self.get_arg(0); 11 | let filename_ptr = self.get_arg(1); 12 | let statbuf = self.get_arg(2); 13 | let flag = self.get_arg(3); 14 | 15 | let filename = self.get_string(filename_ptr); 16 | 17 | let fullpath = match self.filesystem.is_driver_io(&filename) { 18 | true => { 19 | filename 20 | }, 21 | false => { 22 | format!("{}/{}", self.rootfs, filename) 23 | } 24 | }; 25 | 26 | let fullpath: &str = &fullpath; 27 | if Path::new(fullpath).exists() { 28 | let result = fstatat(dirfd as i32, fullpath, unsafe { std::mem::transmute(flag as u32) }).unwrap(); 29 | let mut fsstatbuf = Vec::new(); 30 | 31 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_dev as u64)); 32 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_ino)); 33 | 34 | fsstatbuf.extend_from_slice(&self.pack_32(result.st_mode as u32)); 35 | fsstatbuf.extend_from_slice(&self.pack_32(result.st_nlink as u32)); 36 | fsstatbuf.extend_from_slice(&self.pack_32(1000)); 37 | fsstatbuf.extend_from_slice(&self.pack_32(1000)); 38 | 39 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_rdev as u64)); 40 | fsstatbuf.extend_from_slice(&self.pack_64(0)); 41 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_size as u64)); 42 | 43 | fsstatbuf.extend_from_slice(&self.pack_32(result.st_blksize as u32)); 44 | fsstatbuf.extend_from_slice(&self.pack_32(0)); 45 | 46 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_blocks as u64)); 47 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_atime as u64)); 48 | fsstatbuf.extend_from_slice(&self.pack_64(0)); 49 | 50 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_mtime as u64)); 51 | fsstatbuf.extend_from_slice(&self.pack_64(0)); 52 | 53 | fsstatbuf.extend_from_slice(&self.pack_64(result.st_ctime as u64)); 54 | fsstatbuf.extend_from_slice(&self.pack_64(0)); 55 | 56 | self.mem_write(statbuf, &fsstatbuf); 57 | self.set_return_val(0); 58 | 59 | // println!("sys_fstatat dirfd: {} filename {}: statbuf {:x}", dirfd, fullpath, statbuf); 60 | if self.debug { 61 | self.debug_print(format!("sys_fstatat dirfd: {} filename {}: statbuf {}", dirfd, fullpath, statbuf)); 62 | } 63 | } 64 | else { 65 | self.set_return_val(0xffff_ffff); 66 | } 67 | } 68 | 69 | pub fn sys_fstat(&mut self) { 70 | // sys_fstat(unsigned int fd, struct __old_kernel_stat __user *statbuf); 71 | let fd = self.get_arg(0); 72 | let statbuf = self.get_arg(1); 73 | 74 | let fstat_info = fstat(fd as i32).unwrap(); 75 | let mut fstatbuf = Vec::new(); 76 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_dev as u64)); 77 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_ino as u64)); 78 | fstatbuf.extend_from_slice(&self.pack_32(fstat_info.st_mode as u32)); 79 | fstatbuf.extend_from_slice(&self.pack_32(fstat_info.st_nlink as u32)); 80 | 81 | fstatbuf.extend_from_slice(&self.pack_32(uid)); 82 | fstatbuf.extend_from_slice(&self.pack_32(gid)); 83 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_rdev as u64)); 84 | fstatbuf.extend_from_slice(&self.pack_64(0)); 85 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_size as u64)); 86 | fstatbuf.extend_from_slice(&self.pack_32(fstat_info.st_blksize as u32)); 87 | fstatbuf.extend_from_slice(&self.pack_32(0)); 88 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_blocks as u64)); 89 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_atime as u64)); 90 | fstatbuf.extend_from_slice(&self.pack_64(0)); 91 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_mtime as u64)); 92 | fstatbuf.extend_from_slice(&self.pack_64(0)); 93 | fstatbuf.extend_from_slice(&self.pack_64(fstat_info.st_ctime as u64)); 94 | fstatbuf.extend_from_slice(&self.pack_64(0)); 95 | 96 | self.mem_write(statbuf, &fstatbuf); 97 | 98 | self.set_return_val(0); 99 | } 100 | 101 | pub fn sys_fstatfs(&mut self) { 102 | // sys_fstatfs(unsigned int fd, struct statfs __user *buf); 103 | let fd = self.get_arg(0) as i32; 104 | let fstatbuf = self.get_arg(1); 105 | 106 | let mut statbuf = Vec::new(); 107 | 108 | statbuf.extend_from_slice(&self.pack_64(0xef53)); 109 | statbuf.extend_from_slice(&self.pack_64(0x1000)); 110 | statbuf.extend_from_slice(&self.pack_64(0x3235af)); 111 | statbuf.extend_from_slice(&self.pack_64(0x2b5763)); 112 | statbuf.extend_from_slice(&self.pack_64(0x2b5763)); 113 | statbuf.extend_from_slice(&self.pack_64(0xcccb0)); 114 | statbuf.extend_from_slice(&self.pack_64(0xcbd2e)); 115 | statbuf.extend_from_slice(&self.pack_64(0xd3609fe8)); 116 | statbuf.extend_from_slice(&self.pack_64(0x4970d6b)); 117 | statbuf.extend_from_slice(&self.pack_64(0xff)); 118 | statbuf.extend_from_slice(&self.pack_64(0x1000)); 119 | statbuf.extend_from_slice(&self.pack_64(0x426)); 120 | self.mem_write(fstatbuf, &statbuf); 121 | self.set_return_val(0); 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /code/src/core/hooks.rs: -------------------------------------------------------------------------------- 1 | use capstone::prelude::*; 2 | 3 | use super::android; 4 | use super::rudroid; 5 | use super::unicorn::arch::arm64; 6 | use crate::utilities; 7 | use super::unicorn::unicorn_const; 8 | 9 | pub fn add_hooks(emu: &mut rudroid::Emulator) { 10 | // hook syscalls: https://github.com/unicorn-engine/unicorn/issues/1137 11 | emu.add_intr_hook(android::syscalls::hook_syscall).unwrap(); 12 | 13 | emu.add_mem_hook(unicorn_const::HookType::MEM_FETCH_UNMAPPED, 1, 0, callback_mem_error).unwrap(); 14 | emu.add_mem_hook(unicorn_const::HookType::MEM_READ_UNMAPPED, 1, 0, callback_mem_error).unwrap(); 15 | } 16 | 17 | // hooks 18 | pub fn callback(uc: &mut rudroid::Emulator, address: u64, size: u32) { 19 | // dump_context(uc, address, size as usize); 20 | println!("addr: {:x}", address); 21 | } 22 | 23 | pub fn callback_mem_error(uc: &mut rudroid::Emulator, memtype: unicorn_const::MemType, address: u64, size: usize, value: i64) { 24 | println!("callback_mem_error {:x}", address); 25 | dump_context(uc, address, size); 26 | } 27 | 28 | pub fn callback_mem_rw(uc: &mut rudroid::Emulator, memtype: unicorn_const::MemType, address: u64, size: usize, value: i64) { 29 | println!("callback_mem_rw {:x}", address); 30 | dump_context(uc, address, size); 31 | } 32 | 33 | pub fn dump_context(uc: &mut rudroid::Emulator, addr: u64, size: usize) { 34 | utilities::draw_line(); 35 | 36 | let pc = uc.reg_read(arm64::RegisterARM64::PC as i32).expect("failed to read PC"); 37 | let sp = uc.reg_read(arm64::RegisterARM64::SP as i32).expect("failed to read SP" ); 38 | let lr = uc.reg_read(arm64::RegisterARM64::LR as i32).expect("failed to read LR" ); 39 | let r0 = uc.reg_read(arm64::RegisterARM64::X0 as i32).expect("failed to read x0" ); 40 | let r1 = uc.reg_read(arm64::RegisterARM64::X1 as i32).expect("failed to read x1" ); 41 | let r2 = uc.reg_read(arm64::RegisterARM64::X2 as i32).expect("failed to read x2" ); 42 | let r3 = uc.reg_read(arm64::RegisterARM64::X3 as i32).expect("failed to read x3" ); 43 | let r4 = uc.reg_read(arm64::RegisterARM64::X4 as i32).expect("failed to read x4" ); 44 | let r5 = uc.reg_read(arm64::RegisterARM64::X5 as i32).expect("failed to read x5" ); 45 | let r6 = uc.reg_read(arm64::RegisterARM64::X6 as i32).expect("failed to read x6" ); 46 | let r7 = uc.reg_read(arm64::RegisterARM64::X7 as i32).expect("failed to read x7" ); 47 | let r8 = uc.reg_read(arm64::RegisterARM64::X8 as i32).expect("failed to read x8" ); 48 | let r9 = uc.reg_read(arm64::RegisterARM64::X9 as i32).expect("failed to read x9" ); 49 | let r10 = uc.reg_read(arm64::RegisterARM64::X10 as i32).expect("failed to read x10"); 50 | let r11 = uc.reg_read(arm64::RegisterARM64::X11 as i32).expect("failed to read x11"); 51 | let r12 = uc.reg_read(arm64::RegisterARM64::X12 as i32).expect("failed to read x12"); 52 | let r13 = uc.reg_read(arm64::RegisterARM64::X13 as i32).expect("failed to read x13"); 53 | let r14 = uc.reg_read(arm64::RegisterARM64::X14 as i32).expect("failed to read x14"); 54 | let r15 = uc.reg_read(arm64::RegisterARM64::X15 as i32).expect("failed to read x15"); 55 | let r18 = uc.reg_read(arm64::RegisterARM64::X18 as i32).expect("failed to read x18"); 56 | let r19 = uc.reg_read(arm64::RegisterARM64::X19 as i32).expect("failed to read x19"); 57 | let r20 = uc.reg_read(arm64::RegisterARM64::X20 as i32).expect("failed to read x20"); 58 | let r21 = uc.reg_read(arm64::RegisterARM64::X21 as i32).expect("failed to read x21"); 59 | let r22 = uc.reg_read(arm64::RegisterARM64::X22 as i32).expect("failed to read x22"); 60 | let r23 = uc.reg_read(arm64::RegisterARM64::X23 as i32).expect("failed to read x23"); 61 | let r24 = uc.reg_read(arm64::RegisterARM64::X24 as i32).expect("failed to read x24"); 62 | let r25 = uc.reg_read(arm64::RegisterARM64::X25 as i32).expect("failed to read x25"); 63 | let r26 = uc.reg_read(arm64::RegisterARM64::X26 as i32).expect("failed to read x26"); 64 | let r27 = uc.reg_read(arm64::RegisterARM64::X27 as i32).expect("failed to read x27"); 65 | let r28 = uc.reg_read(arm64::RegisterARM64::X28 as i32).expect("failed to read x28"); 66 | 67 | let cpacr_el1 = uc.reg_read(arm64::RegisterARM64::CPACR_EL1 as i32).expect("failed to read CPACR_EL1"); 68 | utilities::draw_line(); 69 | 70 | println!("$x0 : {:#016x} $x1 : {:#016x} $x2: {:#016x} $x3: {:#016x}", r0, r1, r2, r3); 71 | println!("$x4 : {:#016x} $x5 : {:#016x} $x6: {:#016x} $x7: {:#016x}", r4, r5, r6, r7); 72 | println!("$x8 : {:#016x} $x9 : {:#016x} $x10: {:#016x} $x11: {:#016x}", r8, r9, r10, r11); 73 | println!("$x12: {:#016x} $x13: {:#016x} $x14: {:#016x} $x15: {:#016x}", r12, r13, r14, r15); 74 | println!("$x18: {:#016x} $x19: {:#016x} $x20: {:#016x} $x21: {:#016x}", r18, r19, r20, r21); 75 | println!("$x22: {:#016x} $x23: {:#016x} $x24: {:#016x} $x25: {:#016x}", r22, r23, r24, r25); 76 | println!("$x26: {:#016x} $x27: {:#016x} $x28: {:#016x} ", r26, r27, r28); 77 | println!("$sp : {:#016x} $lr : {:#016x} $pc: {:#016x}", sp, lr, pc); 78 | println!("$cpacr_el1: {:#016x} \n", cpacr_el1); 79 | 80 | let mut buf = vec![0; size]; 81 | if pc != 0 { 82 | uc.mem_read(pc, &mut buf).expect("failed to read opcode from memory"); 83 | let cs_arm: Capstone = Capstone::new() 84 | .arm64() 85 | .mode(arch::arm64::ArchMode::Arm) 86 | .detail(true) 87 | .build().expect("failed to create capstone for ARM"); 88 | 89 | let ins = cs_arm.disasm_all(&buf, size as u64).unwrap(); 90 | println!("$pc: {:#016x}", pc); 91 | println!("{}", ins); 92 | } 93 | 94 | // let stack = uc.mem_read_as_vec(sp, 0x60).unwrap(); 95 | // utilities::context_title(Some("STACK")); 96 | // print!("{}",utilities::pretty_hex(&stack, sp)); 97 | 98 | utilities::draw_line(); 99 | } 100 | -------------------------------------------------------------------------------- /code/src/core/loaders/elfRunner.rs: -------------------------------------------------------------------------------- 1 | use super::super::unicorn::ffi; 2 | use super::super::rudroid; 3 | use super::super::unicorn::unicorn_const; 4 | use super::super::unicorn::unicorn_const::*; 5 | use crate::utilities; 6 | use capstone::prelude::*; 7 | use keystone::keystone_const; 8 | use keystone::{Keystone, Arch as kArch}; 9 | use super::super::unicorn::arch::arm64::RegisterARM64; 10 | 11 | use capstone::prelude::*; 12 | 13 | impl rudroid::Emulator { 14 | pub fn run_elf(&mut self) { 15 | utilities::context_title(Some("Emulating elf")); 16 | let res = self.emu_start(self.elf_entry, 0, 0, 0); 17 | self.handle_emu_exception(res); 18 | utilities::context_title(Some("Emulating elf done.")); 19 | } 20 | 21 | pub fn fuzz_init(&mut self) -> u64 { 22 | let emu_addr = self.uc_align_up(0x14141414141); 23 | self.mem_map(emu_addr, 0x1000, Protection::ALL).expect("Code Emulation"); 24 | 25 | let code = "stp fp, lr, [sp, #-16]!\nmov fp, sp\nmov fp, sp\nblr x12\nldp fp, lr, [sp], #16\nret lr"; 26 | let ks_arm: Keystone = Keystone::new(kArch::ARM64, keystone_const::MODE_LITTLE_ENDIAN).expect("Could not initialize Keystone engine");; 27 | let result = ks_arm.asm(code.to_string(), 0).expect("Could not asemble"); 28 | self.mem_write(emu_addr, &result.bytes); 29 | emu_addr 30 | } 31 | 32 | pub fn call_me(&mut self, func_addr: u64, emu_addr: u64) { 33 | //assumes arguments are already set 34 | self.reg_write(RegisterARM64::X12 as i32, func_addr); // function to emulate 35 | self.reg_write(RegisterARM64::LR as i32, 0); //should return on 0 36 | 37 | let res = self.emu_start(emu_addr, 0x14141415014, 0, 0); 38 | self.handle_emu_exception(res); 39 | } 40 | 41 | pub fn handle_emu_exception(&mut self, err: Result<(), unicorn_const::uc_error>) { 42 | // self.get_mapped(); 43 | 44 | match err.ok() { 45 | Some(v) => { 46 | 47 | }, 48 | None => { 49 | self.display_mapped(); 50 | self.dump_context(); 51 | 52 | match err.err().unwrap() { 53 | unicorn_const::uc_error::FETCH_UNMAPPED => { 54 | panic!("- [handle_emu_exception] unicorn::unicorn_const::uc_error::FETCH_UNMAPPED"); 55 | }, 56 | _ => { 57 | panic!("- [handle_emu_exception] {:?}", err); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | pub fn dump_context(&mut self) { 65 | utilities::draw_line(); 66 | 67 | let pc = self.reg_read(RegisterARM64::PC as i32).expect("failed to read r11"); 68 | let sp = self.reg_read(RegisterARM64::SP as i32).expect("failed to read SP" ); 69 | let lr = self.reg_read(RegisterARM64::LR as i32).expect("failed to read LR" ); 70 | let r0 = self.reg_read(RegisterARM64::X0 as i32).expect("failed to read r0" ); 71 | let r1 = self.reg_read(RegisterARM64::X1 as i32).expect("failed to read r1" ); 72 | let r2 = self.reg_read(RegisterARM64::X2 as i32).expect("failed to read r2" ); 73 | let r3 = self.reg_read(RegisterARM64::X3 as i32).expect("failed to read r3" ); 74 | let r4 = self.reg_read(RegisterARM64::X4 as i32).expect("failed to read r4" ); 75 | let r5 = self.reg_read(RegisterARM64::X5 as i32).expect("failed to read r5" ); 76 | let r6 = self.reg_read(RegisterARM64::X6 as i32).expect("failed to read r6" ); 77 | let r7 = self.reg_read(RegisterARM64::X7 as i32).expect("failed to read r7" ); 78 | let r8 = self.reg_read(RegisterARM64::X8 as i32).expect("failed to read r8" ); 79 | let r9 = self.reg_read(RegisterARM64::X9 as i32).expect("failed to read r9" ); 80 | let r10 = self.reg_read(RegisterARM64::X10 as i32).expect("failed to read r10"); 81 | let r11 = self.reg_read(RegisterARM64::X11 as i32).expect("failed to read r11"); 82 | let r12 = self.reg_read(RegisterARM64::X12 as i32).expect("failed to read r11"); 83 | let r13 = self.reg_read(RegisterARM64::X13 as i32).expect("failed to read r11"); 84 | let r14 = self.reg_read(RegisterARM64::X14 as i32).expect("failed to read r11"); 85 | let r15 = self.reg_read(RegisterARM64::X15 as i32).expect("failed to read r11"); 86 | let r18 = self.reg_read(RegisterARM64::X18 as i32).expect("failed to read r11"); 87 | let r19 = self.reg_read(RegisterARM64::X19 as i32).expect("failed to read r11"); 88 | let r20 = self.reg_read(RegisterARM64::X20 as i32).expect("failed to read r11"); 89 | let r21 = self.reg_read(RegisterARM64::X21 as i32).expect("failed to read r11"); 90 | let r22 = self.reg_read(RegisterARM64::X22 as i32).expect("failed to read r11"); 91 | let r23 = self.reg_read(RegisterARM64::X23 as i32).expect("failed to read r11"); 92 | let r24 = self.reg_read(RegisterARM64::X24 as i32).expect("failed to read r11"); 93 | let r25 = self.reg_read(RegisterARM64::X25 as i32).expect("failed to read r11"); 94 | let r26 = self.reg_read(RegisterARM64::X26 as i32).expect("failed to read r11"); 95 | let r27 = self.reg_read(RegisterARM64::X27 as i32).expect("failed to read r11"); 96 | let r28 = self.reg_read(RegisterARM64::X28 as i32).expect("failed to read r11"); 97 | 98 | let cpacr_el1 = self.reg_read(RegisterARM64::CPACR_EL1 as i32).expect("failed to read r11"); 99 | utilities::draw_line(); 100 | 101 | println!("$r0 : {:#016x} $r1 : {:#016x} $r2: {:#016x} $r3: {:#016x}", r0, r1, r2, r3); 102 | println!("$r4 : {:#016x} $r5 : {:#016x} $r6: {:#016x} $r7: {:#016x}", r4, r5, r6, r7); 103 | println!("$r8 : {:#016x} $r9 : {:#016x} $r10: {:#016x} $r11: {:#016x}", r8, r9, r10, r11); 104 | println!("$r12: {:#016x} $r13: {:#016x} $r14: {:#016x} $r15: {:#016x}", r12, r13, r14, r15); 105 | println!("$r18: {:#016x} $r19: {:#016x} $r20: {:#016x} $r21: {:#016x}", r18, r19, r20, r21); 106 | println!("$r22: {:#016x} $r23: {:#016x} $r24: {:#016x} $r25: {:#016x}", r22, r23, r24, r25); 107 | println!("$r26: {:#016x} $r27: {:#016x} $r28: {:#016x} ", r26, r27, r28); 108 | println!("$sp : {:#016x} $lr : {:#016x} $pc: {:#016x}", sp, lr, pc); 109 | println!("$cpacr_el1: {:#016x} \n", cpacr_el1); 110 | 111 | utilities::draw_line(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /code/src/core/android/syscalls/mod.rs: -------------------------------------------------------------------------------- 1 | mod syscalls; 2 | mod unistd; 3 | mod mman; 4 | mod futex; 5 | mod sched; 6 | mod signal; 7 | mod prctl; 8 | mod random; 9 | mod fnctl; 10 | mod stat; 11 | mod ioctl; 12 | 13 | use crate::{core::{rudroid::Emulator, unicorn::arch::arm64::RegisterARM64}, utilities}; 14 | 15 | pub fn get_syscall(uc: &mut Emulator) -> syscalls::Syscalls { 16 | // syscall_num = UC_ARM64_REG_X8 17 | let syscall = uc.reg_read(RegisterARM64::X8 as i32).unwrap(); 18 | unsafe { ::std::mem::transmute(syscall) } 19 | } 20 | 21 | pub fn hook_syscall(uc: &mut Emulator, intno: u32) { 22 | let pc = uc.reg_read(RegisterARM64::PC as i32).unwrap(); 23 | let syscall = get_syscall(uc); 24 | uc.syscall(syscall); 25 | } 26 | 27 | impl Emulator { 28 | pub fn syscall(&mut self, syscall: syscalls::Syscalls) { 29 | if self.debug { 30 | utilities::draw_line(); 31 | self.debug_print(format!("got syscall: {:?}", syscall)); 32 | } 33 | 34 | match syscall { 35 | 36 | syscalls::Syscalls::__NR3264_mmap => 37 | { 38 | self.sys_mmap(); 39 | }, 40 | 41 | syscalls::Syscalls::__NR_getpid => 42 | { 43 | self.sys_getpid(); 44 | }, 45 | 46 | syscalls::Syscalls::__NR_set_tid_address => { 47 | self.sys_set_tid_address(); 48 | }, 49 | 50 | syscalls::Syscalls::__NR_faccessat => { 51 | self.sys_faccessat(); 52 | }, 53 | 54 | syscalls::Syscalls::__NR_futex => { 55 | self.sys_futex(); 56 | }, 57 | 58 | syscalls::Syscalls::__NR_sched_getscheduler => { 59 | self.sys_sched_getscheduler(); 60 | }, 61 | 62 | syscalls::Syscalls::__NR_mprotect => { 63 | self.sys_mprotect(); 64 | }, 65 | syscalls::Syscalls::__NR_sigaltstack => { 66 | self.sys_sigaltstack(); 67 | }, 68 | 69 | //prctl 70 | syscalls::Syscalls::__NR_prctl => { 71 | self.prctl(); 72 | }, 73 | 74 | //random 75 | syscalls::Syscalls::__NR_getrandom => { 76 | self.sys_getrandom(); 77 | }, 78 | 79 | syscalls::Syscalls::__NR_openat => { 80 | self.sys_openat(); 81 | }, 82 | syscalls::Syscalls::__NR3264_fcntl => { 83 | self.sys_fcntl() 84 | }, 85 | syscalls::Syscalls::__NR_close => { 86 | self.sys_close(); 87 | }, 88 | 89 | syscalls::Syscalls::__NR3264_fstatat => { 90 | self.sys_fstatat(); 91 | }, 92 | 93 | syscalls::Syscalls::__NR_readlinkat => { 94 | self.sys_readlinkat(); 95 | }, 96 | 97 | syscalls::Syscalls::__NR_rt_sigaction => { 98 | self.sys_rt_sigaction(); 99 | }, 100 | 101 | syscalls::Syscalls::__NR3264_fstat => { 102 | self.sys_fstat(); 103 | }, 104 | 105 | syscalls::Syscalls::__NR_read => { 106 | self.sys_read(); 107 | }, 108 | syscalls::Syscalls::__NR_munmap => { 109 | self.sys_munmap(); 110 | }, 111 | 112 | syscalls::Syscalls::__NR3264_fstatfs => { 113 | self.sys_fstatfs(); 114 | }, 115 | 116 | syscalls::Syscalls::__NR_pread64 => { 117 | self.sys_pread64() 118 | }, 119 | 120 | syscalls::Syscalls::__NR_rt_sigprocmask => { 121 | self.sys_rt_sigprocmask(); 122 | }, 123 | 124 | syscalls::Syscalls::__NR_clock_gettime => { 125 | self.empty_syscall_return(); 126 | }, 127 | syscalls::Syscalls::__NR_madvise => { 128 | self.empty_syscall_return(); 129 | }, 130 | 131 | syscalls::Syscalls::__NR_getuid => { 132 | self.sys_getuid() 133 | }, 134 | syscalls::Syscalls::__NR_write => { 135 | self.sys_write() 136 | }, 137 | 138 | syscalls::Syscalls::__NR_ioctl => { 139 | self.sys_ioctl(); 140 | }, 141 | 142 | syscalls::Syscalls::__NR_exit_group => { 143 | self.sys_exit_group(); 144 | }, 145 | 146 | _ => { 147 | panic!("Syscall {:?} not implemented yet!", syscall); 148 | } 149 | }; 150 | } 151 | 152 | pub fn empty_syscall_return(&mut self) { 153 | self.reg_write(RegisterARM64::X0 as i32, 0).unwrap(); 154 | } 155 | 156 | pub fn get_arg(&mut self, num: i32) -> u64 { 157 | // 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7' 158 | match num { 159 | 0 => { 160 | self.reg_read(RegisterARM64::X0 as i32).unwrap() 161 | }, 162 | 1 => { 163 | self.reg_read(RegisterARM64::X1 as i32).unwrap() 164 | }, 165 | 2 => { 166 | self.reg_read(RegisterARM64::X2 as i32).unwrap() 167 | }, 168 | 3 => { 169 | self.reg_read(RegisterARM64::X3 as i32).unwrap() 170 | }, 171 | 4 => { 172 | self.reg_read(RegisterARM64::X4 as i32).unwrap() 173 | }, 174 | 5 => { 175 | self.reg_read(RegisterARM64::X5 as i32).unwrap() 176 | }, 177 | 6 => { 178 | self.reg_read(RegisterARM64::X6 as i32).unwrap() 179 | }, 180 | 7 => { 181 | self.reg_read(RegisterARM64::X7 as i32).unwrap() 182 | }, 183 | _ => { 184 | panic!("i do not support any more arguments :/"); 185 | } 186 | } 187 | } 188 | 189 | pub fn set_return_val(&mut self, value: u64) { 190 | self.reg_write(RegisterARM64::X0 as i32, value).unwrap(); 191 | } 192 | 193 | pub fn get_string(&mut self, addr: u64) -> String { 194 | let mut addr = addr; 195 | let mut string = String::new(); 196 | 197 | loop { 198 | let c = self.mem_read_as_vec(addr, 1).unwrap(); 199 | let c = char::from(c[0]); 200 | match c { 201 | '\x20'..='\x7e' => { 202 | string.push(c) 203 | }, 204 | _ => { 205 | break; 206 | } 207 | }; 208 | addr+=1; 209 | } 210 | string 211 | } 212 | } -------------------------------------------------------------------------------- /code/src/core/android/fs/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | path, 3 | fs::File, 4 | fs::OpenOptions, 5 | io::prelude::*, 6 | io::{self, Write, Read}, 7 | os::unix::io::FromRawFd, 8 | os::unix::io::AsRawFd, 9 | os::unix::io::RawFd, 10 | os::unix::io::IntoRawFd, 11 | os::unix::fs::OpenOptionsExt, 12 | os::unix::fs, 13 | }; 14 | 15 | use std::collections::HashMap; 16 | pub(crate) mod fserrors; 17 | 18 | pub(crate) const MAX_FDS: i32 = 1024; 19 | 20 | pub const O_RDONLY :i32 = 0; 21 | pub const O_WRONLY :i32 = 1; 22 | pub const O_RDWR :i32 = 2; 23 | pub const O_APPEND :i32 = 8; 24 | pub const O_CREAT :i32 = 512; 25 | 26 | pub const O_ACCMODE :i32 = O_CREAT|O_RDWR|O_WRONLY|O_RDONLY; 27 | 28 | #[derive(Clone, Debug)] 29 | pub struct oFile { 30 | pub path : String, 31 | // pub file : File, 32 | pub fd : RawFd, 33 | pub flags : i32, 34 | pub seek : usize, 35 | pub shared : bool, 36 | } 37 | 38 | 39 | #[derive(Debug)] 40 | pub struct FsScheme 41 | { 42 | pub rootfs : String, 43 | pub open_files : HashMap 44 | } 45 | 46 | impl oFile { 47 | pub fn new(path: &str, fd: RawFd, flags: i32) -> oFile { 48 | oFile { 49 | path : String::from(path), 50 | // file : file, 51 | fd : fd, 52 | flags : flags, 53 | seek : 0, 54 | shared : false, 55 | } 56 | } 57 | 58 | pub fn set_shared(&mut self, shared: bool) { 59 | self.shared = shared; 60 | } 61 | } 62 | 63 | impl FsScheme { 64 | pub fn new(rootfs: String) -> FsScheme { 65 | FsScheme { 66 | rootfs : rootfs.clone(), 67 | open_files : HashMap::new(), 68 | } 69 | } 70 | 71 | pub fn check_for_traversal(&self, path: &str) { 72 | //! FIX ME. i'm just checking for ../ == ParentDir 73 | let path = path::Path::new(path); 74 | 75 | for component in path.components().into_iter() { 76 | match component { 77 | path::Component::ParentDir => { 78 | panic!("trying to do dir traversal??/"); 79 | }, 80 | _ => { 81 | } 82 | } 83 | } 84 | } 85 | 86 | pub fn open(&mut self, path: &str, flags: i32) -> RawFd { 87 | 88 | self.check_for_traversal(path); 89 | 90 | let full_path = self.change_path_if_special(path); 91 | 92 | let file = OpenOptions::new().custom_flags(flags as i32) 93 | .create(flags & libc::O_ACCMODE == libc::O_CREAT) 94 | .read((flags & libc::O_ACCMODE == libc::O_RDONLY) || (flags & libc::O_ACCMODE == libc::O_RDWR)) 95 | .write((flags & libc::O_ACCMODE == libc::O_WRONLY) || (flags & libc::O_ACCMODE == libc::O_RDWR)) 96 | .open(&full_path); 97 | 98 | match file.ok() { 99 | Some(v) => { 100 | let fd = v.into_raw_fd(); 101 | let ofile = oFile::new(path, fd, flags); 102 | self.open_files.insert(fd, ofile); 103 | fd 104 | }, 105 | None => { 106 | -1 107 | } 108 | } 109 | } 110 | 111 | pub fn openat(&mut self, dirfd: RawFd, path: &str, flags: i32, mode: i32) -> RawFd { 112 | if dirfd >0 && dirfd < 256 { 113 | unsafe { 114 | self.check_for_traversal(path); 115 | let fd = libc::openat(dirfd, path.as_ptr() as *mut libc::c_char, flags); 116 | let ofile = oFile::new(path, fd, flags); 117 | self.open_files.insert(fd, ofile); 118 | 119 | fd 120 | } 121 | } 122 | else { 123 | self.open(&path, flags) 124 | } 125 | } 126 | 127 | pub fn write(&mut self, fd: RawFd, buffer: &mut [u8]) -> io::Result { 128 | unsafe { 129 | let res = libc::write(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()); 130 | Ok(res as usize) 131 | } 132 | } 133 | 134 | pub fn read(&self, fd: RawFd, buffer: &mut [u8]) -> io::Result { 135 | unsafe { 136 | let res = libc::read(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()); 137 | Ok(res as usize) 138 | } 139 | } 140 | 141 | pub fn pread(&self, fd: RawFd, buf: &mut [u8], offset: u64) -> io::Result { 142 | unsafe 143 | { 144 | let orig_off = libc::lseek(fd, 0, libc::SEEK_CUR); 145 | libc::lseek(fd, offset as i64, libc::SEEK_SET); 146 | let ret = self.read(fd, buf).unwrap(); 147 | libc::lseek(fd, orig_off as i64, libc::SEEK_SET); 148 | Ok(ret) 149 | } 150 | } 151 | 152 | pub fn close(&mut self, fd: i32) { 153 | unsafe { 154 | libc::close(fd); 155 | } 156 | let file = self.open_files.get(&fd); 157 | match file { 158 | Some(v) => { 159 | self.open_files.remove(&fd); 160 | }, 161 | None => { } 162 | } 163 | } 164 | 165 | pub fn get_local_file(&self, fd: RawFd) -> Option<&oFile> { 166 | for (f, file) in self.open_files.iter() { 167 | if *f == fd { 168 | return Some(file); 169 | } 170 | } 171 | None 172 | } 173 | 174 | pub fn set_ofile_shared(&mut self, path: &str, shared: bool) { 175 | for (f, file) in self.open_files.iter_mut() { 176 | if file.path == path { 177 | file.set_shared(shared); 178 | } 179 | } 180 | } 181 | 182 | pub fn change_path_if_special(&self, path: &str) -> String { 183 | if self.is_driver_io(path) { 184 | return String::from(path); 185 | } 186 | 187 | let res = match path { 188 | "/sys/fs/selinux/null" => { 189 | String::from("/dev/null") 190 | }, 191 | _ => { 192 | // let res = format!("{}/{}", self.rootfs, path); 193 | let mut res = String::new(); 194 | res.push_str(&self.rootfs); 195 | res.push('/'); 196 | res.push_str(path); 197 | res 198 | } 199 | }; 200 | // println!("{}", res); 201 | res 202 | } 203 | 204 | pub fn is_driver_io(&self, path: &str) -> bool { 205 | match path { 206 | "/dev/urandom" | "/dev/random"| "/dev/srandom" | "/proc/self/exe" | "/dev/null" => { 207 | true 208 | }, 209 | path if path.contains("/proc/self/fd") => { 210 | true 211 | }, 212 | _ => { 213 | false 214 | } 215 | } 216 | } 217 | 218 | pub fn get_path(&mut self, fd: RawFd) -> Result { 219 | for (f, file) in self.open_files.iter() { 220 | if fd == *f { 221 | return Ok(file.path.clone()); 222 | } 223 | } 224 | Err(fserrors::Error::new(fserrors::ENOENT)) 225 | } 226 | } -------------------------------------------------------------------------------- /code/src/core/android/syscalls/mman.rs: -------------------------------------------------------------------------------- 1 | use xmas_elf::program; 2 | 3 | use crate::utilities; 4 | use crate::core::mmu::MapInfo; 5 | use crate::core::rudroid::Emulator; 6 | use crate::core::android::fs::MAX_FDS; 7 | use crate::core::unicorn::unicorn_const::Protection; 8 | 9 | const MAP_FIXED : u64 = 0x10; 10 | const MAP_ANONYMOUS : u64 = 0x20; 11 | const MREMAP_MAYMOVE : u64 = 0x1; 12 | 13 | impl Emulator { 14 | pub fn sys_mmap(&mut self) { 15 | let addr = self.get_arg(0); 16 | let len = self.get_arg(1); 17 | let prot = self.get_arg(2); 18 | let flags = self.get_arg(3); 19 | let fd : i32 = self.get_arg(4) as i32; 20 | let off = self.get_arg(5) ; 21 | 22 | let aligned_len = self.align_len(len); 23 | 24 | let mut mmap_base = addr; 25 | let mut need_map : bool = true; 26 | 27 | if addr == 0 { 28 | mmap_base = self.mmap_address; 29 | self.mmap_address = mmap_base + aligned_len; 30 | } 31 | 32 | else { 33 | need_map = false; 34 | } 35 | 36 | let is_fixed = (flags & MAP_FIXED) != 0; 37 | if self.debug { 38 | self.debug_print(format!("mmap_base 0x{:x} length 0x{:x} fixed: {} = ({:x}, {:x})", addr, len, is_fixed, mmap_base, aligned_len as usize)); 39 | } 40 | 41 | if need_map { 42 | self.mmu_map(mmap_base, aligned_len as usize, Protection::ALL, "[syscall_mmap]", self.null_mut()); 43 | } 44 | 45 | if (( flags & MAP_ANONYMOUS) == 0 ) && fd < MAX_FDS && fd > 0 { 46 | let mut data = vec![0u8; len as usize]; 47 | self.filesystem.pread(fd, &mut data, off).unwrap(); 48 | 49 | let mem_info: &str = &self.filesystem.get_path(fd).unwrap(); 50 | 51 | let map_info = MapInfo { 52 | memory_start : mmap_base, 53 | memory_end : mmap_base+((len+0x1000-1)/0x1000) * 0x1000, 54 | memory_perms : Protection::ALL, 55 | description : String::from(mem_info), 56 | }; 57 | 58 | self.add_mapinfo(map_info); 59 | self.write(mmap_base, &data); 60 | } 61 | 62 | self.set_return_val(mmap_base); 63 | } 64 | 65 | pub fn sys_mprotect(&mut self) { 66 | let start = self.get_arg(0); 67 | let len = self.get_arg(1); 68 | let prot = self.get_arg(2); 69 | 70 | if self.debug { 71 | self.debug_print(format!("mprotect(0x{:x}, 0x{:x}, {})", start, len, prot)); 72 | } 73 | self.set_return_val(0); 74 | } 75 | 76 | pub fn sys_munmap(&mut self) { 77 | let address = self.get_arg(0); 78 | let len = self.get_arg(1); 79 | 80 | if self.debug { 81 | self.debug_print(format!("sys_munmap(0x{:x}, 0x{:x})",address, len)); 82 | } 83 | 84 | let aligned = ((len + 0x1000 - 1) / 0x1000) * 0x1000; 85 | self.mmu_unmap(address, aligned as usize); 86 | // self.munmap(address, len, aligned); 87 | self.set_return_val(0); 88 | } 89 | 90 | pub fn munmap(&mut self, address: u64, len: u64, aligned: u64) { 91 | let removed = self.map_infos.remove_entry(&address); 92 | 93 | let mut nmap_info : MapInfo = MapInfo { 94 | memory_start : 0, 95 | memory_end : 0, 96 | memory_perms : Protection::NONE, 97 | description : String::new() 98 | }; 99 | 100 | match removed { 101 | Some(v) => { 102 | let addr = v.0; 103 | let map_info = v.1; 104 | 105 | let removed_size: u64 = map_info.memory_end - map_info.memory_start; 106 | 107 | if map_info.memory_end - map_info.memory_start != aligned { 108 | 109 | if aligned >= removed_size { 110 | if self.debug { 111 | self.debug_print(format!("sys_munmap removed=0x{:x} aligned=0x{:x} start=0x{:x} ",removed_size, aligned, address)); 112 | } 113 | let mut addr = address + removed_size; 114 | let mut size = aligned - removed_size; 115 | loop { 116 | if size == 0 { 117 | break; 118 | } 119 | 120 | self.map_infos.remove_entry(&addr); 121 | addr += removed_size; 122 | size -= removed_size; 123 | } 124 | // return ; 125 | } 126 | 127 | 128 | nmap_info = MapInfo { 129 | memory_start : address, 130 | memory_end : address + aligned, 131 | memory_perms : map_info.memory_perms, 132 | description : map_info.description.clone() 133 | }; 134 | } 135 | 136 | if self.map_infos.is_empty() { 137 | self.mmap_address = address; 138 | } 139 | }, 140 | None => { 141 | for (addr, map_info) in self.map_infos.iter_mut() { 142 | if address > *addr && address < map_info.memory_end { 143 | if address + aligned < map_info.memory_end { 144 | let new_size = map_info.memory_end - address - aligned; 145 | 146 | if self.debug { 147 | println!("sys_munmap aligned = 0x{:x} start=0x{:x} base=0x{:x} size={}", aligned, address, address+aligned, new_size); 148 | } 149 | 150 | nmap_info = MapInfo { 151 | memory_start : address + aligned, 152 | memory_end : address + aligned + new_size, 153 | memory_perms : map_info.memory_perms, 154 | description : map_info.description.clone() 155 | }; 156 | } 157 | } 158 | } 159 | } 160 | }; 161 | 162 | if nmap_info.memory_start != 0 { 163 | // self.add_mapinfo(nmap_info); 164 | self.debug_print(format!("sys_munmap address: 0x{:x} len=0x{:x} ",nmap_info.memory_start, (nmap_info.memory_end - nmap_info.memory_start))); 165 | 166 | let desc: &str = &nmap_info.description; 167 | self.mmu_map(nmap_info.memory_start, (nmap_info.memory_end - nmap_info.memory_start) as usize, nmap_info.memory_perms, "munmap", self.null_mut()); 168 | } 169 | } 170 | 171 | pub fn sys_mremap(&mut self) { 172 | // sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr); 173 | 174 | let address = self.get_arg(0); 175 | let old_len = self.get_arg(1); 176 | let new_len = self.get_arg(2); 177 | let flags = self.get_arg(3); 178 | let new_addr = self.get_arg(4); 179 | 180 | let aligned_old_len = ((old_len + 0x1000 - 1) / 0x1000) * 0x1000; 181 | let aligned_new_len = ((new_len + 0x1000 - 1) / 0x1000) * 0x1000; 182 | 183 | if self.debug { 184 | self.debug_print(format!("sys_mremap(0x{:x},0x{:x},0x{:x},0x{:x}, 0x{:x})", address, old_len, new_len, flags, new_addr)); 185 | } 186 | 187 | if old_len == 0 { 188 | panic!("sys_mremap: old_size is zero"); 189 | } 190 | 191 | if flags & MREMAP_MAYMOVE == 0 { 192 | panic!("sys_mremap: flags = {:x}", flags); 193 | } 194 | 195 | let mut nmap_info : MapInfo = MapInfo { 196 | memory_start : 0, 197 | memory_end : 0, 198 | memory_perms : Protection::NONE, 199 | description : String::new() 200 | }; 201 | 202 | for (addr, map_info) in self.map_infos.iter_mut() { 203 | if address >= map_info.memory_start && address + old_len <= map_info.memory_end { 204 | nmap_info = MapInfo { 205 | memory_start : map_info.memory_start, 206 | memory_end : map_info.memory_end, 207 | memory_perms : map_info.memory_perms, 208 | description : map_info.description.clone() 209 | }; 210 | } 211 | } 212 | 213 | if nmap_info.memory_start != nmap_info.memory_end && nmap_info.memory_end != 0 { 214 | 215 | let len = nmap_info.memory_end - nmap_info.memory_start; 216 | 217 | let data = self.mem_read_as_vec(nmap_info.memory_start, len as usize).unwrap(); 218 | self.mmu_unmap(address, len as usize); 219 | let mmap_base = self.mmap_address; 220 | self.mmap_address = self.uc_align_down(mmap_base + aligned_new_len); 221 | self.mmu_map(mmap_base, aligned_new_len as usize, Protection::ALL, "[syscall_mmap]", self.null_mut()); 222 | self.mem_write(mmap_base, &data); 223 | println!("memory_start {:x} memory_end {:x} memory_perms : {} description: {}", nmap_info.memory_start, nmap_info.memory_end, nmap_info.memory_perms, nmap_info.description); 224 | 225 | self.set_return_val(mmap_base); 226 | return; 227 | } 228 | 229 | self.set_return_val(0xffff_ffff); 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /code/src/core/android/syscalls/syscalls.rs: -------------------------------------------------------------------------------- 1 | 2 | #[repr(u64)] 3 | #[derive(Debug)] 4 | //taken from android kernel's include/uapi/asm-generic/unistd.h 5 | pub enum Syscalls { 6 | __NR_io_setup = 0, 7 | __NR_io_destroy = 1, 8 | __NR_io_submit = 2, 9 | __NR_io_cancel = 3, 10 | __NR_io_getevents = 4, 11 | __NR_setxattr = 5, 12 | __NR_lsetxattr = 6, 13 | __NR_fsetxattr = 7, 14 | __NR_getxattr = 8, 15 | __NR_lgetxattr = 9, 16 | __NR_fgetxattr = 10, 17 | __NR_listxattr = 11, 18 | __NR_llistxattr = 12, 19 | __NR_flistxattr = 13, 20 | __NR_removexattr = 14, 21 | __NR_lremovexattr = 15, 22 | __NR_fremovexattr = 16, 23 | __NR_getcwd = 17, 24 | __NR_lookup_dcookie = 18, 25 | __NR_eventfd2 = 19, 26 | __NR_epoll_create1 = 20, 27 | __NR_epoll_ctl = 21, 28 | __NR_epoll_pwait = 22, 29 | __NR_dup = 23, 30 | __NR_dup3 = 24, 31 | __NR3264_fcntl = 25, 32 | __NR_inotify_init1 = 26, 33 | __NR_inotify_add_watch = 27, 34 | __NR_inotify_rm_watch = 28, 35 | __NR_ioctl = 29, 36 | __NR_ioprio_set = 30, 37 | __NR_ioprio_get = 31, 38 | __NR_flock = 32, 39 | __NR_mknodat = 33, 40 | __NR_mkdirat = 34, 41 | __NR_unlinkat = 35, 42 | __NR_symlinkat = 36, 43 | __NR_linkat = 37, 44 | __NR_renameat = 38, 45 | __NR_umount2 = 39, 46 | __NR_mount = 40, 47 | __NR_pivot_root = 41, 48 | __NR_nfsservctl = 42, 49 | __NR3264_statfs = 43, 50 | __NR3264_fstatfs = 44, 51 | __NR3264_truncate = 45, 52 | __NR3264_ftruncate = 46, 53 | __NR_fallocate = 47, 54 | __NR_faccessat = 48, 55 | __NR_chdir = 49, 56 | __NR_fchdir = 50, 57 | __NR_chroot = 51, 58 | __NR_fchmod = 52, 59 | __NR_fchmodat = 53, 60 | __NR_fchownat = 54, 61 | __NR_fchown = 55, 62 | __NR_openat = 56, 63 | __NR_close = 57, 64 | __NR_vhangup = 58, 65 | __NR_pipe2 = 59, 66 | __NR_quotactl = 60, 67 | __NR_getdents64 = 61, 68 | __NR3264_lseek = 62, 69 | __NR_read = 63, 70 | __NR_write = 64, 71 | __NR_readv = 65, 72 | __NR_writev = 66, 73 | __NR_pread64 = 67, 74 | __NR_pwrite64 = 68, 75 | __NR_preadv = 69, 76 | __NR_pwritev = 70, 77 | __NR3264_sendfile = 71, 78 | __NR_pselect6 = 72, 79 | __NR_ppoll = 73, 80 | __NR_signalfd4 = 74, 81 | __NR_vmsplice = 75, 82 | __NR_splice = 76, 83 | __NR_tee = 77, 84 | __NR_readlinkat = 78, 85 | __NR3264_fstatat = 79, 86 | __NR3264_fstat = 80, 87 | __NR_sync = 81, 88 | __NR_fsync = 82, 89 | __NR_fdatasync = 83, 90 | __NR_sync_file_range2 = 84, 91 | // __NR_sync_file_range = 84, 92 | __NR_timerfd_create = 85, 93 | __NR_timerfd_settime = 86, 94 | __NR_timerfd_gettime = 87, 95 | __NR_utimensat = 88, 96 | __NR_acct = 89, 97 | __NR_capget = 90, 98 | __NR_capset = 91, 99 | __NR_personality = 92, 100 | __NR_exit = 93, 101 | __NR_exit_group = 94, 102 | __NR_waitid = 95, 103 | __NR_set_tid_address = 96, 104 | __NR_unshare = 97, 105 | __NR_futex = 98, 106 | __NR_set_robust_list = 99, 107 | __NR_get_robust_list = 100, 108 | __NR_nanosleep = 101, 109 | __NR_getitimer = 102, 110 | __NR_setitimer = 103, 111 | __NR_kexec_load = 104, 112 | __NR_init_module = 105, 113 | __NR_delete_module = 106, 114 | __NR_timer_create = 107, 115 | __NR_timer_gettime = 108, 116 | __NR_timer_getoverrun = 109, 117 | __NR_timer_settime = 110, 118 | __NR_timer_delete = 111, 119 | __NR_clock_settime = 112, 120 | __NR_clock_gettime = 113, 121 | __NR_clock_getres = 114, 122 | __NR_clock_nanosleep = 115, 123 | __NR_syslog = 116, 124 | __NR_ptrace = 117, 125 | __NR_sched_setparam = 118, 126 | __NR_sched_setscheduler = 119, 127 | __NR_sched_getscheduler = 120, 128 | __NR_sched_getparam = 121, 129 | __NR_sched_setaffinity = 122, 130 | __NR_sched_getaffinity = 123, 131 | __NR_sched_yield = 124, 132 | __NR_sched_get_priority_max = 125, 133 | __NR_sched_get_priority_min = 126, 134 | __NR_sched_rr_get_interval = 127, 135 | __NR_restart_syscall = 128, 136 | __NR_kill = 129, 137 | __NR_tkill = 130, 138 | __NR_tgkill = 131, 139 | __NR_sigaltstack = 132, 140 | __NR_rt_sigsuspend = 133, 141 | __NR_rt_sigaction = 134, 142 | __NR_rt_sigprocmask = 135, 143 | __NR_rt_sigpending = 136, 144 | __NR_rt_sigtimedwait = 137, 145 | __NR_rt_sigqueueinfo = 138, 146 | __NR_rt_sigreturn = 139, 147 | __NR_setpriority = 140, 148 | __NR_getpriority = 141, 149 | __NR_reboot = 142, 150 | __NR_setregid = 143, 151 | __NR_setgid = 144, 152 | __NR_setreuid = 145, 153 | __NR_setuid = 146, 154 | __NR_setresuid = 147, 155 | __NR_getresuid = 148, 156 | __NR_setresgid = 149, 157 | __NR_getresgid = 150, 158 | __NR_setfsuid = 151, 159 | __NR_setfsgid = 152, 160 | __NR_times = 153, 161 | __NR_setpgid = 154, 162 | __NR_getpgid = 155, 163 | __NR_getsid = 156, 164 | __NR_setsid = 157, 165 | __NR_getgroups = 158, 166 | __NR_setgroups = 159, 167 | __NR_uname = 160, 168 | __NR_sethostname = 161, 169 | __NR_setdomainname = 162, 170 | __NR_getrlimit = 163, 171 | __NR_setrlimit = 164, 172 | __NR_getrusage = 165, 173 | __NR_umask = 166, 174 | __NR_prctl = 167, 175 | __NR_getcpu = 168, 176 | __NR_gettimeofday = 169, 177 | __NR_settimeofday = 170, 178 | __NR_adjtimex = 171, 179 | __NR_getpid = 172, 180 | __NR_getppid = 173, 181 | __NR_getuid = 174, 182 | __NR_geteuid = 175, 183 | __NR_getgid = 176, 184 | __NR_getegid = 177, 185 | __NR_gettid = 178, 186 | __NR_sysinfo = 179, 187 | __NR_mq_open = 180, 188 | __NR_mq_unlink = 181, 189 | __NR_mq_timedsend = 182, 190 | __NR_mq_timedreceive = 183, 191 | __NR_mq_notify = 184, 192 | __NR_mq_getsetattr = 185, 193 | __NR_msgget = 186, 194 | __NR_msgctl = 187, 195 | __NR_msgrcv = 188, 196 | __NR_msgsnd = 189, 197 | __NR_semget = 190, 198 | __NR_semctl = 191, 199 | __NR_semtimedop = 192, 200 | __NR_semop = 193, 201 | __NR_shmget = 194, 202 | __NR_shmctl = 195, 203 | __NR_shmat = 196, 204 | __NR_shmdt = 197, 205 | __NR_socket = 198, 206 | __NR_socketpair = 199, 207 | __NR_bind = 200, 208 | __NR_listen = 201, 209 | __NR_accept = 202, 210 | __NR_connect = 203, 211 | __NR_getsockname = 204, 212 | __NR_getpeername = 205, 213 | __NR_sendto = 206, 214 | __NR_recvfrom = 207, 215 | __NR_setsockopt = 208, 216 | __NR_getsockopt = 209, 217 | __NR_shutdown = 210, 218 | __NR_sendmsg = 211, 219 | __NR_recvmsg = 212, 220 | __NR_readahead = 213, 221 | __NR_brk = 214, 222 | __NR_munmap = 215, 223 | __NR_mremap = 216, 224 | __NR_add_key = 217, 225 | __NR_request_key = 218, 226 | __NR_keyctl = 219, 227 | __NR_clone = 220, 228 | __NR_execve = 221, 229 | __NR3264_mmap = 222, 230 | __NR3264_fadvise64 = 223, 231 | __NR_swapon = 224, 232 | __NR_swapoff = 225, 233 | __NR_mprotect = 226, 234 | __NR_msync = 227, 235 | __NR_mlock = 228, 236 | __NR_munlock = 229, 237 | __NR_mlockall = 230, 238 | __NR_munlockall = 231, 239 | __NR_mincore = 232, 240 | __NR_madvise = 233, 241 | __NR_remap_file_pages = 234, 242 | __NR_mbind = 235, 243 | __NR_get_mempolicy = 236, 244 | __NR_set_mempolicy = 237, 245 | __NR_migrate_pages = 238, 246 | __NR_move_pages = 239, 247 | __NR_rt_tgsigqueueinfo = 240, 248 | __NR_perf_event_open = 241, 249 | __NR_accept4 = 242, 250 | __NR_recvmmsg = 243, 251 | __NR_arch_specific_syscall = 244, 252 | __NR_wait4 = 260, 253 | __NR_prlimit64 = 261, 254 | __NR_fanotify_init = 262, 255 | __NR_fanotify_mark = 263, 256 | __NR_name_to_handle_at = 264, 257 | __NR_open_by_handle_at = 265, 258 | __NR_clock_adjtime = 266, 259 | __NR_syncfs = 267, 260 | __NR_setns = 268, 261 | __NR_sendmmsg = 269, 262 | __NR_process_vm_readv = 270, 263 | __NR_process_vm_writev = 271, 264 | __NR_kcmp = 272, 265 | __NR_finit_module = 273, 266 | __NR_sched_setattr = 274, 267 | __NR_sched_getattr = 275, 268 | __NR_renameat2 = 276, 269 | __NR_seccomp = 277, 270 | __NR_getrandom = 278, 271 | __NR_memfd_create = 279, 272 | __NR_bpf = 280, 273 | __NR_execveat = 281, 274 | __NR_userfaultfd = 282, 275 | __NR_membarrier = 283, 276 | __NR_mlock2 = 284, 277 | __NR_copy_file_range = 285, 278 | __NR_preadv2 = 286, 279 | __NR_pwritev2 = 287, 280 | __NR_pkey_mprotect = 288, 281 | __NR_pkey_alloc = 289, 282 | __NR_pkey_free = 290, 283 | __NR_statx = 291, 284 | __NR_syscalls = 292, 285 | __NR_open = 1024, 286 | __NR_link = 1025, 287 | __NR_unlink = 1026, 288 | __NR_mknod = 1027, 289 | __NR_chmod = 1028, 290 | __NR_chown = 1029, 291 | __NR_mkdir = 1030, 292 | __NR_rmdir = 1031, 293 | __NR_lchown = 1032, 294 | __NR_access = 1033, 295 | __NR_rename = 1034, 296 | __NR_readlink = 1035, 297 | __NR_symlink = 1036, 298 | __NR_utimes = 1037, 299 | __NR3264_stat = 1038, 300 | __NR3264_lstat = 1039, 301 | // __NR_syscalls = (__NR3264_lstat+1), 302 | __NR_pipe = 1040, 303 | __NR_dup2 = 1041, 304 | __NR_epoll_create = 1042, 305 | __NR_inotify_init = 1043, 306 | __NR_eventfd = 1044, 307 | __NR_signalfd = 1045, 308 | // __NR_syscalls = (__NR_signalfd+1), 309 | __NR_sendfile = 1046, 310 | __NR_ftruncate = 1047, 311 | __NR_truncate = 1048, 312 | __NR_stat = 1049, 313 | __NR_lstat = 1050, 314 | __NR_fstat = 1051, 315 | __NR_fcntl = 1052, 316 | __NR_fadvise64 = 1053, 317 | __NR_newfstatat = 1054, 318 | __NR_fstatfs = 1055, 319 | __NR_statfs = 1056, 320 | __NR_lseek = 1057, 321 | __NR_mmap = 1058, 322 | // __NR_syscalls = (__NR_mmap+1), 323 | __NR_alarm = 1059, 324 | __NR_getpgrp = 1060, 325 | __NR_pause = 1061, 326 | __NR_time = 1062, 327 | __NR_utime = 1063, 328 | __NR_creat = 1064, 329 | __NR_getdents = 1065, 330 | __NR_futimesat = 1066, 331 | __NR_select = 1067, 332 | __NR_poll = 1068, 333 | __NR_epoll_wait = 1069, 334 | __NR_ustat = 1070, 335 | __NR_vfork = 1071, 336 | __NR_oldwait4 = 1072, 337 | __NR_recv = 1073, 338 | __NR_send = 1074, 339 | __NR_bdflush = 1075, 340 | __NR_umount = 1076, 341 | __NR_uselib = 1077, 342 | __NR__sysctl = 1078, 343 | __NR_fork = 1079, 344 | // __NR_syscalls = (__NR_fork+1), 345 | // __NR_fcntl = __NR3264_fcntl, 346 | // __NR_statfs = __NR3264_statfs, 347 | // __NR_fstatfs = __NR3264_fstatfs, 348 | // __NR_truncate = __NR3264_truncate, 349 | // __NR_ftruncate = __NR3264_ftruncate, 350 | // __NR_lseek = __NR3264_lseek, 351 | // __NR_sendfile = __NR3264_sendfile, 352 | // __NR_newfstatat = __NR3264_fstatat, 353 | // __NR_fstat = __NR3264_fstat, 354 | // __NR_mmap = __NR3264_mmap, 355 | // __NR_fadvise64 = __NR3264_fadvise64, 356 | // __NR_stat = __NR3264_stat, 357 | // __NR_lstat = __NR3264_lstat, 358 | // __NR_fcntl64 = __NR3264_fcntl, 359 | // __NR_statfs64 = __NR3264_statfs, 360 | // __NR_fstatfs64 = __NR3264_fstatfs, 361 | // __NR_truncate64 = __NR3264_truncate, 362 | // __NR_ftruncate64 = __NR3264_ftruncate, 363 | // __NR_llseek = __NR3264_lseek, 364 | // __NR_sendfile64 = __NR3264_sendfile, 365 | // __NR_fstatat64 = __NR3264_fstatat, 366 | // __NR_fstat64 = __NR3264_fstat, 367 | // __NR_mmap2 = __NR3264_mmap, 368 | // __NR_fadvise64_64 = __NR3264_fadvise64, 369 | // __NR_stat64 = __NR3264_stat, 370 | // __NR_lstat64 = __NR3264_lstat, 371 | 372 | None, 373 | } -------------------------------------------------------------------------------- /code/src/core/mmu.rs: -------------------------------------------------------------------------------- 1 | use libc::c_void; 2 | use xmas_elf::header; 3 | use std::collections::HashMap; 4 | 5 | use super::rudroid::Emulator; 6 | use super::unicorn::unicorn_const::Protection; 7 | use super::unicorn::arch::arm64::RegisterARM64; 8 | use byteorder::{ByteOrder, BigEndian, LittleEndian}; 9 | 10 | #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] 11 | pub struct MapInfo { 12 | pub memory_start : u64, 13 | pub memory_end : u64, 14 | pub memory_perms : Protection, 15 | pub description : String, 16 | } 17 | 18 | impl Clone for MapInfo { 19 | fn clone(&self) -> Self { 20 | MapInfo { 21 | memory_start : self.memory_start, 22 | memory_end : self.memory_end, 23 | memory_perms : self.memory_perms, 24 | description : self.description.clone(), 25 | } 26 | } 27 | } 28 | 29 | impl std::fmt::Display for MapInfo { 30 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 31 | write!(f, "memory_start {:x} memory_end {:x} memory_perms : {} description: {}", self.memory_start, self.memory_end, self.memory_perms, self.description).unwrap(); 32 | Ok(()) 33 | } 34 | } 35 | 36 | impl Emulator { 37 | pub fn mmu_map(&mut self, address: u64, size: usize, perms: Protection, description: &str, host_ptr: *mut c_void) -> bool { 38 | 39 | if self.is_mapped(address, size as u64) { 40 | return true; 41 | } 42 | 43 | if host_ptr.is_null() { 44 | // let _ = self.mem_map(address, size, perms).expect("mmu_map failed!"); 45 | let _ = self.mem_map(address, size, perms).unwrap(); 46 | } 47 | else { 48 | // Map an existing memory region in the emulator at the specified address. 49 | // 50 | // This function is marked unsafe because it is the responsibility of the caller to 51 | // ensure that `size` matches the size of the passed buffer, an invalid `size` value will 52 | // likely cause a crash in unicorn. 53 | // 54 | // `address` must be aligned to 4kb or this will return `Error::ARG`. 55 | // 56 | // `size` must be a multiple of 4kb or this will return `Error::ARG`. 57 | // 58 | // `ptr` is a pointer to the provided memory region that will be used by the emulator. 59 | let _ = unsafe { self.mem_map_ptr(address, size, perms, host_ptr).expect("mem_map_ptr failed !"); }; 60 | } 61 | 62 | let desc = match description.len() { 63 | 0 => { 64 | String::from("[mapped]") 65 | }, 66 | _ => { 67 | String::from(description) 68 | } 69 | }; 70 | 71 | let map_info = MapInfo { 72 | memory_start : address, 73 | memory_end : address.checked_add(size as u64).unwrap(), 74 | memory_perms : perms, 75 | description : desc, 76 | }; 77 | 78 | self.add_mapinfo(map_info); 79 | 80 | true 81 | } 82 | 83 | pub fn add_mapinfo(&mut self, map_info: MapInfo) { 84 | // self.map_infos.push(map_info); 85 | self.map_infos.insert(map_info.memory_start, map_info); 86 | } 87 | 88 | pub fn mmu_unmap(&mut self, address: u64, size: usize) { 89 | let removed = self.map_infos.remove_entry(&address); 90 | self.mem_unmap(address, size); 91 | } 92 | 93 | pub fn is_mapped(&mut self, address: u64, size: u64) -> bool { 94 | let regions = self.mem_regions().unwrap(); 95 | if regions.len() <= 1 { 96 | return false; 97 | } 98 | 99 | for region in self.mem_regions() { 100 | let val = (region[0].begin >= address) & ((address + size - 1) <= region[1].begin); 101 | match val { 102 | true => { 103 | return true; 104 | }, 105 | _ => { 106 | 107 | } 108 | } 109 | }; 110 | 111 | false 112 | } 113 | 114 | pub fn mmu_mem_set(&mut self, addr: u64, value: char, size: usize) { 115 | let data = vec![value; size].iter().map(|c| *c as u8).collect::>(); 116 | self.mem_write(addr, &data).expect("mmu_mem_set failed"); 117 | } 118 | 119 | pub fn get_mapped(&self, address: u64, len: u64) -> Option<&MapInfo> { 120 | for (addr, map_info) in self.map_infos.iter() { 121 | if address > *addr && address + len < map_info.memory_end { 122 | return Some(&map_info); 123 | } 124 | } 125 | None 126 | } 127 | 128 | pub fn update_mapped_perms(&mut self, address: u64, len: u64, perms: Protection) -> Option<&MapInfo> { 129 | for (addr, map_info) in self.map_infos.iter_mut() { 130 | if address > *addr && address + len < map_info.memory_end { 131 | // return Some(&map_info); 132 | map_info.memory_perms = perms; 133 | } 134 | } 135 | None 136 | } 137 | 138 | pub fn get_mapped_with_desc(&self, desc: String) -> HashMap { 139 | let mut mappings: HashMap = HashMap::new(); 140 | 141 | for (addr, map_info) in self.map_infos.iter() { 142 | if map_info.description == desc { 143 | mappings.insert(*addr, map_info.clone()); 144 | } 145 | } 146 | 147 | mappings 148 | } 149 | 150 | pub fn display_mapped(&self) { 151 | let mut v: Vec<_> = Vec::new(); 152 | for (addr, map_info) in self.map_infos.iter() { 153 | v.push((addr, map_info)); 154 | } 155 | v.sort_by(|x,y| x.0.cmp(&y.0)); 156 | 157 | for (addr, map_info) in v { 158 | println!("{}", map_info); 159 | } 160 | } 161 | 162 | pub fn read(&self, address: u64, size: usize) -> Vec { 163 | self.mem_read_as_vec(address, size).unwrap() 164 | } 165 | 166 | pub fn write(&mut self, address: u64, data: &[u8]) { 167 | self.mem_write(address, data).expect("mmu.write"); 168 | } 169 | 170 | pub fn copy_str(&mut self, address: u64, string: &mut str) -> u64 { 171 | let data = string.as_bytes(); 172 | let address: u64 = ((address as usize) - data.len() - 1) as u64; 173 | self.write(address, data); 174 | address 175 | } 176 | 177 | fn stack_push(&mut self, value: u64) { 178 | let mut sp = self.read_sp(); 179 | sp = sp-8; 180 | self.write_sp(sp); 181 | 182 | self.write(sp, &self.pack_64(value)); 183 | } 184 | 185 | fn stack_pop(&mut self) -> u64 { 186 | let mut sp = self.read_sp(); 187 | sp = sp-8; 188 | self.write_sp(sp); 189 | 190 | let data = self.read(sp, 8); 191 | self.unpack_64(&data) 192 | } 193 | 194 | fn stack_read(&mut self, offset: u32) -> u64 { 195 | let mut sp = self.read_sp(); 196 | let data = self.read(sp+ offset as u64, 8); 197 | self.unpack_64(&data) 198 | } 199 | 200 | fn stack_write(&mut self, offset: usize, data: &[u8]) { 201 | let mut sp = self.read_sp() + offset as u64; 202 | self.write(sp, data); 203 | } 204 | 205 | fn read_sp(&mut self) -> u64 { 206 | self.reg_read(RegisterARM64::SP as i32).unwrap() 207 | } 208 | 209 | fn write_sp(&mut self, value: u64) { 210 | self.reg_write(RegisterARM64::SP as i32, value); 211 | } 212 | 213 | fn read_pc(&mut self) -> u64 { 214 | self.reg_read(RegisterARM64::PC as i32).unwrap() 215 | } 216 | 217 | fn write_pc(&mut self, value: u64) { 218 | self.reg_write(RegisterARM64::PC as i32, value); 219 | } 220 | 221 | // unsigned pack 222 | pub fn pack(&self, value: u64) -> Vec { 223 | match self.machine { 224 | header::Machine::AArch64 => { 225 | self.pack_64(value) 226 | }, 227 | _ => { 228 | panic!(""); 229 | } 230 | } 231 | } 232 | 233 | // unsigned unpack 234 | pub fn unpack(&self, value: &[u8]) -> u64 { 235 | match self.machine { 236 | header::Machine::AArch64 => { 237 | if value.len() == 8 { 238 | self.unpack_64(value) 239 | } 240 | else if (value.len() == 4) { 241 | return self.unpack_32(value) as u64; 242 | } 243 | else { 244 | panic!("need 4 or 8 byte"); 245 | } 246 | }, 247 | _ => { 248 | panic!(""); 249 | } 250 | } 251 | } 252 | 253 | pub fn pack_64(&self, value: u64) -> Vec { 254 | match self.endian { 255 | header::Data::BigEndian => { 256 | value.to_be_bytes().to_vec() 257 | }, 258 | header::Data::LittleEndian => { 259 | value.to_le_bytes().to_vec() 260 | }, 261 | _ => { 262 | panic!("what kiinda endian is this") 263 | } 264 | } 265 | } 266 | 267 | pub fn pack_64s(&self, value: i64, buf: &mut [u8]) { 268 | match self.endian { 269 | header::Data::BigEndian => { 270 | BigEndian::write_i64(buf, value) 271 | }, 272 | header::Data::LittleEndian => { 273 | // LittleEndian::write_i64(buf, value) 274 | }, 275 | _ => { 276 | panic!("what kiinda endian is this") 277 | } 278 | }; 279 | } 280 | 281 | pub fn unpack_64(&self, value: &[u8]) -> u64 { 282 | match self.endian { 283 | header::Data::BigEndian => { 284 | BigEndian::read_u64(value) 285 | }, 286 | header::Data::LittleEndian => { 287 | LittleEndian::read_u64(value) 288 | }, 289 | _ => { 290 | panic!("what kiinda endian is this") 291 | } 292 | } 293 | } 294 | 295 | pub fn unpack_64s(&self, value: &[u8]) -> i64 { 296 | match self.endian { 297 | header::Data::BigEndian => { 298 | BigEndian::read_i64(value) 299 | }, 300 | header::Data::LittleEndian => { 301 | LittleEndian::read_i64(value) 302 | }, 303 | _ => { 304 | panic!("what kiinda endian is this") 305 | } 306 | } 307 | } 308 | 309 | pub fn pack_32(&self, value: u32) -> Vec { 310 | match self.endian { 311 | header::Data::BigEndian => { 312 | value.to_be_bytes().to_vec() 313 | }, 314 | header::Data::LittleEndian => { 315 | value.to_le_bytes().to_vec() 316 | }, 317 | _ => { 318 | panic!("what kiinda endian is this") 319 | } 320 | } 321 | } 322 | 323 | pub fn pack_32s(&self, value: i32, buf: &mut [u8]) { 324 | match self.endian { 325 | header::Data::BigEndian => { 326 | BigEndian::write_i32(buf, value) 327 | }, 328 | header::Data::LittleEndian => { 329 | LittleEndian::write_i32(buf, value) 330 | }, 331 | _ => { 332 | panic!("what kiinda endian is this") 333 | } 334 | }; 335 | } 336 | 337 | pub fn unpack_32(&self, value: &[u8]) -> u32 { 338 | match self.endian { 339 | header::Data::BigEndian => { 340 | BigEndian::read_u32(value) 341 | }, 342 | header::Data::LittleEndian => { 343 | LittleEndian::read_u32(value) 344 | }, 345 | _ => { 346 | panic!("what kiinda endian is this") 347 | } 348 | } 349 | } 350 | 351 | pub fn unpack_32s(&self, value: &[u8]) -> i32 { 352 | match self.endian { 353 | header::Data::BigEndian => { 354 | BigEndian::read_i32(value) 355 | }, 356 | header::Data::LittleEndian => { 357 | LittleEndian::read_i32(value) 358 | }, 359 | _ => { 360 | panic!("what kiinda endian is this") 361 | } 362 | } 363 | } 364 | 365 | pub fn get_pointer_at(&mut self, addr: u64) -> u64 { 366 | match self.machine { 367 | header::Machine::AArch64 => { 368 | let mem = self.mem_read_as_vec(addr, 8).unwrap(); 369 | self.unpack(&mem) 370 | }, 371 | _ => { 372 | panic!("get_pointer_at 0x{:x} failed", addr); 373 | } 374 | } 375 | } 376 | } -------------------------------------------------------------------------------- /code/src/core/loaders/elfLoader.rs: -------------------------------------------------------------------------------- 1 | use crate::core as linux; 2 | use crate::utilities; 3 | use xmas_elf::{header, ElfFile, program}; 4 | use super::super::rudroid::Emulator; 5 | use super::super::unicorn::unicorn_const::Protection; 6 | use super::super::unicorn::arch::arm64::RegisterARM64; 7 | 8 | 9 | /* Symbolic values for the entries in the auxiliary table 10 | put on the initial stack */ 11 | #[repr(u64)] 12 | enum AUX { 13 | AT_NULL = 0, 14 | AT_IGNORE = 1, 15 | AT_EXECFD = 2, 16 | AT_PHDR = 3, 17 | AT_PHENT = 4, 18 | AT_PHNUM = 5, 19 | AT_PAGESZ = 6, 20 | AT_BASE = 7, 21 | AT_FLAGS = 8, 22 | AT_ENTRY = 9, 23 | AT_NOTELF = 10, 24 | AT_UID = 11, 25 | AT_EUID = 12, 26 | AT_GID = 13, 27 | AT_EGID = 14, 28 | AT_PLATFORM = 15, 29 | AT_HWCAP = 16, 30 | AT_CLKTCK = 17, 31 | AT_SECURE = 23, 32 | AT_BASE_PLATFORM = 24, 33 | AT_RANDOM = 25, 34 | AT_HWCAP2 = 26, 35 | AT_EXECFN = 31, 36 | } 37 | 38 | use std::io::prelude::*; 39 | 40 | impl Emulator { 41 | 42 | pub fn load(& mut self, elf: &mut ElfFile) { 43 | self.enable_vfp(); 44 | 45 | let profile = match self.machine { 46 | header::Machine::AArch64 => { 47 | (linux::OS64::stack_address, linux::OS64::stack_size) 48 | }, 49 | _ => { 50 | panic!("[load_with_ld] Not implemented yet!") 51 | } 52 | }; 53 | 54 | let mut stack_address = profile.0 as u64; 55 | let stack_size = profile.1 as usize; 56 | 57 | self.mmu_map(stack_address, stack_size, Protection::READ|Protection::WRITE, "[stack]", self.null_mut()); 58 | self.load_with_ld(stack_address.checked_add(stack_size as u64).unwrap() , 0, self.machine, elf); 59 | stack_address = self.new_stack; 60 | self.reg_write(RegisterARM64::SP as i32, stack_address).unwrap(); 61 | } 62 | 63 | fn load_with_ld(&mut self, stack_address: u64, load_address: u64, archbit: header::Machine, elf: &mut ElfFile) { 64 | let mut load_address = match load_address { 65 | 0 => { 66 | match archbit { 67 | header::Machine::AArch64 => { 68 | self.mmap_address = linux::OS64::mmap_address as u64; 69 | linux::OS64::load_address as u64 70 | }, 71 | _ => { 72 | panic!("Shouldn't be here"); 73 | } 74 | } 75 | }, 76 | _ => { 77 | panic!("Shouldn't be here"); 78 | } 79 | }; 80 | 81 | let mut mem_start : u64 = 0xffff_ffff; 82 | let mut mem_end : u64 = 0xffff_ffff; 83 | let mut mem_s : u64 = 0; 84 | let mut mem_e : u64 = 0; 85 | 86 | let mut interp_path : String = String::new(); 87 | 88 | match elf.header.pt2.type_().as_type() { 89 | header::Type::Executable => { 90 | load_address = 0; 91 | }, 92 | header::Type::SharedObject => { 93 | 94 | } 95 | _ => { 96 | panic!("Some error in head e_type: {:?}", header::Type::SharedObject); 97 | } 98 | } 99 | 100 | for header in elf.program_iter() { 101 | match header.get_type().unwrap() { 102 | 103 | program::Type::Interp => { 104 | let offset = header.offset() as usize; 105 | let end_offset = (header.offset()+header.mem_size()) as usize; 106 | let data = elf.input.get(offset..end_offset).unwrap(); 107 | interp_path = self.null_str(std::str::from_utf8(data).unwrap()); 108 | }, 109 | 110 | program::Type::Load => { 111 | if mem_start > header.virtual_addr() || mem_start == 0xffff_ffff { 112 | mem_start = header.virtual_addr(); 113 | }; 114 | 115 | if mem_end < header.virtual_addr()+header.mem_size() || mem_end == 0xffff_ffff { 116 | mem_end = header.virtual_addr()+header.mem_size(); 117 | } 118 | }, 119 | _ => { 120 | 121 | } 122 | } 123 | } 124 | 125 | mem_start = self.uc_align_down(mem_start); 126 | mem_end = self.uc_align_up(mem_end); 127 | 128 | for header in elf.program_iter() { 129 | match header.get_type().unwrap() { 130 | program::Type::Load => { 131 | mem_s = self.uc_align_down(load_address + header.virtual_addr()); 132 | mem_e = self.uc_align_up(load_address + header.virtual_addr() + header.file_size()); 133 | let perms = utilities::to_uc_permissions(header.flags()); 134 | 135 | let desc = self.elf_path.clone(); 136 | self.mmu_map(mem_s, (mem_e-mem_s) as usize, perms, &desc, self.null_mut()); 137 | 138 | let data = elf.input.get(header.offset() as usize.. 139 | (header.offset()+header.file_size()) as usize).unwrap(); 140 | 141 | self.write(load_address+header.virtual_addr(), data); 142 | }, 143 | _ => { 144 | 145 | } 146 | } 147 | } 148 | 149 | let loaded_mem_end = load_address + mem_end; 150 | 151 | if loaded_mem_end > mem_e { 152 | let desc = self.elf_path.clone(); 153 | self.mmu_map( mem_e, (loaded_mem_end-mem_e) as usize, Protection::ALL, &desc, self.null_mut()); 154 | } 155 | 156 | self.elf_entry = elf.header.pt2.entry_point() + load_address; 157 | self.debug_print(format!("elf_entry {:x}", self.elf_entry)); 158 | 159 | self.brk_address = mem_end + load_address + 0x2000; //not sure why?? seems to be used in ql_syscall_brk 160 | 161 | // load interpreter if there is an interpreter 162 | if !interp_path.is_empty() { 163 | self.debug_print(format!("Trying to load interpreter: {}{}", self.rootfs, interp_path)); 164 | 165 | let mut interp_full_path = String::new(); 166 | 167 | interp_full_path.push_str(&self.rootfs); 168 | interp_full_path.push_str(&interp_path); 169 | 170 | let interp_data = std::fs::read(&interp_full_path).unwrap(); 171 | let interp_elf = ElfFile::new(interp_data.get(0..).unwrap()).unwrap(); 172 | 173 | let mut interp_mem_size: u64 = 0; 174 | let mut interp_address : u64 = 0; 175 | 176 | for i_header in interp_elf.program_iter() { 177 | match i_header.get_type().unwrap() { 178 | program::Type::Load => { 179 | if interp_mem_size < i_header.virtual_addr() + i_header.mem_size() || interp_mem_size == 0 { 180 | interp_mem_size = i_header.virtual_addr() + i_header.mem_size(); 181 | } 182 | }, 183 | _ => { 184 | 185 | } 186 | }; 187 | } 188 | 189 | interp_mem_size = self.uc_align_up(interp_mem_size); 190 | 191 | match archbit { 192 | header::Machine::AArch64 => { 193 | interp_address = linux::OS64::interp_address as u64; 194 | } 195 | _ => { 196 | panic!("what?"); 197 | } 198 | }; 199 | 200 | self.mmu_map(interp_address, interp_mem_size as usize , Protection::ALL, &interp_path, self.null_mut()); 201 | 202 | for i_header in interp_elf.program_iter() { 203 | match i_header.get_type().unwrap() { 204 | program::Type::Load => { 205 | let data = interp_elf.input.get(i_header.offset() as usize.. 206 | (i_header.offset()+i_header.file_size()) as usize 207 | ).unwrap(); 208 | self.write( interp_address+i_header.physical_addr(), data); 209 | }, 210 | _ => { 211 | 212 | } 213 | }; 214 | } 215 | 216 | self.interp_address = interp_address; 217 | self.entry_point = interp_elf.header.pt2.entry_point() + self.interp_address; 218 | } 219 | 220 | // setup elf table 221 | let mut elf_table: Vec = Vec::new(); 222 | 223 | let mut new_stack = stack_address; 224 | 225 | // copy arg0 on to stack. elf_path 226 | new_stack = self.copy_str(new_stack, &mut self.elf_path.clone()); 227 | 228 | elf_table.extend_from_slice(&self.pack(self.args.len() as u64 + 1)); // + 1 is for arg0 = elf path. 229 | elf_table.extend_from_slice(&self.pack(new_stack)); 230 | 231 | let mut argc = self.args.len(); 232 | 233 | loop { 234 | if argc <=0 { 235 | break; 236 | } 237 | argc -= 1; 238 | 239 | let mut arg = self.args[argc].clone(); 240 | new_stack = self.copy_str(new_stack, &mut arg); 241 | elf_table.extend_from_slice(&self.pack(new_stack)); 242 | } 243 | 244 | elf_table.extend_from_slice(&self.pack(0)); 245 | 246 | let mut envc = self.env.len(); 247 | loop { 248 | if envc <=0 { 249 | break; 250 | } 251 | envc -= 1; 252 | let mut env = self.env[envc].clone(); 253 | new_stack = self.copy_str(new_stack, &mut env); 254 | elf_table.extend_from_slice(&self.pack(new_stack)); 255 | } 256 | 257 | elf_table.extend_from_slice(&self.pack(0)); 258 | 259 | new_stack = self.alignment(new_stack); 260 | 261 | let mut randstr = "a".repeat(0x10); 262 | let mut cpustr = String::from("aarch64"); 263 | 264 | let mut addr1 = self.copy_str(new_stack, &mut randstr); 265 | new_stack = addr1; 266 | 267 | let mut addr2 = self.copy_str(new_stack, &mut cpustr); 268 | new_stack = addr2; 269 | 270 | new_stack = self.alignment(new_stack); 271 | 272 | // Set AUX 273 | let head = elf.header; 274 | 275 | let elf_phdr = load_address + head.pt2.ph_offset(); 276 | let elf_phent = head.pt2.ph_entry_size(); 277 | let elf_phnum = head.pt2.ph_count(); 278 | let elf_pagesz = 0x1000; 279 | let elf_guid = linux::uid; 280 | let elf_flags = 0; 281 | let elf_entry = load_address + head.pt2.entry_point(); 282 | let randstraddr = addr1; 283 | let cpustraddr = addr2; 284 | 285 | let elf_hwcap: u64 = match head.pt2.machine().as_machine() { 286 | header::Machine::AArch64 => { 287 | 0x078bfbfd 288 | }, 289 | _ => { 290 | panic!(""); 291 | } 292 | }; 293 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PHDR as u64, elf_phdr + mem_start)); 294 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PHENT as u64, elf_phent as u64)); 295 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PHNUM as u64, elf_phnum as u64)); 296 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PAGESZ as u64, elf_pagesz as u64)); 297 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_BASE as u64, self.interp_address)); 298 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_FLAGS as u64, elf_flags)); 299 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_ENTRY as u64, elf_entry)); 300 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_UID as u64, elf_guid as u64)); 301 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_EUID as u64, elf_guid as u64)); 302 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_GID as u64, elf_guid as u64)); 303 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_EGID as u64, elf_guid as u64)); 304 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_HWCAP as u64, elf_hwcap as u64)); 305 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_CLKTCK as u64, 100)); 306 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_RANDOM as u64, randstraddr)); 307 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PLATFORM as u64, cpustraddr)); 308 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_SECURE as u64, 0)); 309 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_NULL as u64, 0)); 310 | 311 | 312 | let len = 0x10 - ((new_stack - elf_table.len() as u64) & 0xf) as usize; 313 | let padding = std::iter::repeat('0').take(len).collect::(); 314 | 315 | elf_table.extend_from_slice(padding.as_bytes()); 316 | 317 | let addr = new_stack - elf_table.len() as u64; 318 | self.write( addr, &elf_table); 319 | 320 | new_stack = new_stack - elf_table.len() as u64; 321 | 322 | self.new_stack = new_stack; 323 | self.load_address = load_address; 324 | } 325 | 326 | fn new_aux_ent(&self, key: u64, val: u64) -> Vec { 327 | let mut aux: Vec = Vec::new(); 328 | aux.extend_from_slice(&self.pack(key)); 329 | aux.extend_from_slice(&self.pack(val)); 330 | aux 331 | } 332 | 333 | pub fn run_linker(&mut self) { 334 | utilities::context_title(Some("Emulating linker64")); 335 | let res = self.emu_start(self.entry_point, self.elf_entry, 0, 0); 336 | self.handle_emu_exception(res); 337 | utilities::context_title(Some("Emulating linker64 done")); 338 | // self.display_mapped(); 339 | } 340 | } -------------------------------------------------------------------------------- /code/src/core/android/fs/fserrors.rs: -------------------------------------------------------------------------------- 1 | use core::{fmt, result}; 2 | 3 | #[derive(Eq, PartialEq)] 4 | pub struct Error { 5 | pub errno: i32, 6 | } 7 | 8 | pub type Result = result::Result; 9 | 10 | impl Error { 11 | pub fn new(errno: i32) -> Error { 12 | Error { errno: errno } 13 | } 14 | 15 | pub fn mux(result: Result) -> usize { 16 | match result { 17 | Ok(value) => value, 18 | Err(error) => -error.errno as usize, 19 | } 20 | } 21 | 22 | pub fn demux(value: usize) -> Result { 23 | let errno = -(value as i32); 24 | if errno >= 1 && errno < STR_ERROR.len() as i32 { 25 | Err(Error::new(errno)) 26 | } else { 27 | Ok(value) 28 | } 29 | } 30 | 31 | pub fn text(&self) -> &'static str { 32 | STR_ERROR.get(self.errno as usize).map(|&x| x).unwrap_or("Unknown Error") 33 | } 34 | } 35 | 36 | impl fmt::Debug for Error { 37 | fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { 38 | f.write_str(self.text()) 39 | } 40 | } 41 | 42 | impl fmt::Display for Error { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { 44 | f.write_str(self.text()) 45 | } 46 | } 47 | 48 | pub const EPERM: i32 = 1; /* Operation not permitted */ 49 | pub const ENOENT: i32 = 2; /* No such file or directory */ 50 | pub const ESRCH: i32 = 3; /* No such process */ 51 | pub const EINTR: i32 = 4; /* Interrupted system call */ 52 | pub const EIO: i32 = 5; /* I/O error */ 53 | pub const ENXIO: i32 = 6; /* No such device or address */ 54 | pub const E2BIG: i32 = 7; /* Argument list too long */ 55 | pub const ENOEXEC: i32 = 8; /* Exec format error */ 56 | pub const EBADF: i32 = 9; /* Bad file number */ 57 | pub const ECHILD: i32 = 10; /* No child processes */ 58 | pub const EAGAIN: i32 = 11; /* Try again */ 59 | pub const ENOMEM: i32 = 12; /* Out of memory */ 60 | pub const EACCES: i32 = 13; /* Permission denied */ 61 | pub const EFAULT: i32 = 14; /* Bad address */ 62 | pub const ENOTBLK: i32 = 15; /* Block device required */ 63 | pub const EBUSY: i32 = 16; /* Device or resource busy */ 64 | pub const EEXIST: i32 = 17; /* File exists */ 65 | pub const EXDEV: i32 = 18; /* Cross-device link */ 66 | pub const ENODEV: i32 = 19; /* No such device */ 67 | pub const ENOTDIR: i32 = 20; /* Not a directory */ 68 | pub const EISDIR: i32 = 21; /* Is a directory */ 69 | pub const EINVAL: i32 = 22; /* Invalid argument */ 70 | pub const ENFILE: i32 = 23; /* File table overflow */ 71 | pub const EMFILE: i32 = 24; /* Too many open files */ 72 | pub const ENOTTY: i32 = 25; /* Not a typewriter */ 73 | pub const ETXTBSY: i32 = 26; /* Text file busy */ 74 | pub const EFBIG: i32 = 27; /* File too large */ 75 | pub const ENOSPC: i32 = 28; /* No space left on device */ 76 | pub const ESPIPE: i32 = 29; /* Illegal seek */ 77 | pub const EROFS: i32 = 30; /* Read-only file system */ 78 | pub const EMLINK: i32 = 31; /* Too many links */ 79 | pub const EPIPE: i32 = 32; /* Broken pipe */ 80 | pub const EDOM: i32 = 33; /* Math argument out of domain of func */ 81 | pub const ERANGE: i32 = 34; /* Math result not representable */ 82 | pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ 83 | pub const ENAMETOOLONG: i32 = 36; /* File name too long */ 84 | pub const ENOLCK: i32 = 37; /* No record locks available */ 85 | pub const ENOSYS: i32 = 38; /* Function not implemented */ 86 | pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ 87 | pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ 88 | pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ 89 | pub const ENOMSG: i32 = 42; /* No message of desired type */ 90 | pub const EIDRM: i32 = 43; /* Identifier removed */ 91 | pub const ECHRNG: i32 = 44; /* Channel number out of range */ 92 | pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ 93 | pub const EL3HLT: i32 = 46; /* Level 3 halted */ 94 | pub const EL3RST: i32 = 47; /* Level 3 reset */ 95 | pub const ELNRNG: i32 = 48; /* Link number out of range */ 96 | pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ 97 | pub const ENOCSI: i32 = 50; /* No CSI structure available */ 98 | pub const EL2HLT: i32 = 51; /* Level 2 halted */ 99 | pub const EBADE: i32 = 52; /* Invalid exchange */ 100 | pub const EBADR: i32 = 53; /* Invalid request descriptor */ 101 | pub const EXFULL: i32 = 54; /* Exchange full */ 102 | pub const ENOANO: i32 = 55; /* No anode */ 103 | pub const EBADRQC: i32 = 56; /* Invalid request code */ 104 | pub const EBADSLT: i32 = 57; /* Invalid slot */ 105 | pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ 106 | pub const EBFONT: i32 = 59; /* Bad font file format */ 107 | pub const ENOSTR: i32 = 60; /* Device not a stream */ 108 | pub const ENODATA: i32 = 61; /* No data available */ 109 | pub const ETIME: i32 = 62; /* Timer expired */ 110 | pub const ENOSR: i32 = 63; /* Out of streams resources */ 111 | pub const ENONET: i32 = 64; /* Machine is not on the network */ 112 | pub const ENOPKG: i32 = 65; /* Package not installed */ 113 | pub const EREMOTE: i32 = 66; /* Object is remote */ 114 | pub const ENOLINK: i32 = 67; /* Link has been severed */ 115 | pub const EADV: i32 = 68; /* Advertise error */ 116 | pub const ESRMNT: i32 = 69; /* Srmount error */ 117 | pub const ECOMM: i32 = 70; /* Communication error on send */ 118 | pub const EPROTO: i32 = 71; /* Protocol error */ 119 | pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ 120 | pub const EDOTDOT: i32 = 73; /* RFS specific error */ 121 | pub const EBADMSG: i32 = 74; /* Not a data message */ 122 | pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ 123 | pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ 124 | pub const EBADFD: i32 = 77; /* File descriptor in bad state */ 125 | pub const EREMCHG: i32 = 78; /* Remote address changed */ 126 | pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ 127 | pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ 128 | pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ 129 | pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ 130 | pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ 131 | pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ 132 | pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ 133 | pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ 134 | pub const EUSERS: i32 = 87; /* Too many users */ 135 | pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ 136 | pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ 137 | pub const EMSGSIZE: i32 = 90; /* Message too long */ 138 | pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ 139 | pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ 140 | pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ 141 | pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ 142 | pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ 143 | pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ 144 | pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ 145 | pub const EADDRINUSE: i32 = 98; /* Address already in use */ 146 | pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ 147 | pub const ENETDOWN: i32 = 100; /* Network is down */ 148 | pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ 149 | pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ 150 | pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ 151 | pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ 152 | pub const ENOBUFS: i32 = 105; /* No buffer space available */ 153 | pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ 154 | pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ 155 | pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ 156 | pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ 157 | pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ 158 | pub const ECONNREFUSED: i32 = 111; /* Connection refused */ 159 | pub const EHOSTDOWN: i32 = 112; /* Host is down */ 160 | pub const EHOSTUNREACH: i32 = 113; /* No route to host */ 161 | pub const EALREADY: i32 = 114; /* Operation already in progress */ 162 | pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ 163 | pub const ESTALE: i32 = 116; /* Stale NFS file handle */ 164 | pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ 165 | pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ 166 | pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ 167 | pub const EISNAM: i32 = 120; /* Is a named type file */ 168 | pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ 169 | pub const EDQUOT: i32 = 122; /* Quota exceeded */ 170 | pub const ENOMEDIUM: i32 = 123; /* No medium found */ 171 | pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ 172 | pub const ECANCELED: i32 = 125; /* Operation Canceled */ 173 | pub const ENOKEY: i32 = 126; /* Required key not available */ 174 | pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ 175 | pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ 176 | pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ 177 | pub const EOWNERDEAD: i32 = 130; /* Owner died */ 178 | pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ 179 | 180 | pub static STR_ERROR: [&'static str; 132] = ["Success", 181 | "Operation not permitted", 182 | "No such file or directory", 183 | "No such process", 184 | "Interrupted system call", 185 | "I/O error", 186 | "No such device or address", 187 | "Argument list too long", 188 | "Exec format error", 189 | "Bad file number", 190 | "No child processes", 191 | "Try again", 192 | "Out of memory", 193 | "Permission denied", 194 | "Bad address", 195 | "Block device required", 196 | "Device or resource busy", 197 | "File exists", 198 | "Cross-device link", 199 | "No such device", 200 | "Not a directory", 201 | "Is a directory", 202 | "Invalid argument", 203 | "File table overflow", 204 | "Too many open files", 205 | "Not a typewriter", 206 | "Text file busy", 207 | "File too large", 208 | "No space left on device", 209 | "Illegal seek", 210 | "Read-only file system", 211 | "Too many links", 212 | "Broken pipe", 213 | "Math argument out of domain of func", 214 | "Math result not representable", 215 | "Resource deadlock would occur", 216 | "File name too long", 217 | "No record locks available", 218 | "Function not implemented", 219 | "Directory not empty", 220 | "Too many symbolic links encountered", 221 | "Operation would block", 222 | "No message of desired type", 223 | "Identifier removed", 224 | "Channel number out of range", 225 | "Level 2 not synchronized", 226 | "Level 3 halted", 227 | "Level 3 reset", 228 | "Link number out of range", 229 | "Protocol driver not attached", 230 | "No CSI structure available", 231 | "Level 2 halted", 232 | "Invalid exchange", 233 | "Invalid request descriptor", 234 | "Exchange full", 235 | "No anode", 236 | "Invalid request code", 237 | "Invalid slot", 238 | "Resource deadlock would occur", 239 | "Bad font file format", 240 | "Device not a stream", 241 | "No data available", 242 | "Timer expired", 243 | "Out of streams resources", 244 | "Machine is not on the network", 245 | "Package not installed", 246 | "Object is remote", 247 | "Link has been severed", 248 | "Advertise error", 249 | "Srmount error", 250 | "Communication error on send", 251 | "Protocol error", 252 | "Multihop attempted", 253 | "RFS specific error", 254 | "Not a data message", 255 | "Value too large for defined data type", 256 | "Name not unique on network", 257 | "File descriptor in bad state", 258 | "Remote address changed", 259 | "Can not access a needed shared library", 260 | "Accessing a corrupted shared library", 261 | ".lib section in a.out corrupted", 262 | "Attempting to link in too many shared libraries", 263 | "Cannot exec a shared library directly", 264 | "Illegal byte sequence", 265 | "Interrupted system call should be restarted", 266 | "Streams pipe error", 267 | "Too many users", 268 | "Socket operation on non-socket", 269 | "Destination address required", 270 | "Message too long", 271 | "Protocol wrong type for socket", 272 | "Protocol not available", 273 | "Protocol not supported", 274 | "Socket type not supported", 275 | "Operation not supported on transport endpoint", 276 | "Protocol family not supported", 277 | "Address family not supported by protocol", 278 | "Address already in use", 279 | "Cannot assign requested address", 280 | "Network is down", 281 | "Network is unreachable", 282 | "Network dropped connection because of reset", 283 | "Software caused connection abort", 284 | "Connection reset by peer", 285 | "No buffer space available", 286 | "Transport endpoint is already connected", 287 | "Transport endpoint is not connected", 288 | "Cannot send after transport endpoint shutdown", 289 | "Too many references: cannot splice", 290 | "Connection timed out", 291 | "Connection refused", 292 | "Host is down", 293 | "No route to host", 294 | "Operation already in progress", 295 | "Operation now in progress", 296 | "Stale NFS file handle", 297 | "Structure needs cleaning", 298 | "Not a XENIX named type file", 299 | "No XENIX semaphores available", 300 | "Is a named type file", 301 | "Remote I/O error", 302 | "Quota exceeded", 303 | "No medium found", 304 | "Wrong medium type", 305 | "Operation Canceled", 306 | "Required key not available", 307 | "Key has expired", 308 | "Key has been revoked", 309 | "Key was rejected by service", 310 | "Owner died", 311 | "State not recoverable"]; 312 | -------------------------------------------------------------------------------- /code/src/core/unicorn/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod arch; 2 | pub mod ffi; 3 | pub mod unicorn_const; 4 | 5 | use libc::c_void; 6 | use xmas_elf::header; 7 | 8 | use crate::utilities; 9 | use super::rudroid::Emulator; 10 | use arch::arm64; 11 | use unicorn_const::{Arch, uc_error, MemRegion, Protection, HookType, MemType, Query}; 12 | 13 | #[derive(Debug)] 14 | pub struct Context { 15 | context: ffi::uc_context, 16 | } 17 | 18 | impl Context { 19 | pub fn new() -> Self { 20 | Context { context: 0 } 21 | } 22 | pub fn is_initialized(&self) -> bool { 23 | self.context != 0 24 | } 25 | } 26 | 27 | impl Drop for Context { 28 | fn drop(&mut self) { 29 | unsafe { ffi::uc_free(self.context) }; 30 | } 31 | } 32 | 33 | impl Emulator { 34 | 35 | /// Return the architecture of the current emulator. 36 | pub fn get_arch(&self) -> Arch { 37 | self.arch 38 | } 39 | 40 | /// Returns a vector with the memory regions that are mapped in the emulator. 41 | pub fn mem_regions(&self) -> Result, uc_error> { 42 | let mut nb_regions: u32 = 0; 43 | let mut p_regions: *const MemRegion = std::ptr::null_mut(); 44 | let err = unsafe { ffi::uc_mem_regions(self.uc, &mut p_regions, &mut nb_regions) }; 45 | if err == uc_error::OK { 46 | let mut regions = Vec::new(); 47 | for i in 0..nb_regions { 48 | regions.push(unsafe { std::mem::transmute_copy(&*p_regions.offset(i as isize)) }); 49 | } 50 | unsafe { libc::free(p_regions as _) }; 51 | Ok(regions) 52 | } else { 53 | Err(err) 54 | } 55 | } 56 | 57 | /// Read a range of bytes from memory at the specified address. 58 | pub fn mem_read(&self, address: u64, buf: &mut [u8]) -> Result<(), uc_error> { 59 | let err = unsafe { ffi::uc_mem_read(self.uc, address, buf.as_mut_ptr(), buf.len()) }; 60 | if err == uc_error::OK { 61 | Ok(()) 62 | } else { 63 | Err(err) 64 | } 65 | } 66 | 67 | /// Return a range of bytes from memory at the specified address as vector. 68 | pub fn mem_read_as_vec(&self, address: u64, size: usize) -> Result, uc_error> { 69 | let mut buf = vec![0; size]; 70 | let err = unsafe { ffi::uc_mem_read(self.uc, address, buf.as_mut_ptr(), size) }; 71 | if err == uc_error::OK { 72 | Ok(buf) 73 | } else { 74 | Err(err) 75 | } 76 | } 77 | 78 | pub fn mem_write(&mut self, address: u64, bytes: &[u8]) -> Result<(), uc_error> { 79 | let err = unsafe { ffi::uc_mem_write(self.uc, address, bytes.as_ptr(), bytes.len()) }; 80 | if err == uc_error::OK { 81 | Ok(()) 82 | } else { 83 | Err(err) 84 | } 85 | } 86 | 87 | /// Map an existing memory region in the emulator at the specified address. 88 | /// 89 | /// This function is marked unsafe because it is the responsibility of the caller to 90 | /// ensure that `size` matches the size of the passed buffer, an invalid `size` value will 91 | /// likely cause a crash in unicorn. 92 | /// 93 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 94 | /// 95 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 96 | /// 97 | /// `ptr` is a pointer to the provided memory region that will be used by the emulator. 98 | pub fn mem_map_ptr(&mut self, 99 | address: u64, 100 | size: usize, 101 | perms: Protection, 102 | ptr: *mut c_void 103 | ) -> Result<(), uc_error> { 104 | let err = unsafe { ffi::uc_mem_map_ptr(self.uc, address, size, perms.bits(), ptr) }; 105 | if err == uc_error::OK { 106 | Ok(()) 107 | } else { 108 | Err(err) 109 | } 110 | } 111 | 112 | /// Map a memory region in the emulator at the specified address. 113 | /// 114 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 115 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 116 | pub fn mem_map(&mut self, 117 | address: u64, 118 | size: libc::size_t, 119 | perms: Protection 120 | ) -> Result<(), uc_error> { 121 | let err = unsafe { ffi::uc_mem_map(self.uc, address, size, perms.bits()) }; 122 | if err == uc_error::OK { 123 | Ok(()) 124 | } else { 125 | Err(err) 126 | } 127 | } 128 | 129 | /// Unmap a memory region. 130 | /// 131 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 132 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 133 | pub fn mem_unmap(&mut self, 134 | address: u64, 135 | size: libc::size_t 136 | ) -> Result<(), uc_error> { 137 | let err = unsafe { ffi::uc_mem_unmap(self.uc, address, size) }; 138 | if err == uc_error::OK { 139 | Ok(()) 140 | } else { 141 | Err(err) 142 | } 143 | } 144 | 145 | /// Set the memory permissions for an existing memory region. 146 | /// 147 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 148 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 149 | pub fn mem_protect(&mut self, 150 | address: u64, 151 | size: libc::size_t, 152 | perms: Protection 153 | ) -> Result<(), uc_error> { 154 | let err = unsafe { ffi::uc_mem_protect(self.uc, address, size, perms.bits()) }; 155 | if err == uc_error::OK { 156 | Ok(()) 157 | } else { 158 | Err(err) 159 | } 160 | } 161 | 162 | /// Write an unsigned value from a register. 163 | pub fn reg_write>(&mut self, regid: T, value: u64) -> Result<(), uc_error> { 164 | let err = unsafe { ffi::uc_reg_write(self.uc, regid.into(), &value as *const _ as _) }; 165 | if err == uc_error::OK { 166 | Ok(()) 167 | } else { 168 | Err(err) 169 | } 170 | } 171 | 172 | /// Write variable sized values into registers. 173 | /// 174 | /// The user has to make sure that the buffer length matches the register size. 175 | /// This adds support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM (x86); Q, V (arm64)). 176 | pub fn reg_write_long>(&self, regid: T, value: Box<[u8]>) -> Result<(), uc_error> { 177 | let err = unsafe { ffi::uc_reg_write(self.uc, regid.into(), value.as_ptr() as _) }; 178 | if err == uc_error::OK { 179 | Ok(()) 180 | } else { 181 | Err(err) 182 | } 183 | } 184 | 185 | /// Read an unsigned value from a register. 186 | /// 187 | /// Not to be used with registers larger than 64 bit. 188 | pub fn reg_read>(&self, regid: T) -> Result { 189 | let mut value: u64 = 0; 190 | let err = unsafe { ffi::uc_reg_read(self.uc, regid.into(), &mut value as *mut u64 as _) }; 191 | if err == uc_error::OK { 192 | Ok(value) 193 | } else { 194 | Err(err) 195 | } 196 | } 197 | 198 | /// Read 128, 256 or 512 bit register value into heap allocated byte array. 199 | /// 200 | /// This adds safe support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM (x86); Q, V (arm64)). 201 | pub fn reg_read_long>(&self, regid: T) -> Result, uc_error> { 202 | let err: uc_error; 203 | let boxed: Box<[u8]>; 204 | let mut value: Vec; 205 | let curr_reg_id = regid.into(); 206 | let curr_arch = self.get_arch(); 207 | 208 | // if curr_arch == Arch::X86 { 209 | // if curr_reg_id >= x86::RegisterX86::XMM0 as i32 && curr_reg_id <= x86::RegisterX86::XMM31 as i32 { 210 | // value = vec![0; 16 as usize]; 211 | // } else if curr_reg_id >= x86::RegisterX86::YMM0 as i32 && curr_reg_id <= x86::RegisterX86::YMM31 as i32 { 212 | // value = vec![0; 32 as usize]; 213 | // } else if curr_reg_id >= x86::RegisterX86::ZMM0 as i32 && curr_reg_id <= x86::RegisterX86::ZMM31 as i32 { 214 | // value = vec![0; 64 as usize]; 215 | // } else if curr_reg_id == x86::RegisterX86::GDTR as i32 || 216 | // curr_reg_id == x86::RegisterX86::IDTR as i32 { 217 | // value = vec![0; 10 as usize]; // 64 bit base address in IA-32e mode 218 | // } else { 219 | // return Err(uc_error::ARG) 220 | // } 221 | // } else 222 | if curr_arch == Arch::ARM64 { 223 | if (curr_reg_id >= arm64::RegisterARM64::Q0 as i32 && curr_reg_id <= arm64::RegisterARM64::Q31 as i32) || 224 | (curr_reg_id >= arm64::RegisterARM64::V0 as i32 && curr_reg_id <= arm64::RegisterARM64::V31 as i32) { 225 | value = vec![0; 16 as usize]; 226 | } else { 227 | return Err(uc_error::ARG) 228 | } 229 | } else { 230 | return Err(uc_error::ARCH) 231 | } 232 | 233 | err = unsafe { ffi::uc_reg_read(self.uc, curr_reg_id, value.as_mut_ptr() as _) }; 234 | 235 | if err == uc_error::OK { 236 | boxed = value.into_boxed_slice(); 237 | Ok(boxed) 238 | } else { 239 | Err(err) 240 | } 241 | } 242 | 243 | /// Read a signed 32-bit value from a register. 244 | pub fn reg_read_i32>(&self, regid: T) -> Result { 245 | let mut value: i32 = 0; 246 | let err = unsafe { ffi::uc_reg_read(self.uc, regid.into(), &mut value as *mut i32 as _) }; 247 | if err == uc_error::OK { 248 | Ok(value) 249 | } else { 250 | Err(err) 251 | } 252 | } 253 | 254 | /// Add a code hook. 255 | pub fn add_code_hook( 256 | &mut self, 257 | begin: u64, 258 | end: u64, 259 | callback: F, 260 | ) -> Result 261 | where F: FnMut(&mut Emulator, u64, u32) 262 | { 263 | let mut hook_ptr = std::ptr::null_mut(); 264 | let mut user_data = Box::new(ffi::CodeHook { 265 | unicorn: self, 266 | callback: Box::new(callback), 267 | }); 268 | 269 | let err = unsafe { 270 | ffi::uc_hook_add( 271 | self.uc, 272 | &mut hook_ptr, 273 | HookType::CODE, 274 | ffi::code_hook_proxy:: as _, 275 | user_data.as_mut() as *mut _ as _, 276 | begin, 277 | end, 278 | ) 279 | }; 280 | if err == uc_error::OK { 281 | unsafe { self }.code_hooks.insert(hook_ptr, user_data); 282 | Ok(hook_ptr) 283 | } else { 284 | Err(err) 285 | } 286 | } 287 | 288 | /// Add a memory hook. 289 | pub fn add_mem_hook( 290 | &mut self, 291 | hook_type: HookType, 292 | begin: u64, 293 | end: u64, 294 | callback: F, 295 | ) -> Result 296 | where F: FnMut(&mut Emulator, MemType, u64, usize, i64) 297 | { 298 | if (hook_type as i32) < 16 || hook_type == HookType::INSN_INVALID { 299 | return Err(uc_error::ARG); 300 | } 301 | 302 | let mut hook_ptr = std::ptr::null_mut(); 303 | let mut user_data = Box::new(ffi::MemHook { 304 | unicorn: self, 305 | callback: Box::new(callback), 306 | }); 307 | 308 | let err = unsafe { 309 | ffi::uc_hook_add( 310 | self.uc, 311 | &mut hook_ptr, 312 | hook_type, 313 | ffi::mem_hook_proxy:: as _, 314 | user_data.as_mut() as *mut _ as _, 315 | begin, 316 | end, 317 | ) 318 | }; 319 | if err == uc_error::OK { 320 | unsafe { self}.mem_hooks.insert(hook_ptr, user_data); 321 | Ok(hook_ptr) 322 | } else { 323 | Err(err) 324 | } 325 | } 326 | 327 | /// Add an interrupt hook. 328 | pub fn add_intr_hook( 329 | &mut self, 330 | callback: F, 331 | ) -> Result 332 | where F: FnMut(&mut Emulator, u32) 333 | { 334 | let mut hook_ptr = std::ptr::null_mut(); 335 | let mut user_data = Box::new(ffi::InterruptHook { 336 | unicorn: self, 337 | callback: Box::new(callback), 338 | }); 339 | 340 | let err = unsafe { 341 | ffi::uc_hook_add( 342 | self.uc, 343 | &mut hook_ptr, 344 | HookType::INTR, 345 | ffi::intr_hook_proxy:: as _, 346 | user_data.as_mut() as *mut _ as _, 347 | 0, 348 | 0, 349 | ) 350 | }; 351 | if err == uc_error::OK { 352 | unsafe { self }.intr_hooks.insert(hook_ptr, user_data); 353 | Ok(hook_ptr) 354 | } else { 355 | Err(err) 356 | } 357 | } 358 | 359 | /// Remove a hook. 360 | /// 361 | /// `hook` is the value returned by `add_*_hook` functions. 362 | pub fn remove_hook(&mut self, hook: ffi::uc_hook) -> Result<(), uc_error> { 363 | let handle = unsafe { self }; 364 | let err: uc_error; 365 | // if handle.code_hooks.contains_key(&hook) || 366 | // handle.mem_hooks.contains_key(&hook) || 367 | // handle.intr_hooks.contains_key(&hook) || 368 | // handle.insn_in_hooks.contains_key(&hook) || 369 | // handle.insn_out_hooks.contains_key(&hook) || 370 | // handle.insn_sys_hooks.contains_key(&hook) { 371 | err = unsafe { ffi::uc_hook_del(handle.uc, hook) }; 372 | // handle.mem_hooks.remove(&hook); 373 | // } else { 374 | // err = uc_error::HOOK; 375 | // } 376 | 377 | if err == uc_error::OK { 378 | Ok(()) 379 | } else { 380 | Err(err) 381 | } 382 | } 383 | 384 | /// Allocate and return an empty Unicorn context. 385 | /// 386 | /// To be populated via context_save. 387 | pub fn context_alloc(&self) -> Result { 388 | let mut empty_context: ffi::uc_context = Default::default(); 389 | let err = unsafe { ffi::uc_context_alloc(self.uc, &mut empty_context) }; 390 | if err == uc_error::OK { 391 | Ok(Context { context: empty_context }) 392 | } else { 393 | Err(err) 394 | } 395 | } 396 | 397 | /// Save current Unicorn context to previously allocated Context struct. 398 | pub fn context_save(&self, context: &mut Context) -> Result<(), uc_error> { 399 | let err = unsafe { ffi::uc_context_save(self.uc, context.context) }; 400 | if err == uc_error::OK { 401 | Ok(()) 402 | } else { 403 | Err(err) 404 | } 405 | } 406 | 407 | /// Allocate and return a Context struct initialized with the current CPU context. 408 | /// 409 | /// This can be used for fast rollbacks with context_restore. 410 | /// In case of many non-concurrent context saves, use context_alloc and *_save 411 | /// individually to avoid unnecessary allocations. 412 | pub fn context_init(&self) -> Result { 413 | let mut new_context: ffi::uc_context = Default::default(); 414 | let err = unsafe { ffi::uc_context_alloc(self.uc, &mut new_context) }; 415 | if err != uc_error::OK { 416 | return Err(err); 417 | } 418 | let err = unsafe { ffi::uc_context_save(self.uc, new_context) }; 419 | if err == uc_error::OK { 420 | Ok(Context { context: new_context }) 421 | } else { 422 | unsafe { ffi::uc_free(new_context) }; 423 | Err(err) 424 | } 425 | } 426 | 427 | /// Restore a previously saved Unicorn context. 428 | /// 429 | /// Perform a quick rollback of the CPU context, including registers and some 430 | /// internal metadata. Contexts may not be shared across engine instances with 431 | /// differing arches or modes. Memory has to be restored manually, if needed. 432 | pub fn context_restore(&self, context: &Context) -> Result<(), uc_error> { 433 | let err = unsafe { ffi::uc_context_restore(self.uc, context.context) }; 434 | if err == uc_error::OK { 435 | Ok(()) 436 | } else { 437 | Err(err) 438 | } 439 | } 440 | 441 | /// Emulate machine code for a specified duration. 442 | /// 443 | /// `begin` is the address where to start the emulation. The emulation stops if `until` 444 | /// is hit. `timeout` specifies a duration in microseconds after which the emulation is 445 | /// stopped (infinite execution if set to 0). `count` is the maximum number of instructions 446 | /// to emulate (emulate all the available instructions if set to 0). 447 | pub fn emu_start(&mut self, 448 | begin: u64, 449 | until: u64, 450 | timeout: u64, 451 | count: usize 452 | ) -> Result<(), uc_error> { 453 | let err = unsafe { ffi::uc_emu_start(self.uc, begin, until, timeout, count as _) }; 454 | if err == uc_error::OK { 455 | Ok(()) 456 | } else { 457 | Err(err) 458 | } 459 | } 460 | 461 | /// Stop the emulation. 462 | /// 463 | /// This is usually called from callback function in hooks. 464 | /// NOTE: For now, this will stop the execution only after the current block. 465 | pub fn emu_stop(&mut self) -> Result<(), uc_error> { 466 | let err = unsafe { ffi::uc_emu_stop(self.uc) }; 467 | if err == uc_error::OK { 468 | Ok(()) 469 | } else { 470 | Err(err) 471 | } 472 | } 473 | 474 | /// Query the internal status of the engine. 475 | /// 476 | /// supported: MODE, PAGE_SIZE, ARCH 477 | pub fn query(&self, query: Query) -> Result { 478 | let mut result: libc::size_t = Default::default(); 479 | let err = unsafe { ffi::uc_query(self.uc, query, &mut result) }; 480 | if err == uc_error::OK { 481 | Ok(result) 482 | } else { 483 | Err(err) 484 | } 485 | } 486 | 487 | pub fn debug_print(&self, message: String) { 488 | if self.debug { 489 | utilities::draw_line(); 490 | utilities::log(&message, utilities::DebugLevel::DEBUG); 491 | } 492 | } 493 | 494 | pub fn enable_vfp(&mut self) { 495 | let UC_ARM64_REG_CPACR_EL1 = 261; 496 | let cpacr_el1 = self.reg_read(UC_ARM64_REG_CPACR_EL1).unwrap(); 497 | self.reg_write(UC_ARM64_REG_CPACR_EL1, cpacr_el1|0x300000 as u64).unwrap(); 498 | } 499 | 500 | pub fn align_len(&self, len: u64) -> u64 { 501 | ((len+ 0x1000 - 1) / 0x1000) * 0x1000 502 | } 503 | 504 | pub fn uc_align_down(&self, address: u64) -> u64 { 505 | (address / 0x1000) * 0x1000 506 | } 507 | 508 | pub fn uc_align_up(&self, address: u64) -> u64 { 509 | let re = (address / 0x1000 + 1) * 0x1000; 510 | re 511 | } 512 | 513 | pub fn align_size(&self, value: u64, align: u64) -> u64 { 514 | ( (value -1) / align + 1 ) * align 515 | } 516 | 517 | pub fn null_mut(&self) -> *mut std::ffi::c_void { 518 | std::ptr::null_mut() 519 | } 520 | 521 | 522 | pub fn null_str(&self, input: &str) -> String { 523 | let res = input.trim_matches(char::from(0)); 524 | String::from(res) 525 | } 526 | 527 | pub fn alignment(&self, address: u64) -> u64 { 528 | match self.machine { 529 | header::Machine::AArch64 => { 530 | (address / 8) * 8 531 | }, 532 | _ => { 533 | panic!(""); 534 | } 535 | } 536 | } 537 | } 538 | 539 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Rudroid - Writing the World's worst Android Emulator in Rust 🦀 2 | 3 | ## Introduction 4 | Rudroid - this might arguably be one of the worst Android emulators possible. In this blog, we'll write an emulator that can run a 'Hello World' Android ELF binary. While doing this, we will learn how to go about writing our own emulators. 5 | 6 | Writing an emulator is an awesome way to study and probably master the low-level details of the system we are trying to emulate. I assume you have some working knowledge of Rust, a Linux machine with Rust installed or a Docker engine, and a lot of patience to go through the documentation of system calls, file formats, and more. 7 | 8 |   9 | 10 | Topics we need to understand while writing Rudroid: 11 | - Basic Android Operating System Architecture 12 | - What are system calls 13 | - How system calls are handled in AArch64 14 | - How memory mapping works 15 | - How the operating system loads an ELF into memory and runs it 16 | - How we can emulate the behavior of Operating system to load an ELF into memory and run 17 | 18 | Let's start by reading the definition of Android: 19 | 20 | > Android is an open-source, Linux-based software stack created for a wide array of devices and form factors. The following diagram shows the major components of the Android platform. 21 |   22 | 23 | ## Kernel Architecture 24 | The basic architecture of Linux kernel: 25 | 26 | Kernel Architecture 27 | 28 | Core functionalities of a kernel are: 29 | - Process management 30 | - Device management 31 | - Memory management 32 | - Interrupt handling 33 | - Block I/O communication 34 | - File System Management 35 | 36 | For writing an emulator that just runs an Android ELF binary, the most interesting kernel components are Memory Management, File System Management, Process Management and Interrupt handling, and System Call Interface via which ELF communicates with Kernel. 37 | 38 | 39 | Kernel Architecture 40 |   41 | 42 | > Signals: The kernel uses signals to call into a process. For example, signals are 43 | used to notify a process of certain faults, such as division by zero. 44 | 45 | > Processes and Scheduler: Creates, schedules, and manages processes. 46 | 47 | > Virtual Memory: Allocates and manages virtual memory for processes. 48 | 49 | > File Systems: Implements the file and filesystem-related interfaces for user-space to communicate with the underlying disks. 50 | 51 | > Traps and faults: Handles traps and faults generated by the processor, such as a memory fault. 52 | 53 | > Physical memory: Manages the pool of page frames in real memory and allocates pages for virtual memory. 54 | 55 | > Interrupts: Handles all the interrupts from peripheral devices. 56 | 57 | > System calls: The system call is the means by which a process requests a specific kernel service for example read from a file, write to file, execute a program. There are several hundred system calls, which can be roughly grouped into six categories:
58 | * file system
59 | * process
60 | * scheduling
61 | * interprocess communication (ipc)
62 | * socket (networking)
63 | * miscellaneous. 64 | 65 | 66 | ## How do Emulators do what they do? 67 | An emulator usually has an MMU to manage guest's memory requests, an instruction interpreter (decode -> translate -> execute), signal handlers, interrupt handlers. 68 | 69 | These are the steps an emulator usually does: 70 | * load the target binary to memory 71 | * figure out the ISA of target binary 72 | * if emulator supports the ISA, initialize CPU 73 | * initialize signal handlers 74 | * initialize interrupt handlers 75 | * initialize syscall handlers 76 | * start CPU loop 77 | 78 | What happens inside a CPU Loop: 79 | * fetch opcode to execute at Program Counter 80 | * increment Program Counter 81 | * decode opcode 82 | * translate opcode from emulated ISA to host ISA 83 | * execute the translated opcode 84 | * handle any raised signals/interrupts 85 | * continue the loop 86 | 87 | emulate cpu loop 88 | 89 | 90 | ## Rudroid's Architecture 91 | 92 | So, our Rudroid is just going to be a binary that implements an ELF loader, memory management, system call interface, filesystem. The final Rudroid's binary should take the ELF that prints 'Hello World' to stdout as command-line argument and execute it on the host. The command should look something like this: 93 | 94 | ```bash 95 | # ./Rudroid hello_world.elf 96 | hello world 97 | ``` 98 | 99 | We are going to run our Rudroid on a Linux machine. This is how our Rudroid's architecture is going to look like: 100 | 101 | Rudroid Architecture 102 | 103 | ## ELF loading process 104 | 105 | We'll try not to dwell too much into the details of the ELF file format. Take a look at this comprehensive ELF standard [here](https://refspecs.linuxfoundation.org/elf/elf.pdf). 106 | 107 | Executable (ELFs) and shared object files (libraries) statically represent programs. When you decide to run a binary, the operating system starts by setting up a new process for the program to run. 108 | 109 | ELFs are composed of three major components: 110 | - an executable header (`Ehdr`) 111 | - Sections (section header are represented as `Shdr`) 112 | - Segments (also known as Program Headers are represented as `Phdr`) 113 | 114 | `Ehdr` as defined in `/usr/include/elf.h` 115 | 116 | ```c 117 | typedef struct { 118 | unsigned char e_ident[16]; /* Magic number and other info */ 119 | uint16_t e_type; /* Object file type */ 120 | uint16_t e_machine; /* Architecture */ 121 | uint32_t e_version; /* Object file version */ 122 | uint64_t e_entry; /* Entry point virtual address */ 123 | uint64_t e_phoff; /* Program header table file offset */ 124 | uint64_t e_shoff; /* Section header table file offset */ 125 | uint32_t e_flags; /* Processor-specific flags */ 126 | uint16_t e_ehsize; /* ELF header size in bytes */ 127 | uint16_t e_phentsize; /* Program header table entry size */ 128 | uint16_t e_phnum; /* Program header table entry count */ 129 | uint16_t e_shentsize; /* Section header table entry size */ 130 | uint16_t e_shnum; /* Section header table entry count */ 131 | uint16_t e_shstrndx; /* Section header string table index*/ 132 | } Elf64_Ehdr; 133 | ``` 134 |   135 | 136 | `Phdr` as defined in `/usr/include/elf.h` 137 | ```c 138 | typedef struct elf64_phdr { 139 | Elf64_Word p_type; 140 | Elf64_Word p_flags; 141 | Elf64_Off p_offset; /* Segment file offset */ 142 | Elf64_Addr p_vaddr; /* Segment virtual address */ 143 | Elf64_Addr p_paddr; /* Segment physical address */ 144 | Elf64_Xword p_filesz; /* Segment size in file */ 145 | Elf64_Xword p_memsz; /* Segment size in memory */ 146 | Elf64_Xword p_align; /* Segment alignment, file & memory */ 147 | } Elf64_Phdr; 148 | ``` 149 |   150 | 151 | 152 | `Shdr` as defined in `/usr/include/elf.h` 153 | ```c 154 | typedef struct elf64_shdr { 155 | Elf64_Word sh_name; /* Section name, index in string tbl */ 156 | Elf64_Word sh_type; /* Type of section */ 157 | Elf64_Xword sh_flags; /* Miscellaneous section attributes */ 158 | Elf64_Addr sh_addr; /* Section virtual addr at execution */ 159 | Elf64_Off sh_offset; /* Section file offset */ 160 | Elf64_Xword sh_size; /* Size of section in bytes */ 161 | Elf64_Word sh_link; /* Index of another section */ 162 | Elf64_Word sh_info; /* Additional section information */ 163 | Elf64_Xword sh_addralign; /* Section alignment */ 164 | Elf64_Xword sh_entsize; /* Entry size if section holds table */ 165 | } Elf64_Shdr; 166 | ``` 167 | 168 | The kernel only really cares about Ehdr and Phdrs and only three types of program header entries: 169 | - PT_LOAD : Loadable Segment 170 | - PT_INTERP : Segment holding .interp section 171 | - PT_GNU_STACK : flag to set program's stack to executable 172 | 173 | The ELF loader in the kernel starts loading ELF by first examining the ELF header to check the validity of ELF. After this, the loader now loops over the program header entries, looking for PT_LOAD and PT_INTERP. For every PT_LOAD entry, the loader maps memory at `load_address + phdr_header.p_vaddr` of size `phdr_header.mem_size` and copies the contents of the segment into allocated memory. If PT_INTERP is found, the loader again parses this as an ELF file and maps it into memory, and keeps track of the entrypoints of the main ELF file and interpreter's ELF file. 174 | 175 | Once this is done, the loader starts setting up and populating the stack with `auxiliary vector` (ELF tables), environment variables, and command-line arguments passed to the ELF. An ELF auxiliary vector is an (id, value) pair that describes useful information about the program being run and the environment it is running in. 176 | 177 | For this, we need an ELF parser in rust. We can either write our own ELF parser or use an already existing [xmas-elf crate](https://github.com/nrc/xmas-elf). 178 | 179 | Before we could start writing an ELF loader, we also need a memory manager as we have to map the ELF into memory, manage stack, etc. Let's look at how a memory manager works. 180 | 181 | ## Memory Management (MMU) 182 | 183 | > Linux memory management subsystem is responsible, as the name implies, for managing the memory in the system. This includes implementation of virtual memory and demand paging, memory allocation both for kernel internal structures and userspace programs, mapping of files into processes address space, and many other cool things. 184 |   185 | 186 | It provides functionality to `map` and `unmap` memory allocations. We have to implement these functionalities: 187 | - map memory at a given location or of a given size 188 | - unmap memory at a given location or of a given size 189 | - read from memory 190 | - write to memory 191 | - manage permissions of the memory 192 |   193 | 194 | Mapping ranges from an address to address + size_of_the_mapping. We can look at `mmap` reference from the manual [here](https://man7.org/linux/man-pages/man2/mmap.2.html). 195 |   196 | ```c 197 | void *mmap(void *addr, size_t length, int prot, int flags, 198 | int fd, off_t offset); 199 | ```` 200 | 201 | ``` 202 | mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length of the mapping (which must be greater than 0). 203 | ``` 204 | 205 | Memory protections: 206 | 207 | ```c 208 | PROT_EXEC 209 | Pages may be executed. 210 | 211 | PROT_READ 212 | Pages may be read. 213 | 214 | PROT_WRITE 215 | Pages may be written. 216 | 217 | PROT_NONE 218 | Pages may not be accessed. 219 | ``` 220 | 221 | Unicorn Engine offers this functionality: 222 | 223 | ```rust 224 | /// Map a memory region in the emulator at the specified address. 225 | /// 226 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 227 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 228 | pub fn mem_map(&mut self, 229 | address: u64, 230 | size: libc::size_t, 231 | perms: Protection 232 | ) -> Result<(), uc_error>; 233 | 234 | 235 | /// Unmap a memory region. 236 | /// 237 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 238 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 239 | pub fn mem_unmap(&mut self, 240 | address: u64, 241 | size: libc::size_t 242 | ) -> Result<(), uc_error>; 243 | 244 | 245 | /// Set the memory permissions for an existing memory region. 246 | /// 247 | /// `address` must be aligned to 4kb or this will return `Error::ARG`. 248 | /// `size` must be a multiple of 4kb or this will return `Error::ARG`. 249 | pub fn mem_protect(&mut self, 250 | address: u64, 251 | size: libc::size_t, 252 | perms: Protection 253 | ) -> Result<(), uc_error> { 254 | let err = unsafe { ffi::uc_mem_protect(self.uc, address, size, perms.bits()) }; 255 | if err == uc_error::OK { 256 | Ok(()) 257 | } else { 258 | Err(err) 259 | } 260 | } 261 | ``` 262 | 263 |   264 | 265 | We can define protections and mapping as structs in rust: 266 | 267 | ```rust 268 | bitflags! { 269 | #[repr(C)] 270 | pub struct Protection : u32 { 271 | const NONE = 0; 272 | const READ = 1; 273 | const WRITE = 2; 274 | const EXEC = 4; 275 | const ALL = 7; 276 | } 277 | } 278 | 279 | pub struct MapInfo { 280 | pub memory_start : u64, 281 | pub memory_end : u64, 282 | pub memory_perms : Protection, 283 | pub description : String, 284 | } 285 | ``` 286 | 287 | Using these `mem_map`, `mem_unmap` functions from Unicorn, We can implement our MMU as a hashmap of starting address and MapInfo struct. 288 | 289 | We'll also look at how system calls work and then start writing our Emulator. 290 | 291 | ## System Calls 292 | 293 | > A system call is a routine that allows a user application to request actions that require special privileges or functionalities. Adding system calls is one of several ways to extend the functions provided by the kernel. 294 |   295 | 296 | In AArch64, there are special instructions for making such system calls. These instructions cause an exception, which allows controlled entry into a more privileged Exception level. 297 | 298 | - SVC - Supervisor call: 299 | Causes an exception targeting EL1. 300 | Used by an application to call the OS. 301 | - HVC - Hypervisor call: 302 | Causes an exception targeting EL2. 303 | Used by an OS to call the hypervisor, not available at EL0. 304 | - SMC - Secure monitor call: 305 | Causes an exception targeting EL3. 306 | Used by an OS or hypervisor to call the EL3 firmware, not available at EL0. 307 | 308 | AArch64 system call 309 |   310 | 311 | InAArch64, the system call number is passed in `X8` register and the return value in `X0` register. We will use Unicorn's hooks to hook onto these SVC calls and execute the corresponding system call and return the results. 312 | 313 | ## AArch64 Instruction Emulation 314 | 315 | Since writing emulating all the AArch64 instructions is a tedious job, we will make use of Unicorn Engine for emulating the instructions. We will still see how it works. 316 | 317 | ## impl rudroid 318 | 319 | Finally, we'll start writing the code for our Rudroid. Let's see how easy or complex it will be. 320 | 321 | I'm going to use a Linux Docker container on my Apple M1 as the host for running Rudroid. 322 | 323 | Rudroid's Dockerfile: 324 | 325 | #### **`Dockerfile`** 326 | ```dockerfile 327 | FROM rust:latest 328 | 329 | RUN apt update -y 330 | RUN apt install -y nano cmake 331 | 332 | WORKDIR /setup 333 | RUN git clone https://github.com/unicorn-engine/unicorn/ 334 | WORKDIR /setup/unicorn/ 335 | RUN ./make.sh 336 | RUN ./make.sh install 337 | 338 | WORKDIR /setup/ 339 | RUN git clone https://github.com/keystone-engine/keystone/ 340 | RUN mkdir build 341 | WORKDIR /setup/keystone/build 342 | RUN ../make-share.sh 343 | RUN make install 344 | 345 | RUN cp /usr/local/lib/libkeystone.so* /usr/lib/ 346 | 347 | RUN apt-get install -y clang llvm binutils-dev libunwind-dev 348 | WORKDIR /home/ 349 | ``` 350 | 351 | #### **`run.sh`** 352 | ```bash 353 | #!/bin/bash 354 | image=Rudroid 355 | docker build -t $image . 356 | docker run --rm -v `pwd`:/home -v `pwd`/resources/:/resources/ -it $image bash 357 | ``` 358 | 359 | ```bash 360 | $ chmod +x run.sh 361 | $ run.sh 362 | root@9346e6664ae9:/home/code# 363 | ``` 364 | 365 | Here we are installing the required rust, unicorn-engine, capstone-engine, and keystone-engine. 366 | 367 | We will extend `Unicorn` impl from [Unicorn Rust crate](https://github.com/unicorn-engine/unicorn/blob/next/bindings/rust/) and add system call handlers, file system management, etc. I took only the required files and discarded the remaining. 368 | 369 | ```c 370 | ➜ src git:(main) ✗ tree core/unicorn/ 371 | | |____ 372 | | | |____unicorn_const.rs 373 | | | |____ffi.rs 374 | | | |____mod.rs 375 | | | |____arch 376 | | | | |____arm64.rs 377 | | | | |____mod.rs 378 | ``` 379 | 380 | #### Directory structure 381 | Let's set up the below directory structure: 382 | 383 | Tree 384 | 385 |   386 | 387 | We are going to need `libc` crate to interact/forward our system calls to the host and `xmas-elf` crate for parsing ELF file. Add `libc = "0.2.101"` and `xmas-elf = "0.8.0"`to dependencies in Cargo.toml. Also added some helpers functions in `utilities.rs` to print in color.🎨 388 | 389 | #### **`Cargo.toml`** 390 | ```yaml 391 | [package] 392 | name = "Rudroid" 393 | version = "0.1.0" 394 | edition = "2018" 395 | 396 | [dependencies] 397 | libc = "0.2.101" 398 | bitflags = ">=1.1.0" 399 | xmas-elf = "0.8.0" 400 | byteorder = "1.4.3" 401 | keystone = "0.9.0" 402 | capstone="0.10.0" 403 | nix = "0.22.1" 404 | ``` 405 | 406 | So I deleted the Unicorn `new` implementation and `struct` definition and added a new struct definition inside `core/rudroid.rs`. Our new implementation declares a new struct called Emulator that keeps track of details of the Elf file, filesystem, and Unicorn hooks. 407 | 408 | ### **`core/rudroid.rs`** 409 | ```rust 410 | 411 | // #[derive(Debug)] 412 | pub struct Emulator { 413 | pub debug : bool, 414 | 415 | pub rootfs : String, 416 | pub elf_path : String, 417 | 418 | pub machine : header::Machine, 419 | pub endian : header::Data, 420 | pub arch : Arch, 421 | 422 | pub uc : ffi::uc_handle, 423 | pub uc_type : D, 424 | 425 | pub filesystem : fs::FsScheme, 426 | 427 | // mmu stuff 428 | pub load_address : u64, 429 | pub mmap_address : u64, 430 | pub new_stack : u64, 431 | pub interp_address : u64, 432 | pub entry_point : u64, 433 | pub elf_entry : u64, 434 | pub brk_address : u64, 435 | 436 | //elf arguments 437 | pub args : Vec, 438 | pub env : Vec, 439 | 440 | pub map_infos : HashMap, 441 | 442 | //hook 443 | pub code_hooks : HashMap<*mut libc::c_void, Box>>, 444 | pub mem_hooks : HashMap<*mut libc::c_void, Box>>, 445 | pub intr_hooks : HashMap<*mut libc::c_void, Box>>, 446 | pub insn_in_hooks : HashMap<*mut libc::c_void, Box>>, 447 | pub insn_out_hooks : HashMap<*mut libc::c_void, Box>>, 448 | pub insn_sys_hooks : HashMap<*mut libc::c_void, Box>>, 449 | 450 | // syscalls stuff 451 | pub sigmap : HashMap>, 452 | 453 | _pin : std::marker::PhantomPinned, 454 | } 455 | ``` 456 | 457 | Now we have to implement `Emulator`. 458 | 459 | ```rust 460 | impl Emulator 461 | { 462 | pub fn new(elf_path: &str, rootfs: &str, elf: &mut ElfFile, endian: header::Data, args: Vec, env: Vec, data: D, debug: bool) -> Result, uc_error> { 463 | 464 | let mut machine = elf.header.pt2.machine().as_machine(); 465 | 466 | let (arch, mode) = match machine { 467 | header::Machine::AArch64 => { 468 | (Arch::ARM64, Mode::LITTLE_ENDIAN) 469 | }, 470 | _ => { 471 | panic!("Not implemented yet!") 472 | } 473 | }; 474 | 475 | let mut handle = std::ptr::null_mut(); 476 | 477 | //uc_open: Create new instance of unicorn engine. 478 | let err = unsafe { ffi::uc_open(arch, mode, &mut handle) }; 479 | 480 | //create a new Emulator and return. 481 | let mut emu = Emulator { 482 | debug : debug, 483 | rootfs : String::from(rootfs), 484 | 485 | elf_path : String::from(elf_path), 486 | args : args, 487 | env : env, 488 | 489 | uc : handle, 490 | uc_type : data, 491 | 492 | arch : arch, 493 | machine : machine, 494 | endian : endian, 495 | 496 | map_infos : HashMap::new(), 497 | entry_point : 0, 498 | elf_entry : 0, 499 | brk_address : 0, 500 | mmap_address : 0, 501 | interp_address : 0, 502 | new_stack : 0, 503 | load_address : 0, 504 | 505 | //hooks 506 | code_hooks : HashMap::new(), 507 | mem_hooks : HashMap::new(), 508 | intr_hooks : HashMap::new(), 509 | insn_in_hooks : HashMap::new(), 510 | insn_out_hooks : HashMap::new(), 511 | insn_sys_hooks : HashMap::new(), 512 | 513 | _pin : std::marker::PhantomPinned, 514 | 515 | //create a File System object 516 | filesystem : fs::FsScheme::new(String::from(rootfs)), 517 | sigmap : HashMap::new(), 518 | }; 519 | 520 | //parse and load the ELF into memory 521 | emu.load(elf); 522 | 523 | // display the memory mapping 524 | emu.display_mapped(); 525 | 526 | if err == uc_error::OK { 527 | Ok(emu) 528 | } else { 529 | Err(err) 530 | } 531 | } 532 | } 533 | ``` 534 | 535 | Replaced all the implementations of `impl UnicornHandler` with `impl Emulator`. This way, we already have all the capabilities of `Unicorn` like memory management, hooks, instruction interpreter, CPU loop, etc. I think this is called Lazy programming? 🙊 536 | 537 | As explained in the ELF Loader section above, we parse the ELF using `xmas-elf` crate, go through the program headers, and map the respective segments into the memory. We also set up Stack for the program. 538 | 539 | ### **`core/loaders/elfLoader.rs`** 540 | ```rust 541 | impl Emulator 542 | { 543 | pub fn load(& mut self, elf: &mut ElfFile) 544 | { 545 | self.enable_vfp(); 546 | 547 | let profile = match self.machine { 548 | header::Machine::AArch64 => { 549 | (linux::OS64::stack_address, linux::OS64::stack_size) 550 | }, 551 | _ => { 552 | panic!("[load_with_ld] Not implemented yet!") 553 | } 554 | }; 555 | 556 | let mut stack_address = profile.0 as u64; 557 | let stack_size = profile.1 as usize; 558 | 559 | //initialise stack 560 | self.mmu_map(stack_address, stack_size, Protection::READ|Protection::WRITE, "[stack]", self.null_mut()); 561 | 562 | // load ELF and linker into memory 563 | self.load_with_ld(stack_address.checked_add(stack_size as u64).unwrap() , 0, self.machine, elf); 564 | 565 | stack_address = self.new_stack; 566 | self.reg_write(RegisterARM64::SP as i32, stack_address).unwrap(); 567 | } 568 | 569 | fn load_with_ld(&mut self, stack_address: u64, load_address: u64, archbit: header::Machine, elf: &mut ElfFile) { 570 | let mut load_address = match load_address { 571 | 0 => { 572 | match archbit { 573 | header::Machine::AArch64 => { 574 | self.mmap_address = linux::OS64::mmap_address as u64; 575 | linux::OS64::load_address as u64 576 | }, 577 | _ => { 578 | panic!("Shouldn't be here"); 579 | } 580 | } 581 | }, 582 | _ => { 583 | panic!("Shouldn't be here"); 584 | } 585 | }; 586 | 587 | let mut mem_start : u64 = 0xffff_ffff; 588 | let mut mem_end : u64 = 0xffff_ffff; 589 | let mut mem_s : u64 = 0; 590 | let mut mem_e : u64 = 0; 591 | 592 | let mut interp_path : String = String::new(); 593 | 594 | match elf.header.pt2.type_().as_type() { 595 | header::Type::Executable => { 596 | load_address = 0; 597 | }, 598 | header::Type::SharedObject => { 599 | 600 | } 601 | _ => { 602 | panic!("Some error in head e_type: {:?}", header::Type::SharedObject); 603 | } 604 | } 605 | 606 | for header in elf.program_iter() { 607 | match header.get_type().unwrap() { 608 | 609 | program::Type::Interp => { 610 | let offset = header.offset() as usize; 611 | let end_offset = (header.offset()+header.mem_size()) as usize; 612 | let data = elf.input.get(offset..end_offset).unwrap(); 613 | interp_path = self.null_str(std::str::from_utf8(data).unwrap()); 614 | }, 615 | 616 | program::Type::Load => { 617 | if mem_start > header.virtual_addr() || mem_start == 0xffff_ffff { 618 | mem_start = header.virtual_addr(); 619 | }; 620 | 621 | if mem_end < header.virtual_addr()+header.mem_size() || mem_end == 0xffff_ffff { 622 | mem_end = header.virtual_addr()+header.mem_size(); 623 | } 624 | }, 625 | _ => { 626 | 627 | } 628 | } 629 | } 630 | 631 | mem_start = self.uc_align_down(mem_start); 632 | mem_end = self.uc_align_up(mem_end); 633 | 634 | for header in elf.program_iter() { 635 | match header.get_type().unwrap() { 636 | program::Type::Load => { 637 | mem_s = self.uc_align_down(load_address + header.virtual_addr()); 638 | mem_e = self.uc_align_up(load_address + header.virtual_addr() + header.file_size()); 639 | let perms = utilities::to_uc_permissions(header.flags()); 640 | 641 | let desc = self.elf_path.clone(); 642 | self.mmu_map(mem_s, (mem_e-mem_s) as usize, perms, &desc, self.null_mut()); 643 | 644 | let data = elf.input.get(header.offset() as usize.. 645 | (header.offset()+header.file_size()) as usize).unwrap(); 646 | 647 | self.write(load_address+header.virtual_addr(), data); 648 | }, 649 | _ => { 650 | 651 | } 652 | } 653 | } 654 | 655 | let loaded_mem_end = load_address + mem_end; 656 | 657 | if loaded_mem_end > mem_e { 658 | let desc = self.elf_path.clone(); 659 | self.mmu_map( mem_e, (loaded_mem_end-mem_e) as usize, Protection::ALL, &desc, self.null_mut()); 660 | } 661 | 662 | self.elf_entry = elf.header.pt2.entry_point() + load_address; 663 | self.debug_print(format!("elf_entry {:x}", self.elf_entry)); 664 | 665 | self.brk_address = mem_end + load_address + 0x2000; //not sure why?? seems to be used in ql_syscall_brk 666 | 667 | // load interpreter if there is an interpreter 668 | if !interp_path.is_empty() { 669 | self.debug_print(format!("Trying to load interpreter: {}{}", self.rootfs, interp_path)); 670 | 671 | let mut interp_full_path = String::new(); 672 | 673 | interp_full_path.push_str(&self.rootfs); 674 | interp_full_path.push_str(&interp_path); 675 | 676 | let interp_data = std::fs::read(&interp_full_path).unwrap(); 677 | let interp_elf = ElfFile::new(interp_data.get(0..).unwrap()).unwrap(); 678 | 679 | let mut interp_mem_size: u64 = 0; 680 | let mut interp_address : u64 = 0; 681 | 682 | for i_header in interp_elf.program_iter() { 683 | match i_header.get_type().unwrap() { 684 | program::Type::Load => { 685 | if interp_mem_size < i_header.virtual_addr() + i_header.mem_size() || interp_mem_size == 0 { 686 | interp_mem_size = i_header.virtual_addr() + i_header.mem_size(); 687 | } 688 | }, 689 | _ => { 690 | 691 | } 692 | }; 693 | } 694 | 695 | interp_mem_size = self.uc_align_up(interp_mem_size); 696 | 697 | match archbit { 698 | header::Machine::AArch64 => { 699 | interp_address = linux::OS64::interp_address as u64; 700 | } 701 | _ => { 702 | panic!("what?"); 703 | } 704 | }; 705 | 706 | //map interpreter into memory 707 | self.mmu_map(interp_address, interp_mem_size as usize , Protection::ALL, &interp_path, self.null_mut()); 708 | 709 | for i_header in interp_elf.program_iter() { 710 | match i_header.get_type().unwrap() { 711 | program::Type::Load => { 712 | let data = interp_elf.input.get(i_header.offset() as usize.. 713 | (i_header.offset()+i_header.file_size()) as usize 714 | ).unwrap(); 715 | self.write( interp_address+i_header.physical_addr(), data); 716 | }, 717 | _ => { 718 | 719 | } 720 | }; 721 | } 722 | 723 | self.interp_address = interp_address; 724 | self.entry_point = interp_elf.header.pt2.entry_point() + self.interp_address; 725 | } 726 | 727 | // setup elf table 728 | let mut elf_table: Vec = Vec::new(); 729 | 730 | let mut new_stack = stack_address; 731 | 732 | // copy arg0 on to stack. elf_path 733 | new_stack = self.copy_str(new_stack, &mut self.elf_path.clone()); 734 | 735 | elf_table.extend_from_slice(&self.pack(self.args.len() as u64 + 1)); // + 1 is for arg0 = elf path. 736 | elf_table.extend_from_slice(&self.pack(new_stack)); 737 | 738 | let mut argc = self.args.len(); 739 | 740 | loop { 741 | if argc <=0 { 742 | break; 743 | } 744 | argc -= 1; 745 | 746 | let mut arg = self.args[argc].clone(); 747 | new_stack = self.copy_str(new_stack, &mut arg); 748 | elf_table.extend_from_slice(&self.pack(new_stack)); 749 | } 750 | 751 | elf_table.extend_from_slice(&self.pack(0)); 752 | 753 | let mut envc = self.env.len(); 754 | 755 | loop { 756 | if envc <=0 { 757 | break; 758 | } 759 | envc -= 1; 760 | let mut env = self.env[envc].clone(); 761 | new_stack = self.copy_str(new_stack, &mut env); 762 | elf_table.extend_from_slice(&self.pack(new_stack)); 763 | } 764 | 765 | elf_table.extend_from_slice(&self.pack(0)); 766 | 767 | new_stack = self.alignment(new_stack); 768 | 769 | //our super secure random string 770 | let mut randstr = "a".repeat(0x10); 771 | let mut cpustr = String::from("aarch64"); 772 | 773 | let mut addr1 = self.copy_str(new_stack, &mut randstr); 774 | new_stack = addr1; 775 | 776 | let mut addr2 = self.copy_str(new_stack, &mut cpustr); 777 | new_stack = addr2; 778 | 779 | new_stack = self.alignment(new_stack); 780 | 781 | // Set AUX 782 | let head = elf.header; 783 | 784 | let elf_phdr = load_address + head.pt2.ph_offset(); 785 | let elf_phent = head.pt2.ph_entry_size(); 786 | let elf_phnum = head.pt2.ph_count(); 787 | let elf_pagesz = 0x1000; 788 | let elf_guid = linux::uid; 789 | let elf_flags = 0; 790 | let elf_entry = load_address + head.pt2.entry_point(); 791 | let randstraddr = addr1; 792 | let cpustraddr = addr2; 793 | 794 | let elf_hwcap: u64 = match head.pt2.machine().as_machine() { 795 | header::Machine::AArch64 => { 796 | 0x078bfbfd 797 | }, 798 | _ => { 799 | panic!(""); 800 | } 801 | }; 802 | 803 | //setup auxiliary vectors 804 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PHDR as u64, elf_phdr + mem_start)); 805 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PHENT as u64, elf_phent as u64)); 806 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PHNUM as u64, elf_phnum as u64)); 807 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PAGESZ as u64, elf_pagesz as u64)); 808 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_BASE as u64, self.interp_address)); 809 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_FLAGS as u64, elf_flags)); 810 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_ENTRY as u64, elf_entry)); 811 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_UID as u64, elf_guid as u64)); 812 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_EUID as u64, elf_guid as u64)); 813 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_GID as u64, elf_guid as u64)); 814 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_EGID as u64, elf_guid as u64)); 815 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_HWCAP as u64, elf_hwcap as u64)); 816 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_CLKTCK as u64, 100)); 817 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_RANDOM as u64, randstraddr)); 818 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_PLATFORM as u64, cpustraddr)); 819 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_SECURE as u64, 0)); 820 | elf_table.extend_from_slice(&self.new_aux_ent(AUX::AT_NULL as u64, 0)); 821 | 822 | 823 | let len = 0x10 - ((new_stack - elf_table.len() as u64) & 0xf) as usize; 824 | let padding = std::iter::repeat('0').take(len).collect::(); 825 | 826 | elf_table.extend_from_slice(padding.as_bytes()); 827 | 828 | let addr = new_stack - elf_table.len() as u64; 829 | self.write( addr, &elf_table); 830 | 831 | new_stack = new_stack - elf_table.len() as u64; 832 | 833 | self.new_stack = new_stack; 834 | self.load_address = load_address; 835 | } 836 | 837 | fn new_aux_ent(&self, key: u64, val: u64) -> Vec 838 | { 839 | //pack the aux key-val pair 840 | let mut aux: Vec = Vec::new(); 841 | aux.extend_from_slice(&self.pack(key)); 842 | aux.extend_from_slice(&self.pack(val)); 843 | aux 844 | } 845 | 846 | // Run linker 847 | pub fn run_linker(&mut self) 848 | { 849 | utilities::context_title(Some("Emulating linker64")); 850 | let res = self.emu_start(self.entry_point, self.elf_entry, 0, 0); 851 | self.handle_emu_exception(res); 852 | utilities::context_title(Some("Emulating linker64 done")); 853 | } 854 | } 855 | ``` 856 | 857 | We add three hooks in `core/hook.rs` 858 | 859 | ```rust 860 | pub fn add_hooks(emu: &mut rudroid::Emulator) { 861 | //handle SVC 862 | emu.add_intr_hook(android::syscalls::hook_syscall).unwrap(); 863 | 864 | //handle MEM_FETCH_UNMAPPED 865 | emu.add_mem_hook(unicorn_const::HookType::MEM_FETCH_UNMAPPED, 1, 0, callback_mem_error).unwrap(); 866 | 867 | //handle MEM_READ_UNMAPPED 868 | emu.add_mem_hook(unicorn_const::HookType::MEM_READ_UNMAPPED, 1, 0, callback_mem_error).unwrap(); 869 | ``` 870 | 871 | And in `hook_syscall` function, we read the `x8` register from the execution context, match it with syscalls of Android, and try to emulate the syscall. Instead of implementing every syscall in our code, we can just forward some of them to the host system, get the return values and forward them to the emulated binary. 872 | 873 | ### **`core/android/syscalls/mod.rs`** 874 | ```rust 875 | mod syscalls; 876 | mod unistd; 877 | 878 | use crate::{core::{rudroid::Emulator, unicorn::arch::arm64::RegisterARM64}, utilities}; 879 | 880 | pub fn get_syscall(uc: &mut Emulator) -> syscalls::Syscalls { 881 | // syscall_num = UC_ARM64_REG_X8 882 | let syscall = uc.reg_read(RegisterARM64::X8 as i32).unwrap(); 883 | unsafe { ::std::mem::transmute(syscall) } 884 | } 885 | 886 | pub fn hook_syscall(uc: &mut Emulator, intno: u32) { 887 | let pc = uc.reg_read(RegisterARM64::PC as i32).unwrap(); 888 | let syscall = get_syscall(uc); 889 | uc.syscall(syscall); 890 | } 891 | 892 | impl Emulator { 893 | pub fn syscall(&mut self, syscall: syscalls::Syscalls) { 894 | if self.debug { 895 | utilities::draw_line(); 896 | self.debug_print(format!("got syscall: {:?}", syscall)); 897 | } 898 | 899 | match syscall { 900 | 901 | syscalls::Syscalls::__NR_getpid => 902 | { 903 | self.sys_getpid(); 904 | } 905 | 906 | _ => { 907 | panic!("Syscall {:?} not implemented yet!", syscall); 908 | } 909 | }; 910 | } 911 | 912 | pub fn empty_syscall_return(&mut self) { 913 | self.reg_write(RegisterARM64::X0 as i32, 0).unwrap(); 914 | } 915 | 916 | pub fn get_arg(&mut self, num: i32) -> u64 { 917 | // 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7' 918 | match num { 919 | 0 => { 920 | self.reg_read(RegisterARM64::X0 as i32).unwrap() 921 | }, 922 | 1 => { 923 | self.reg_read(RegisterARM64::X1 as i32).unwrap() 924 | }, 925 | 2 => { 926 | self.reg_read(RegisterARM64::X2 as i32).unwrap() 927 | }, 928 | 3 => { 929 | self.reg_read(RegisterARM64::X3 as i32).unwrap() 930 | }, 931 | 4 => { 932 | self.reg_read(RegisterARM64::X4 as i32).unwrap() 933 | }, 934 | 5 => { 935 | self.reg_read(RegisterARM64::X5 as i32).unwrap() 936 | }, 937 | 6 => { 938 | self.reg_read(RegisterARM64::X6 as i32).unwrap() 939 | }, 940 | 7 => { 941 | self.reg_read(RegisterARM64::X7 as i32).unwrap() 942 | }, 943 | _ => { 944 | panic!("i do not support any more arguments :/"); 945 | } 946 | } 947 | } 948 | 949 | pub fn set_return_val(&mut self, value: u64) { 950 | self.reg_write(RegisterARM64::X0 as i32, value).unwrap(); 951 | } 952 | } 953 | ``` 954 | And in `main.rs` file, we parse the command line arguments to Rudroid, take target 'Hello World' ELF and `rootfs` (/system/ directory copied from an android device) folder as 2 arguments, create an Emulator, load the ELF into memory and start the CPU loop. 955 | 956 | ### **`main.rs`** 957 | ```rust 958 | extern crate byteorder; 959 | extern crate capstone; 960 | extern crate keystone; 961 | extern crate nix; 962 | extern crate xmas_elf; 963 | 964 | mod utilities; 965 | mod core; 966 | 967 | use std::env; 968 | use xmas_elf::ElfFile; 969 | 970 | use crate::utilities::context_title; 971 | 972 | fn parse_args() -> env::Args { 973 | //! Parse Command line arguments 974 | let mut args = env::args(); 975 | 976 | if args.len() != 3 { 977 | panic!("Please provide an ELF library and rootfs folder"); 978 | } 979 | args 980 | } 981 | 982 | fn main() 983 | { 984 | utilities::context_title(Some("Hello, world!")); 985 | let mut args = parse_args(); 986 | let mut elf_filename = args.nth(1).unwrap(); 987 | let rootfs = args.next().unwrap(); 988 | 989 | let mut elf_data = std::fs::read(&mut elf_filename).unwrap(); 990 | let mut elf: ElfFile = ElfFile::new(&mut elf_data).unwrap(); 991 | 992 | //our hello world program takes no arguments or environment variables 993 | let program_args: Vec = vec![]; 994 | let program_env: Vec = Vec::new(); 995 | 996 | let endian = elf.header.pt1.data(); 997 | let mut emu = core::rudroid::Emulator::new( &elf_filename, &rootfs, &mut elf, endian, program_args, program_env, 0, true).expect("Emulator initialisation failed"); 998 | 999 | //set up hooks 1000 | core::hooks::add_hooks(&mut emu); 1001 | 1002 | //run linker to load dependencies of ELF and then run the main from ELF 1003 | emu.run_linker(); 1004 | emu.run_elf(); 1005 | 1006 | context_title(Some("Emulator creted")) 1007 | } 1008 | ``` 1009 |   1010 | We are already ready to execute the ELF binary, except that when any syscall is called by the binary we panic with `panic!("Syscall {:?} not implemented yet!", syscall);` 1011 | 1012 | The best part here is, we can just do it on the fly i.e., implement the requested `syscall` that was requested in the above panic. 1013 | 1014 | Lets' compile and link it with Unicorn/Keystone/capstone. 1015 | 1016 | ```Makefile 1017 | build: 1018 | RUSTFLAGS="-L /usr/lib/ -lunicorn -L /usr/local/lib/ -lkeystone -Awarnings" cargo run -- /setup/hello /setup/rootfs/ 1019 | ``` 1020 |   1021 | 1022 | Now compile and execute with `make`: 1023 | 1024 | Compile and execute with make 1025 | 1026 | You can notice in the screenshot above that Emulator panicked with `'Syscall __NR_getpid not implemented yet!'`. So, let's implement __NR_getpid syscall. If you check the documents of getpid (`__NR_getpid`) documented here `https://man7.org/linux/man-pages/man2/getpid.2.html`, just returns the PID of the executing process. Since here we are executing the binary in our own emulator, we can return whatever number as PID in the response. Let's return 1337 as PID. 1027 | 1028 | So we create a file `unistd.rs` inside `syscalls` folder and implement __NR_getpid syscall. 1029 | 1030 | ### **`core/android/syscalls/unistd.rs`** 1031 | ```rust 1032 | use std::process; 1033 | use crate::core::rudroid::Emulator; 1034 | 1035 | impl Emulator { 1036 | pub fn sys_getpid(&mut self) { 1037 | let pid = 1337; 1038 | self.set_return_val(pid as u64); 1039 | } 1040 | } 1041 | ``` 1042 | 1043 |   1044 | 1045 | And now we run `make` again to execute. 1046 | 1047 | Compile and execute with make 1048 | 1049 | As you can see, it executed `[DEBUG]: got syscall: __NR_getpid` and now panicked with `'Syscall __NR3264_mmap not implemented yet!'`. If you are not sure what this syscall does, just search in [bootlin](https://elixir.bootlin.com/linux/latest). For this __NR3264_mmap, it is defined in https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/unistd.h#L645 1050 | 1051 | `__SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)` 1052 | 1053 | This implements [mmap](https://man7.org/linux/man-pages/man2/mmap.2.html). So, we go ahead and implement this as well. 1054 | 1055 | ```rust 1056 | impl Emulator { 1057 | pub fn sys_mmap(&mut self) { 1058 | let addr = self.get_arg(0); 1059 | let len = self.get_arg(1); 1060 | let prot = self.get_arg(2); 1061 | let flags = self.get_arg(3); 1062 | let fd : i32 = self.get_arg(4) as i32; 1063 | let off = self.get_arg(5) ; 1064 | 1065 | let aligned_len = self.align_len(len); 1066 | 1067 | let mut mmap_base = addr; 1068 | let mut need_map : bool = true; 1069 | 1070 | if addr == 0 { 1071 | mmap_base = self.mmap_address; 1072 | self.mmap_address = mmap_base + aligned_len; 1073 | } 1074 | 1075 | else { 1076 | need_map = false; 1077 | } 1078 | 1079 | let is_fixed = (flags & MAP_FIXED) != 0; 1080 | if self.debug { 1081 | self.debug_print(format!("mmap_base 0x{:x} length 0x{:x} fixed: {} = ({:x}, {:x})", addr, len, is_fixed, mmap_base, aligned_len as usize)); 1082 | } 1083 | 1084 | if need_map { 1085 | self.mmu_map(mmap_base, aligned_len as usize, Protection::ALL, "[syscall_mmap]", self.null_mut()); 1086 | } 1087 | 1088 | if (( flags & MAP_ANONYMOUS) == 0 ) && fd < MAX_FDS && fd > 0 { 1089 | let mut data = vec![0u8; len as usize]; 1090 | self.filesystem.pread(fd, &mut data, off).unwrap(); 1091 | 1092 | let mem_info: &str = &self.filesystem.get_path(fd).unwrap(); 1093 | 1094 | let map_info = MapInfo { 1095 | memory_start : mmap_base, 1096 | memory_end : mmap_base+((len+0x1000-1)/0x1000) * 0x1000, 1097 | memory_perms : Protection::ALL, 1098 | description : String::from(mem_info), 1099 | }; 1100 | 1101 | self.add_mapinfo(map_info); 1102 | self.write(mmap_base, &data); 1103 | } 1104 | 1105 | self.set_return_val(mmap_base); 1106 | } 1107 | } 1108 | ``` 1109 | 1110 |   1111 | 1112 | And we `make` again. 1113 | 1114 | Compile and execute with make 1115 | 1116 | Do you see where I am going? Just keep doing this for few more syscalls till I saw the output 'Hello World' 💃🕺💃🕺 1117 | 1118 | Hello World from the binary 1119 | 1120 | Uffff. That's a long post. Hope it's useful to someone. Please [DM](https://twitter.com/ant4g0nist) me if I made any boo-boo. 1121 | 1122 |   1123 | 1124 | 1125 | ## Resources 1126 | - [gamozolabs](https://www.youtube.com/user/gamozolabs) 1127 | - [javidx9](https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA) 1128 | - [ferrisstreamsstuff](https://www.youtube.com/c/ferrisstreamsstuff) 1129 | - https://developer.arm.com/documentation/102374/0101/System-calls 1130 | --------------------------------------------------------------------------------