mirror of
https://github.com/fbelavenuto/arpl.git
synced 2026-01-03 23:22:05 +08:00
115
kpatch/main.c
115
kpatch/main.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Fabio Belavenuto <belavenuto@gmail.com>
|
||||
* Copyright (c) 2022 Fabio Belavenuto <belavenuto@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,11 +28,8 @@
|
||||
* - values of ORs are 1/2/4/8 respectively
|
||||
* - [const-ptr] is always the same
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* A quick tool for patching the ramdisk check in the DSM kernel image
|
||||
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
|
||||
*
|
||||
* Added patch for CMOS_WRITE by Fabio Belavenuto
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -44,22 +41,25 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <gelf.h>
|
||||
|
||||
const int DIR_FWD = 1;
|
||||
const int DIR_RWD = -1;
|
||||
|
||||
/* Variables */
|
||||
int fd;
|
||||
int verbose = 1, read_only = 0;
|
||||
Elf *elfHandle;
|
||||
GElf_Ehdr elfExecHeader;
|
||||
uint64_t orPos[4], fileSize, rodataAddr, rodataOffs, initTextOffs;
|
||||
int fd, verbose = 1, read_only = 0;
|
||||
Elf *elfHandle;
|
||||
GElf_Ehdr elfExecHeader;
|
||||
uint64_t orPos[4], fileSize, rodataAddr, rodataOffs, initTextOffs;
|
||||
unsigned char *fileData;
|
||||
|
||||
/*****************************************************************************/
|
||||
void errorMsg(char *message) {
|
||||
fprintf(stderr, "%s\n", message);
|
||||
void errorMsg(char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ void patchBootParams() {
|
||||
uint64_t newPtrOffset, ptrOffset;
|
||||
int n;
|
||||
|
||||
printf("Patching boot params.\n");
|
||||
//The function will reside in init code part. We don't care we may potentially search beyond as we expect it to be found
|
||||
printf("Found .init.text at %lX\n", initTextOffs);
|
||||
while (initTextOffs < fileSize) {
|
||||
addr = findPUSH_R12_R15_SEQ(initTextOffs);
|
||||
if (addr == -1)
|
||||
@@ -160,8 +160,8 @@ void patchBootParams() {
|
||||
} else if (ptrOffset == newPtrOffset) {
|
||||
++ec;
|
||||
}
|
||||
printf("\t[+] Found LOCK-OR#$idx sequence @ %lX => %02X %02X %02X %02X %02X %02X %02X %02X [RIP+%lX]\n",
|
||||
pos, fileData[pos], fileData[pos+1], fileData[pos+2], fileData[pos+3], fileData[pos+4],
|
||||
printf("\t[+] Found LOCK-OR#%d sequence @ %lX => %02X %02X %02X %02X %02X %02X %02X %02X [RIP+%lX]\n",
|
||||
n, pos, fileData[pos], fileData[pos+1], fileData[pos+2], fileData[pos+3], fileData[pos+4],
|
||||
fileData[pos+5], fileData[pos+6], fileData[pos+7], newPtrOffset);
|
||||
}
|
||||
if (ec != 4) {
|
||||
@@ -175,7 +175,7 @@ void patchBootParams() {
|
||||
break;
|
||||
}
|
||||
if (addr == -1) {
|
||||
errorMsg("\nFailed to find matching sequences");
|
||||
errorMsg("\nFailed to find matching sequences\n");
|
||||
} else {
|
||||
//Patch offsets
|
||||
for (n = 0; n < 4; n++) {
|
||||
@@ -197,11 +197,10 @@ uint32_t changeEndian(uint32_t num) {
|
||||
|
||||
/*****************************************************************************/
|
||||
uint64_t findSeq(const char* seq, int len, uint32_t pos, int dir, uint64_t max) {
|
||||
uint64_t i;
|
||||
uint64_t i = pos;
|
||||
|
||||
i = pos;
|
||||
do {
|
||||
if (strncmp((const char*)fileData+i, seq, len) == 0) {
|
||||
if (memcmp((const char*)fileData+i, seq, len) == 0) {
|
||||
return i;
|
||||
}
|
||||
i += dir;
|
||||
@@ -216,9 +215,9 @@ void patchRamdiskCheck() {
|
||||
uint64_t printkPos, testPos, jzPos;
|
||||
const char str[] = "3ramdisk corrupt";
|
||||
|
||||
printf("Patching ramdisk check\n");
|
||||
printf("Patching ramdisk check.\n");
|
||||
for (pos = rodataOffs; pos < fileSize; pos++) {
|
||||
if (strncmp(str, (const char*)(fileData + pos), 16) == 0) {
|
||||
if (memcmp(str, (const char*)(fileData + pos), 16) == 0) {
|
||||
pos -= rodataOffs;
|
||||
break;
|
||||
}
|
||||
@@ -227,17 +226,15 @@ void patchRamdiskCheck() {
|
||||
printf("LE arg addr: %08lX\n", errPrintAddr);
|
||||
printkPos = findSeq((const char*)&errPrintAddr, 4, 0, DIR_FWD, -1);
|
||||
if (printkPos == -1) {
|
||||
errorMsg("printk pos not found!");
|
||||
errorMsg("printk pos not found!\n");
|
||||
}
|
||||
//double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI)
|
||||
printkPos -= 3;
|
||||
if (strncmp((const char*)fileData+printkPos, "\x48\xc7", 2) != 0) {
|
||||
printf("Expected MOV=>reg before printk error, got %02X %02X\n", fileData[printkPos], fileData[printkPos+1]);
|
||||
errorMsg("");
|
||||
if (memcmp((const char*)fileData+printkPos, "\x48\xc7", 2) != 0) {
|
||||
errorMsg("Expected MOV=>reg before printk error, got %02X %02X\n", fileData[printkPos], fileData[printkPos+1]);
|
||||
}
|
||||
if (fileData[printkPos+2] < 0xC0 || fileData[printkPos+2] > 0xC7) {
|
||||
printf("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[printkPos+2]);
|
||||
errorMsg("");
|
||||
errorMsg("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[printkPos+2]);
|
||||
}
|
||||
printf("Found printk MOV @ %08lX\n", printkPos);
|
||||
|
||||
@@ -256,6 +253,54 @@ void patchRamdiskCheck() {
|
||||
fileData[jzPos] = 0xEB;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void patchCmosWrite() {
|
||||
uint64_t pos, errPrintAddr;
|
||||
uint64_t pr_errPos, testPos, callPos;
|
||||
const char str[] = "3smpboot: %s: this boot have memory training";
|
||||
|
||||
printf("Patching call to rtc_cmos_write.\n");
|
||||
for (pos = rodataOffs; pos < fileSize; pos++) {
|
||||
if (memcmp(str, (const char*)(fileData + pos), 16) == 0) {
|
||||
pos -= rodataOffs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
errPrintAddr = rodataAddr + pos - 1;
|
||||
printf("LE arg addr: %08lX\n", errPrintAddr);
|
||||
pr_errPos = findSeq((const char*)&errPrintAddr, 4, 0, DIR_FWD, -1);
|
||||
if (pr_errPos == -1) {
|
||||
printf("pr_err pos not found - ignoring.\n"); // Some kernels do not have the call, exit without error
|
||||
return;
|
||||
}
|
||||
//double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI)
|
||||
pr_errPos -= 3;
|
||||
if (memcmp((const char*)fileData+pr_errPos, "\x48\xc7", 2) != 0) {
|
||||
errorMsg("Expected MOV=>reg before pr_err error, got %02X %02X\n", fileData[pr_errPos], fileData[pr_errPos+1]);
|
||||
}
|
||||
if (fileData[pr_errPos+2] < 0xC0 || fileData[pr_errPos+2] > 0xC7) {
|
||||
errorMsg("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[pr_errPos+2]);
|
||||
}
|
||||
printf("Found pr_err MOV @ %08lX\n", pr_errPos);
|
||||
|
||||
// now we should seek a reasonable amount (say, up to 64 bytes) for a sequence of
|
||||
// MOV ESI, 0x48 => MOV EDI, 0xFF => MOV EBX, EAX
|
||||
testPos = findSeq("\xBE\x48\x00\x00\x00\xBF\xFF\x00\x00\x00\x89\xC3", 12, pr_errPos, DIR_RWD, 64);
|
||||
if (testPos == -1) {
|
||||
printf("Failed to find MOV ESI, 0x48 => MOV EDI, 0xFF => MOV EBX, EAX\n");
|
||||
return;
|
||||
}
|
||||
printf("Found MOV ESI, 0x48 => MOV EDI, 0xFF => MOV EBX, EAX @ %08lX\n", testPos);
|
||||
callPos = testPos + 12;
|
||||
if (fileData[callPos] != 0xE8) {
|
||||
errorMsg("Failed to find CALL\n");
|
||||
}
|
||||
printf("OK - patching %02X (CALL) to 0x90.. (NOPs) @ %08lX\n",
|
||||
fileData[callPos], callPos);
|
||||
for(uint64_t i = 0; i < 5; i++)
|
||||
fileData[callPos+i] = 0x90;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int main(int argc, char *argv[]) {
|
||||
struct stat fileInf;
|
||||
@@ -264,7 +309,7 @@ int main(int argc, char *argv[]) {
|
||||
char *sectionName;
|
||||
|
||||
if (argc != 3) {
|
||||
errorMsg("Use: kpatch <vmlinux> <output>");
|
||||
errorMsg("Use: kpatch <vmlinux> <output>\n");
|
||||
}
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
@@ -281,13 +326,13 @@ int main(int argc, char *argv[]) {
|
||||
switch(elf_kind(elfHandle)) {
|
||||
case ELF_K_NUM:
|
||||
case ELF_K_NONE:
|
||||
errorMsg("file type unknown");
|
||||
errorMsg("file type unknown\n");
|
||||
break;
|
||||
case ELF_K_COFF:
|
||||
errorMsg("COFF binaries not supported");
|
||||
errorMsg("COFF binaries not supported\n");
|
||||
break;
|
||||
case ELF_K_AR:
|
||||
errorMsg("AR archives not supported");
|
||||
errorMsg("AR archives not supported\n");
|
||||
break;
|
||||
case ELF_K_ELF:
|
||||
break;
|
||||
@@ -319,8 +364,12 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
close(fd);
|
||||
|
||||
printf("Found .init.text offset @ %lX\n", initTextOffs);
|
||||
printf("Found .rodata address @ %lX\n", rodataAddr);
|
||||
printf("Found .rodata offset @ %lX\n", rodataOffs);
|
||||
patchBootParams();
|
||||
patchRamdiskCheck();
|
||||
patchCmosWrite();
|
||||
if ((fd = open(argv[2], O_WRONLY | O_CREAT, 0644)) == -1) {
|
||||
errorNum();
|
||||
}
|
||||
@@ -328,6 +377,6 @@ int main(int argc, char *argv[]) {
|
||||
errorNum();
|
||||
}
|
||||
close(fd);
|
||||
printf("\n");
|
||||
printf("Finish!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user