How to manually root a phone? I want to learn how to root a android phone manually, I mean without any apps like KingRoot, dr.fone etc.
I did not found any guides or information about it.

(Background Information: I want to root a BlackBerry KeyOne, even if you say it does not work i want to learn and try it anyway)

Can you please help me?
I was looking at the web search results of “how to manually root Android devices” and I noticed that most of those are either just advertising stuff or makes use of dedicated (particularly closed source) rooting solutions. Those which worked some time ago are now obsolete since they depended on some security vulnerability in Android which was fixed over time.

In fact it's not impossible to root phone manually but it's not worth the hassle. However as a reference, let me describe an option. But before diving into the technical details, we need to understand what root is and how Android prevents root access. Details can be found here but a few points in short:


Mostly vendors ship their devices with locked bootloader, and a chain of trust is established during boot process, which won't let any modification be done to kernel (boot.img), recovery or the main OS. So the first step towards rooting is unlocked bootloader. Beware of the risks!
A part of the chain of trust is dm-verity (VB/AVB); a kernel based phenomenon which makes sure that partitions containing core OS (/system, /vendor, /odm) are always mounted read-only and any malicious attempt to modify them must fail. Modifying boot.img or recovery.img is usually accompanied by disabling dm-verity to avoid surprises like bootloops at later stages. TWRP's standard warning:


  This device uses dm-verity!
  This means that swiping to allow system modifications will prevent you from being able to boot if you are using the stock kernel.

Similarly some vendors particularly Samsung go beyond normal and build extra security features in their devices like Knox, RKP, Defex, proca, TIMA, FIPS, bla bla bla. So you might also need to circumvent those e.g. by building kernel with SECURITY_SELINUX_DEVELOP=y, patching kernel binary etc.
Android apps don't have capabilities to elevate their privileges by executing binaries which have setuid or file capabilities set (which is the standard way to get root access). So the only option is to run a background persistent process (daemon) with root privileges outside the apps (e.g. during boot process) and request it to do privileged tasks on behalf of unprivileged apps when needed.
Root (i.e. UID 0) is the old Discretionary Access Control (DAC), but Android also makes use of Mandatory Access Control (MAC) i.e. SELinux. A root process running with restricted SELinux context is quite helpless, so we have to break this barrier too. It requires modifying SELinux policy.


I'll address the last two points here, but first two considerations:


Android rooting solutions deploy a special su binary which - when executed by an app - makes a connection to privileged daemon and gets the app a root shell. So this su binary and daemon are specially developed for this purpose. A less sophisticated approach would be to run already available daemons like adbd, sshd or one of the old inetutils flavors (telnetd, rlogind, rshd, rexecd) with root privileges. When running in background, these servers can provide a root shell or execute commands with root privileges when connected by a client. For the sake of simplicity I'm using only a minimal network utility named netcat (nc) which is a busybox applet. But please note that apps can't get root access with this approach, it can only be used from commandline.
We are going to patch monolithic /sepolicy file and /init.rc file which are part of ramdisk in boot.img. But starting with Treble Android uses split policy which is loaded/compiled from /system/etc/selinux/ and /vendor/etc/selinux/. Starting with SAR, there's no ramdisk at all in boot.img and /init.rc is part of system.img. So in both cases you need to necessarily modify system partition. I'm not giving details on that here.


STEPS:


Extract boot.img e.g. using AIK or magiskboot on Android or PC.
Create a new SELinux context, say pseudo_su. Set it permissive so that to allow any possible interactions with other processes / files etc. Use Magisk's supolicy tool or sepolicy-inject (1, 2) on Android or PC:

~# supolicy --load sepolicy --save sepolicy 'create pseudo_su' 'permissive pseudo_su' 'dontaudit pseudo_su * * *' 'allow pseudo_su * * *' 'allow * pseudo_su * *'


Or to build split-policy using Android's compiler:

~# /system/bin/secilc -m -M true -G -N -c $(cat /sys/fs/selinux/policyvers) -o sepolicy /system/etc/selinux/plat_sepolicy.cil /system/etc/selinux/mapping/$(cat /vendor/etc/selinux/plat_sepolicy_vers.txt).cil $([ -f /vendor/etc/selinux/vendor_sepolicy.cil ] &amp;&amp; echo /vendor/etc/selinux/vendor_sepolicy.cil /vendor/etc/selinux/plat_pub_versioned.cil || echo /vendor/etc/selinux/nonplat_sepolicy.cil)


* Get the value of POLICYDB_VERSION_MAX from your kernel source.

To use vendor's precompiled_sepolicy or build from split-policy and patch:

~# supolicy --load-split --save sepolicy 'create pseudo_su' 'permissive pseudo_su' 'dontaudit pseudo_su * * *' 'allow pseudo_su * * *' 'allow * pseudo_su * *'

Define an init service which starts a simple TCP server on boot, only listening to on-device connections:

# /init.rc
...
service pseudo_su /sbin/busybox nc -lk -s 127.0.0.1 -p 23 -e /sbin/busybox sh
    seclabel u:r:pseudo_su:s0
    disabled

on property:sys.boot_completed=1
    start pseudo_su


* Make sure you get the right busybox binary, there are multiple implementations of netcat.
* Use port 23 or any other unused port.
Copy updated sepolicy and init.rc to root of extracted ramdisk, busybox binary to [ramdisk/]sbin/ and set permissions.
Repack boot.img and flash or test with fastboot boot boot.img.


HOW TO RUN ROOT COMMANDS?

Once booted, we can pass commands from a netcat client on terminal emulator app (like Termux) or adb shell:

~$ echo id | /sbin/busybox nc localhost 23
uid=0(root) gid=0(root) groups=0(root) context=u:r:pseudo_su:s0


* Default SELinux policy doesn't allow apps traverse /sbin. So either inject allow rules or put busybox in /system/*bin/. Or use some other nc e.g. from Termux's netcat package.

For ease of use, create functions (put them in .bashrc so that you don't have to define every time):

# ~/.bashrc
...
function psu() { echo "$@ 2&gt;&amp;1" | /sbin/busybox nc localhost 23; }
function psush() { /sbin/busybox nc localhost 23; }


~$ ls -ld /data/adb
ls: cannot access '/data/adb': Permission denied
~$ psu ls -ld /data/adb
drwx------ 7 root root 3488 2019-07-19 00:44 /data/adb


To get root shell:

~$ psush
whoami
root
^C


But it's just a dumb shell, not connected to terminal. To have a more feature-rich experience, other tools like socat can be used which support line editing, pseudo-terminals etc.
Also environment variables aren't evaluated unless explicitly passed, because commands are executed remotely:

~$ /data/data/com.termux/files/usr/bin/ps -p $$,1 -o pid=,comm=
23599 bash
~$ psu /data/data/com.termux/files/usr/bin/ps -p $$,1 -o pid=,comm=
CANNOT LINK EXECUTABLE "/data/data/com.termux/files/usr/bin/ps": library "libprocps.so" not found
~$ psu LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib /data/data/com.termux/files/usr/bin/ps -p $$,1 -o pid=,comm=
    1 init
23599 bash


So that's how we can get a minimal root functionality without using any specialized rooting tools.



RELATED:


How does SuperSU provide root privilege?