Rooting the Toshiba AT10A

As I needed a software controllable high-resolution display for another project, and had an old Toshiba AT10A lying around (yes, I'm actively searching for similar tablets by now), the easiest option seemed to repeat the rooting procedure I did for the other Toshibas.

Re-using binaries and scripts from the original rooting run, I arrive at:

shell@android:/data/local/tmp $ ls -la
-rwxrwxrwx shell    shell       55381 2024-09-24 08:03 dirtycow
-rwxrwxrwx shell    shell         296 2024-09-24 08:03 root.sh
-rwxrwxrwx shell    shell         309 2024-09-24 08:03 start-su.sh
-rwxrwxrwx shell    shell       49253 2024-09-24 08:03 su

(script contents will be shown below, but they're not usable yet).

and immediately:

shell@android:/data/local/tmp $ cp /system/bin/debuggerd debuggerd.orig
shell@android:/data/local/tmp $ cp /system/bin/netd netd.orig
shell@android:/data/local/tmp $ ./dirtycow start-su.sh /system/bin/debuggerd
shell@android:/data/local/tmp $ ./dirtycow start-su.sh /system/bin/netd
shell@android:/data/local/tmp $ sleep 45
shell@android:/data/local/tmp $ ./su
/system/bin/sh: No controlling tty: open /dev/tty: No such device or address
/system/bin/sh: warning: won't have full job control
root@android:/ #

Unfortunately, the kernel has a different layout yet again, so I need to repeat some steps:

root@android:/ # echo 0 > /proc/sys/kernel/kptr_restrict
root@android:/ # cat /proc/kallsyms >/data/local/tmp/kallsyms.txt

As for the AT300SE I need to dump the code registering sealime. The beaten path being to assemble a call to print_hex_dump and patch that into gps_drv.ko:

% cat dump_memory.as
.macro mov32, reg, val
    movw \reg, #:lower16:\val
    movt \reg, #:upper16:\val
.endm

init_module:
        push  {r4,lr}
        sub   sp, sp, #20

        adr   r0, KERN_ERR
        adr   r1, PREFIX
        mov   r2, #1  // DUMP_PREFIX_ADDRESS
        mov   r3, #16 // rowsize
        mov   r4, #1
        str   r4, [sp] // groupsize
        mov32 r4, 0xc01c6b64 // register_sealime
        str   r4, [sp, #4] // buf
        mov32 r4, 0x100
        str   r4, [sp, #8] // len
        mov   r4, #1
        str   r4, [sp, #12] // ascii

        mov32 r4, 0xc0204dc8 // print_hex_dump
        blx   r4

        mov   r0, #-43
        add   sp, sp, #20
        pop   {r4,pc}

KERN_ERR:
        .asciz "<3>"

PREFIX:
        .asciz "glomus"

Assemble for arm and patch the resulting code into the .init.text section of the original gps_drv.ko:

% arm-none-eabi-as dump_memory.as -o dump_memory.o  
% readelf -a dump_memory.o
...
  [ 1] .text             PROGBITS        00000000 000034 000064 00  AX  0   0  4
...
% readelf -a gps_drv.ko
...
  [ 3] .init.text        PROGBITS        00000000 000a9c 0000fc 00  AX  0   0  4
  [ 4] .rel.init.text    REL             00000000 01c130 000080 08     50   3  4
...
% cp gps_drv.ko dump_memory.ko
% dd bs=1 skip=$((0x34)) count=$((0x64)) seek=$((0xa9c)) if=dump_memory.o of=dump_memory.ko conv=notrunc

... and disabling any .rel.init.text relocations (by setting the section length to zero):

% readelf -a gps_drv.ko
...
  Start of section headers:          111856 (bytes into file)
...
% # 40 bytes per section headers, 20 byte offset of length field
% dd bs=1 count=1 skip=0 seek=$((111856 + 4 * 40 + 20)) if=/dev/zero of=dump_memory.ko conv=notrunc
% readelf -a dump_memory.ko
...
  [ 4] .rel.init.text    REL             00000000 01c130 000000 08     50   3  4
...

Dirtycow and insmod the improved "GPS driver":

root@android:/data/local/tmp # ./dirtycow dump_memory.ko /system/lib/modules/gps_drv.ko
root@android:/data/local/tmp # insmod /system/lib/modules/gps_drv.ko
insmod: init_module '/system/lib/modules/gps_drv.ko' failed (Identifier removed)
root@android:/data/local/tmp # dmesg
<3>[  736.985051] glomusc01c6b64: 00 40 2d e9 00 40 bd e8 fc 37 0b e3 48 31 4c e3  .@-..@...7..H1L.
<3>[  736.997016] glomusc01c6b74: 00 00 83 e5 00 00 a0 e3 1e ff 2f e1 00 40 2d e9  ........../..@-.
<3>[  737.008876] glomusc01c6b84: 00 40 bd e8 fc 37 0b e3 48 31 4c e3 04 00 83 e5  .@...7..H1L.....
<3>[  737.017996] glomusc01c6b94: 00 00 a0 e3 1e ff 2f e1 f0 45 2d e9 0c d0 4d e2  ....../..E-...M.
<3>[  737.027536] glomusc01c6ba4: 00 40 2d e9 00 40 bd e8 78 40 9f e5 00 60 a0 e1  .@-..@..x@...`..
<3>[  737.036975] glomusc01c6bb4: 01 70 a0 e1 02 50 a0 e1 03 80 a0 e1 00 c0 94 e5  .p...P..........
<3>[  737.046059] glomusc01c6bc4: 28 a0 9d e5 00 00 5c e3 12 00 00 0a 00 a0 8d e5  (.....\.........
<3>[  737.054715] glomusc01c6bd4: a4 c1 9c e5 3c ff 2f e1 01 00 70 e3 0b 00 00 0a  ....<./...p.....
<3>[  737.063344] glomusc01c6be4: 04 30 94 e5 00 00 53 e3 08 00 00 0a a4 c1 93 e5  .0....S.........
<3>[  737.071970] glomusc01c6bf4: 00 00 5c e3 05 00 00 0a 00 a0 8d e5 06 00 a0 e1  ..\.............
<3>[  737.080636] glomusc01c6c04: 07 10 a0 e1 05 20 a0 e1 08 30 a0 e1 3c ff 2f e1  ..... ...0..<./.
<3>[  737.089348] glomusc01c6c14: 0c d0 8d e2 f0 85 bd e8 02 30 a0 e1 00 a0 8d e5  .........0......
<3>[  737.097964] glomusc01c6c24: cd fc ff eb eb ff ff ea fc b7 48 c1 f8 4f 2d e9  ..........H..O-.
<3>[  737.110022] glomusc01c6c34: 00 40 2d e9 00 40 bd e8 00 50 a0 e1 c4 60 9f e5  .@-..@...P...`..
<3>[  737.118686] glomusc01c6c44: 01 90 a0 e1 00 00 96 e5 00 00 50 e3 02 00 00 0a  ..........P.....
<3>[  737.127949] glomusc01c6c54: 10 00 80 e2 9c c9 00 eb 00 00 96 e5 00 40 90 e5  .............@..

With a bit of VIm and xxd, grab the original instruction stream:

% cat register_sealime.dump  
00000000: 00 40 2d e9 00 40 bd e8 fc 37 0b e3 48 31 4c e3  .@-..@...7..H1L.
00000010: 00 00 83 e5 00 00 a0 e3 1e ff 2f e1 00 40 2d e9  ........../..@-.
00000020: 00 40 bd e8 fc 37 0b e3 48 31 4c e3 04 00 83 e5  .@...7..H1L.....
00000030: 00 00 a0 e3 1e ff 2f e1 f0 45 2d e9 0c d0 4d e2  ....../..E-...M.
00000040: 00 40 2d e9 00 40 bd e8 78 40 9f e5 00 60 a0 e1  .@-..@..x@...`..
00000050: 01 70 a0 e1 02 50 a0 e1 03 80 a0 e1 00 c0 94 e5  .p...P..........
00000060: 28 a0 9d e5 00 00 5c e3 12 00 00 0a 00 a0 8d e5  (.....\.........
00000070: a4 c1 9c e5 3c ff 2f e1 01 00 70 e3 0b 00 00 0a  ....<./...p.....
00000080: 04 30 94 e5 00 00 53 e3 08 00 00 0a a4 c1 93 e5  .0....S.........
00000090: 00 00 5c e3 05 00 00 0a 00 a0 8d e5 06 00 a0 e1  ..\.............
000000A0: 07 10 a0 e1 05 20 a0 e1 08 30 a0 e1 3c ff 2f e1  ..... ...0..<./.
000000B0: 0c d0 8d e2 f0 85 bd e8 02 30 a0 e1 00 a0 8d e5  .........0......
000000C0: cd fc ff eb eb ff ff ea fc b7 48 c1 f8 4f 2d e9  ..........H..O-.
000000D0: 00 40 2d e9 00 40 bd e8 00 50 a0 e1 c4 60 9f e5  .@-..@...P...`..
000000E0: 01 90 a0 e1 00 00 96 e5 00 00 50 e3 02 00 00 0a  ..........P.....
000000F0: 10 00 80 e2 9c c9 00 eb 00 00 96 e5 00 40 90 e5  .............@..
% xxd -r register_sealime.dump > register_sealime
% arm-none-eabi-objdump -D -b binary -m arm_any register_sealime


register_sealime:     file format binary


Disassembly of section .data:

00000000 <.data>:
   0:   e92d4000        stmfd   sp!, {lr}
   4:   e8bd4000        ldmfd   sp!, {lr}
   8:   e30b37fc        movw    r3, #47100      @ 0xb7fc
   c:   e34c3148        movt    r3, #49480      @ 0xc148
  10:   e5830000        str     r0, [r3]
  14:   e3a00000        mov     r0, #0
  18:   e12fff1e        bx      lr
  1c:   e92d4000        stmfd   sp!, {lr}
  20:   e8bd4000        ldmfd   sp!, {lr}
  24:   e30b37fc        movw    r3, #47100      @ 0xb7fc
  28:   e34c3148        movt    r3, #49480      @ 0xc148
  2c:   e5830004        str     r0, [r3, #4]
  30:   e3a00000        mov     r0, #0
  34:   e12fff1e        bx      lr
  38:   e92d45f0        push    {r4, r5, r6, r7, r8, sl, lr}
  3c:   e24dd00c        sub     sp, sp, #12
  40:   e92d4000        stmfd   sp!, {lr}
  44:   e8bd4000        ldmfd   sp!, {lr}
  48:   e59f4078        ldr     r4, [pc, #120]  @ 0xc8
...

Write code to unregister sealime (set the pointer to NULL), assemble and patch a glomus.ko from gps_drv.ko:

% cat > glomus.as
.macro mov32, reg, val
    movw \reg, #:lower16:\val
    movt \reg, #:upper16:\val
.endm

init_module:
  push  {lr}
 
  mov   r0, #0
  mov32 r1, 0xc148B7fc
  str   r0, [r1]
  str   r0, [r1, #4]
 
  mov   r0, #-43
  pop   {pc}
% arm-none-eabi-as glomus.as -o glomus.o  
% cp gps_drv.ko glomus.ko
% dd bs=1 skip=$((0x34)) count=$((0x64)) seek=$((0xa9c)) if=glomus.o of=glomus.ko conv=notrunc
% dd bs=1 count=1 skip=0 seek=$((111856 + 4 * 40 + 20)) if=/dev/zero of=glomus.ko conv=notrunc

And finally disable sealime:

root@android:/data/local/tmp # ./dirtycow glomus.ko /system/lib/modules/gps_drv.ko
root@android:/data/local/tmp # insmod /system/lib/modules/gps_drv.ko
insmod: init_module '/system/lib/modules/gps_drv.ko' failed (Identifier removed)
root@android:/data/local/tmp # ./dirtycow gps_drv.ko /system/lib/modules/gps_drv.ko

At this point, it seems I have full access. Unfortunately, /dev/graphics/fb0 is no longer mapped to the actual screen, thanks to whatever bootanim and zygote did with the GL setup.

So let's disable that part of the boot sequence. Unfortunately, remounting /system read-write will crash the kernel when it tries to "write back" the dirty-cow'ed pages. So instead let's rename drmserver bootanimation and surfaceflinger directly on the block device.

To prepare, I'm copying the original image so I can train filesystem patching locally (and without risk of bricking):

root@android:/data/local/tmp # dd if=/dev/block/platform/sdhci-tegra.3/by-name/APP of=/data/local/tmp/system.img
root@android:/data/local/tmp # chmod 777 /data/local/tmp/system.img
% adb pull /data/local/tmp/system.img
% file system.img 
system.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (extents) (large files)
% e2fsck -vn system.img 
e2fsck 1.47.0 (5-Feb-2023)
system.img: clean, 1782/65536 files, 227442/262140 blocks

I planned to manually patch the file system via dd at this point, but ultimately concluded it would be dumb. Instead:

% cp system.img system-new.img
% mount -o loop system-new.img /mnt
/mnt/bin % mv bootanimation bootanimation.off
/mnt/bin % mv drmserver drmserver.off
/mnt/bin % mv surfaceflinger surfaceflinger.off
% umount /mnt

Using https://gitli.stratum0.org/Drahflow/binpatch (and after adjusting some sprintf format strings):

% ./generate system.img system-new.img > system.patch.c
% gcc -W -Wall -Wextra -static system.patch.c -o system.patch
% adb push system.patch /data/local/tmp
root@android:/data/local/tmp # ./system.patch /dev/block/platform/sdhci-tegra.3/by-name/APP
Patched at 0x0
Patched at 0x243000
...
Patched at 0x18048000
Patched at 0x18243000
root@android:/data/local/tmp # reboot
% adb shell
shell@android:/ $ ls /system/bin/boot*
/system/bin/bootanimation.off

And indeed, /dev/graphics/fb0 is now mapped to the screen as would be expected.
The backlight can be controlled via /sys/class/backlight/pwm-backlight/brightness.

Script contents for reference

shell@android:/data/local/tmp $ cat root.sh
#!/system/bin/sh

cd /data/local/tmp
./dirtycow start-su.sh /system/bin/debuggerd
./dirtycow start-su.sh /system/bin/netd

sleep 45

./dirtycow glomus.ko /system/lib/modules/gps_drv.ko
echo 'insmod /system/lib/modules/gps_drv.ko; exit' | ./su
./dirtycow gps_drv.ko /system/lib/modules/gps_drv.ko
shell@android:/data/local/tmp $ cat start-su.sh
#!/system/bin/sh

if ! /data/local/tmp/su -c id; then
        mount -o remount,suid /data
        /data/local/tmp/su --daemon
fi

# repair daemons
/data/local/tmp/dirtycow /data/local/tmp/debuggerd.orig /system/bin/debuggerd
/data/local/tmp/dirtycow /data/local/tmp/netd.orig /system/bin/netd

exec "$0" "$@"