[Android General] fddm:
This is a guide for advanced users to remove the effect of CONFIG_MODULE_SIG_FORCE on stock kernels. This can be used to load custom modules you built or in building TWRP where you want to use a stock kernel and leverage the vendor partition to make the image smaller and still have it work on different variants.

The prerequisite here is a raw kernel image. Modern AARCH64 devices generally just gzip the kernel, but other compression formats can be used as well as decompression code prepended to the compressed kernel which will have to be cut out and stitched back in once the modifications are made.

If you don't already have Ghidra installed, go ahead and install it as it will be the analysis tool used here.

The first step is to launch Ghidra and create new project, then drag your kernel binary into the active project.

View attachment 5313445

If the processor architecture is not filled in, it's probably missing the header, and you'll have to choose it from the list. If the file is unknown, you'll need to try different options until the disassembly looks correct. Then you can double-click the project file to open in Ghidra. Click analyze and let it process the binary until the hourglass at the bottom right disappears.

Our primary method for obtaining information and locating our target code is though strings.

Select Search - > For strings... and have it search the entire binary

Since Linux is open source, we start by finding which exact version we are dealing with. Filtering the strings dialog for "linux" yields the version string, in this case Linux version 4.19.95-perf.

View attachment 5313449

Our target is to disable the effects of the CONFIG_MODULE_SIG_FORCE, so we need to find references of it in the kernel source tree. After reading through the code, we find our target function module_sig_check in module.c

https://elixir.bootlin.com/linux/v4.19.95/source/kernel/module.c#L2789

There are no strings referenced in this function, so we have to track/backtrack through called/calling functions to find one that is near the function we are looking for. In the called function mod_verify_sig we find a good candidate "%s: Module is not signed with expected PKCS#7 message"

module_signing.c - kernel/module_signing.c - Linux source code (v4.19.95) - Bootlin

Elixir Cross Referencer - Explore source code in your browser - Particularly useful for the Linux kernel and other low-level projects in C/C++ (bootloaders, C libraries...)

elixir.bootlin.com

Double-clicking in the strings dialog takes us to were that string is stored and also gives us an XREF that we can double-click to get to the code referencing it

View attachment 5313453

If we scroll up to the start of the function we have landed in, we get another XREF(bottom of the highlighted section) that will land us right in the middle of module_sig_check

View attachment 5313461

We have now landed in a very large function, much larger than module_sig_check. This is a result of compiler optimization. The compiler has merged several functions together and much of the code has been optimized out making it harder to follow.

View attachment 5313463

My approach to patching this is to find the beginning of the first IF statement and have the code there jump directly to "info->sig_ok = true". The disassembly is directly linked to the decompiler, so you can click and select code in either window to see the corresponding code on the other side.

Our first target

if (flags == 0 &&
info->len > markerlen &&
memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {

looks like this decompiled(partial):

if ((param_3 == 0) && ((char *)0x1c < param_1[3])) {

Highlighting the decompiled code, we find the first instruction to be here:

001224f0 96 01 00 35 cbnz w22,LAB_00122520

View attachment 5313467

Doing the same for our second target

info->sig_ok = true;

which looks like this in the decompilation:

*(undefined *)((longlong)param_1 + 0x54) = 1;

leads us the corresponding instruction:

00122574 68 52 01 39 strb w8,[x19, #0x54]

But our true landing point is actually one instruction above it:

00122570 e8 03 00 32 mov w8,#0x1

This instruction sets the w8 register to 1 which is in turn used to set info->sig_ok. Skipping this would cause it to be set to whatever is on w8 at the time, which could be anything.

View attachment 5313477

With both targets, we can start patching. Right-click the cbnz instruction at 001224f0 and select Patch Instruction. Once it's done processing, we set the first field to "b" for the branch instruction and the second to "0x00122570" for branch target followed by enter. Now we end up with

001224f0 20 00 00 14 b LAB_00122570

and the decompilation will reflect the change in code flow after giving it time to update.

View attachment 5313479

Finally we can go to Export Program..., set the format to Binary and press OK to save the modified binary.