mirror of
https://github.com/RROrg/rr.git
synced 2025-06-21 05:51:05 +08:00
Replaced php scripts for alternatives
Add kpatch C code for patch DSM kernel Fix ramdisk-common-init-script (wrong merge)
This commit is contained in:
parent
ea1cf413be
commit
c7aab7f297
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@ test.sh
|
|||||||
docker/Dockerfile
|
docker/Dockerfile
|
||||||
docker/cache
|
docker/cache
|
||||||
*.bak
|
*.bak
|
||||||
|
*.o
|
||||||
|
@ -20,3 +20,9 @@ tasks:
|
|||||||
dir: addons
|
dir: addons
|
||||||
cmds:
|
cmds:
|
||||||
- ./compile-addons.sh {{.CLI_ARGS}}
|
- ./compile-addons.sh {{.CLI_ARGS}}
|
||||||
|
|
||||||
|
compile-kpatch:
|
||||||
|
dir: kpatch
|
||||||
|
cmds:
|
||||||
|
- make clean all
|
||||||
|
- mv kpatch ../files/board/arpl/overlayfs/opt/arpl/
|
||||||
|
@ -1,245 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file contains usual common functions used by patchers
|
|
||||||
*
|
|
||||||
* Most of the functions here are written to be C-like without utilizing any of the PHP's magic. This functionality is
|
|
||||||
* ultimately intended to be rewritten into a dynamic patcher in C. Making this code compatible wtih simple C (e.g.
|
|
||||||
* by not using fancy regexes) will make it slower in PHP but MUCH easier to rewrite into C later on.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function perr(string $txt, $die = false)
|
|
||||||
{
|
|
||||||
fwrite(STDERR, $txt);
|
|
||||||
if ($die) {
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
function getELFSectionAddr(string $elf, string $section, int $pos)
|
|
||||||
{
|
|
||||||
$secAddr = exec(
|
|
||||||
sprintf('readelf -S \'%1$s\' | grep -E \'\s%2$s\s\' | awk -F\'%2$s\' \'{ print $2 }\' | awk \'{ print $%3$d }\'', $elf, str_replace('.', '\.', $section), $pos)
|
|
||||||
);
|
|
||||||
if (!$secAddr) {
|
|
||||||
perr("$section section not found in $elf file\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$secAddr = hexdec(substr($secAddr, -8));
|
|
||||||
perr("Found $section at " . decTo32bUFhex($secAddr) . " in $elf\n");
|
|
||||||
|
|
||||||
return $secAddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getELFStringLoc(string $elf, string $text)
|
|
||||||
{
|
|
||||||
$strAddr = exec(
|
|
||||||
sprintf(
|
|
||||||
'readelf -p \'.rodata\' \'%s\' | grep \'%s\' | grep -oE \'\[(\s+)?.+\]\' | grep -oE \'[a-f0-9]+\'',
|
|
||||||
$elf, $text
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$strAddr) {
|
|
||||||
perr("$text string not found in $elf file's .rodata section\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$secAddr = hexdec(substr($strAddr, -8));
|
|
||||||
perr("Found \"$text\" at " . decTo32bUFhex($secAddr) . " in $elf\n");
|
|
||||||
|
|
||||||
return $secAddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getArgFilePath(int $argn)
|
|
||||||
{
|
|
||||||
global $argv;
|
|
||||||
|
|
||||||
$file = realpath($argv[$argn]);
|
|
||||||
if (!is_file($file) || !$file) {
|
|
||||||
perr("Expected a readable file in argument $argn - found none\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts decimal value to 32-bit little-endian hex value
|
|
||||||
*/
|
|
||||||
function decTo32bLEhex(int $dec)
|
|
||||||
{
|
|
||||||
$hex = str_pad(dechex($dec), 32 / 8 * 2, 'f', STR_PAD_LEFT); //32-bit hex
|
|
||||||
|
|
||||||
return implode('', array_reverse(str_split($hex, 2))); //make it little-endian
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts decimal value to 32-bit user-friendly (and big-endian) hex value
|
|
||||||
*
|
|
||||||
* This function should really be used for printing
|
|
||||||
*/
|
|
||||||
function decTo32bUFhex(int $dec)
|
|
||||||
{
|
|
||||||
return implode(' ', str_split(str_pad(dechex($dec), 32 / 8 * 2, 'f', STR_PAD_LEFT), 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
function rawToUFhex(string $raw)
|
|
||||||
{
|
|
||||||
$out = '';
|
|
||||||
for($i=0, $iMax = strlen($raw); $i < $iMax; $i++) {
|
|
||||||
$out .= sprintf('%02x', ord($raw[$i]));
|
|
||||||
|
|
||||||
if ($i+1 !== $iMax) {
|
|
||||||
$out .= ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert hex values to their binary/raw counterparts as-is
|
|
||||||
*/
|
|
||||||
function hex2raw(string $hex)
|
|
||||||
{
|
|
||||||
$bin = '';
|
|
||||||
for ($i = 0, $iMax = strlen($hex); $i < $iMax; $i += 2) {
|
|
||||||
$bin .= chr(hexdec($hex[$i] . $hex[$i + 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bin;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DIR_FWD = 1;
|
|
||||||
const DIR_RWD = -1;
|
|
||||||
function findSequence($fp, string $bin, int $pos, int $dir, int $maxToCheck)
|
|
||||||
{
|
|
||||||
if ($maxToCheck === -1) {
|
|
||||||
$maxToCheck = PHP_INT_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
$len = strlen($bin);
|
|
||||||
do {
|
|
||||||
fseek($fp, $pos);
|
|
||||||
if (strcmp(fread($fp, $len), $bin) === 0) {
|
|
||||||
return $pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
$pos = $pos + $dir;
|
|
||||||
$maxToCheck--;
|
|
||||||
} while (!feof($fp) && $pos != -1 && $maxToCheck != 0);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates a pattern of bytes $searchSeqNum in a $fp stream starting from $pos seeking up to $maxToCheck
|
|
||||||
*
|
|
||||||
* @param array $searchSeqNum An array containing n elements (where n=length of the searched sequence). Each element can
|
|
||||||
* be a null (denoting "any byte"), singular hex/int value (e.g. 0xF5), or a range in a form
|
|
||||||
* of a two-element array (e.g. [0xF0, 0xF7])
|
|
||||||
*/
|
|
||||||
function findSequenceWithWildcard($fp, array $searchSeqNum, int $pos, int $maxToCheck)
|
|
||||||
{
|
|
||||||
if ($maxToCheck === -1) {
|
|
||||||
$maxToCheck = PHP_INT_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
$bufLen = count($searchSeqNum);
|
|
||||||
if ($maxToCheck < $bufLen) {
|
|
||||||
perr("maxToCheck cannot be smaller than search sequence!", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Convert all singular value to raw bytes while leaving arrays as numeric (performance reasons). As this loop is
|
|
||||||
//executed once per pattern it can be sub-optimal but more careful with data validation
|
|
||||||
$searchSeq = [];
|
|
||||||
foreach ($searchSeqNum as $idx => $num) {
|
|
||||||
if ($num === null) {
|
|
||||||
$searchSeq[] = null;
|
|
||||||
} elseif (is_array($num) && count($num) == 2 && is_int($num[0]) && is_int($num[1]) && $num[0] >= 0 &&
|
|
||||||
$num[0] <= 255 && $num[1] >= 0 && $num[1] <= 255 && $num[0] < $num[1]) {
|
|
||||||
$searchSeq[] = $num; //Leave them as numeric
|
|
||||||
} elseif (is_int($num) && $num >= 0 && $num <= 255) {
|
|
||||||
$searchSeq[] = chr($num);
|
|
||||||
} else {
|
|
||||||
perr("Found invalid search sequence at index $idx", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//$pos denotes start position but it's also used to mark where start of a potential pattern match was found
|
|
||||||
fseek($fp, $pos);
|
|
||||||
do { //This loop is optimized for speed
|
|
||||||
$buf = fread($fp, $bufLen);
|
|
||||||
if (!isset($buf[$bufLen-1])) {
|
|
||||||
break; //Not enough data = no match
|
|
||||||
}
|
|
||||||
|
|
||||||
$successfulLoops = 0;
|
|
||||||
foreach ($searchSeq as $byteIdx => $seekByte) {
|
|
||||||
if ($seekByte === null) { //any character
|
|
||||||
++$successfulLoops;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//element in the array can be a range [(int)from,(int)to] or a literal SINGLE byte
|
|
||||||
//if isset finds a second element it will mean for us that it's an array of 2 elements (as we don't expect
|
|
||||||
//a string longer than a single byte)
|
|
||||||
if (isset($seekByte[1])) {
|
|
||||||
$curByteNum = ord($buf[$byteIdx]);
|
|
||||||
if ($curByteNum < $seekByte[0] || $curByteNum > $seekByte[1]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} elseif($buf[$byteIdx] !== $seekByte) { //If the byte doesn't match literally we know it's not a match
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
++$successfulLoops;
|
|
||||||
}
|
|
||||||
if ($successfulLoops === $bufLen) {
|
|
||||||
return $pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek($fp, ++$pos);
|
|
||||||
$maxToCheck--;
|
|
||||||
} while (!feof($fp) && $maxToCheck != 0);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return resource
|
|
||||||
*/
|
|
||||||
function getFileMemMapped(string $path)
|
|
||||||
{
|
|
||||||
$fp = fopen('php://memory', 'r+');
|
|
||||||
fwrite($fp, file_get_contents($path)); //poor man's mmap :D
|
|
||||||
|
|
||||||
return $fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveStreamToFile($fp, string $path)
|
|
||||||
{
|
|
||||||
perr("Saving stream to $path ...\n");
|
|
||||||
|
|
||||||
$fp2 = fopen($path, 'w');
|
|
||||||
fseek($fp, 0);
|
|
||||||
while (!feof($fp)) {
|
|
||||||
fwrite($fp2, fread($fp, 8192));
|
|
||||||
}
|
|
||||||
fclose($fp2);
|
|
||||||
|
|
||||||
perr("DONE!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not call this in time-sensitive code...
|
|
||||||
*/
|
|
||||||
function readAt($fp, int $pos, int $len)
|
|
||||||
{
|
|
||||||
fseek($fp, $pos);
|
|
||||||
return fread($fp, $len);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
if ($argc < 2 || $argc > 2) {
|
|
||||||
fwrite(STDERR, "Usage: " . $argv[0] . " <file>\n");
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
echo hash_file('crc32b', $argv[1]);
|
|
||||||
?>
|
|
BIN
files/board/arpl/overlayfs/opt/arpl/kpatch
Executable file
BIN
files/board/arpl/overlayfs/opt/arpl/kpatch
Executable file
Binary file not shown.
@ -1,141 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A quick tool for patching the boot_params check in the DSM kernel image
|
|
||||||
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
|
|
||||||
*
|
|
||||||
* The overall pattern we need to find is:
|
|
||||||
* - an CDECL function
|
|
||||||
* - does "LOCK OR [const-ptr],n" 4x
|
|
||||||
* - values of ORs are 1/2/4/8 respectively
|
|
||||||
* - [const-ptr] is always the same
|
|
||||||
*
|
|
||||||
* Usage: php patch-boot_params-check.php vmlinux vmlinux-mod
|
|
||||||
*/
|
|
||||||
|
|
||||||
require __DIR__ . '/common.php';
|
|
||||||
|
|
||||||
if ($argc < 2 || $argc > 3) {
|
|
||||||
perr("Usage: " . $argv[0] . " <inFile> [<outFile>]\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = getArgFilePath(1);
|
|
||||||
perr("\nGenerating patch for $file\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
|
|
||||||
$codeAddr = getELFSectionAddr($file, '.init.text', 3);
|
|
||||||
|
|
||||||
//Finding a function boundary is non-trivial really as patters can vary, we can have multiple exit points, and in CISC
|
|
||||||
// there are many things which may match e.g. "PUSH EBP". Implementing even a rough disassembler is pointless.
|
|
||||||
//However, we can certainly cheat here as we know with CDECL a non-empty function will always contain one or more
|
|
||||||
// PUSH (0x41) R12-R15 (0x54-57) sequences. Then we can search like a 1K forward for these characteristic LOCK OR.
|
|
||||||
const PUSH_R12_R15_SEQ = [0x41, [0x54, 0x57]];
|
|
||||||
const PUSH_R12_R15_SEQ_LEN = 2;
|
|
||||||
const LOCK_OR_LOOK_AHEAD = 1024;
|
|
||||||
const LOCK_OR_PTR_SEQs = [
|
|
||||||
[0xF0, 0x80, null, null, null, null, null, 0x01],
|
|
||||||
[0xF0, 0x80, null, null, null, null, null, 0x02],
|
|
||||||
[0xF0, 0x80, null, null, null, null, null, 0x04],
|
|
||||||
[0xF0, 0x80, null, null, null, null, null, 0x08],
|
|
||||||
];
|
|
||||||
const LOCK_OR_PTR_SEQs_NUM = 4; //how many sequences we are expecting
|
|
||||||
const LOCK_OR_PTR_SEQ_LEN = 8; //length of a single sequence
|
|
||||||
|
|
||||||
$fp = getFileMemMapped($file); //Read the whole file to memory to make fseet/fread much faster
|
|
||||||
$pos = $codeAddr; //Start from where code starts
|
|
||||||
$orsPos = null; //When matched it will contain our resulting file offsets to LOCK(); OR BYTE PTR [rip+...],0x calls
|
|
||||||
perr("Looking for f() candidates...\n");
|
|
||||||
do {
|
|
||||||
$find = findSequenceWithWildcard($fp, PUSH_R12_R15_SEQ, $pos, -1);
|
|
||||||
if ($find === -1) {
|
|
||||||
break; //no more "functions" left
|
|
||||||
}
|
|
||||||
|
|
||||||
perr("\rAnalyzing f() candidate @ " . decTo32bUFhex($pos));
|
|
||||||
|
|
||||||
//we found something looking like PUSH R12-R15, now find the ORs
|
|
||||||
$orsPos = []; //file offsets where LOCK() calls should start
|
|
||||||
$orsPosNum = 0; //Number of LOCK(); OR ptr sequences found
|
|
||||||
$seqPos = $pos;
|
|
||||||
foreach (LOCK_OR_PTR_SEQs as $idx => $seq) {
|
|
||||||
$find = findSequenceWithWildcard($fp, $seq, $seqPos, LOCK_OR_LOOK_AHEAD);
|
|
||||||
if ($find === -1) {
|
|
||||||
break; //Seq not found - there's no point to look further
|
|
||||||
}
|
|
||||||
|
|
||||||
$orsPos[] = $find;
|
|
||||||
++$orsPosNum;
|
|
||||||
$seqPos = $find + LOCK_OR_PTR_SEQ_LEN; //Next search will start after the current sequence code
|
|
||||||
}
|
|
||||||
|
|
||||||
//We can always move forward by the function token length (obvious) but if we couldn't find any LOCK-OR tokens
|
|
||||||
// we can skip the whole look ahead distance. We CANNOT do that if we found even a single token because the next one
|
|
||||||
// might have been just after the look ahead distance
|
|
||||||
if ($orsPosNum !== LOCK_OR_PTR_SEQs_NUM) {
|
|
||||||
$pos += PUSH_R12_R15_SEQ_LEN;
|
|
||||||
if ($orsPosNum === 0) {
|
|
||||||
$pos += LOCK_OR_LOOK_AHEAD;
|
|
||||||
}
|
|
||||||
continue; //Continue the main search loop to find next function candidate
|
|
||||||
}
|
|
||||||
|
|
||||||
//We found LOCK(); OR ptr sequences so we can print some logs and collect ptrs (as this is quite expensive)
|
|
||||||
$seqPtrsDist = [];
|
|
||||||
perr("\n[?] Found possible f() @ " . decTo32bUFhex($pos) . "\n");
|
|
||||||
$ptrOffset = null;
|
|
||||||
$equalJumps = 0;
|
|
||||||
foreach (LOCK_OR_PTR_SEQs as $idx => $seq) {
|
|
||||||
//data will have the following bytes:
|
|
||||||
// [0-LOCK()] [1-OR()] [2-BYTE-PTR] [3-OFFS-b3] [4-OFFS-b2] [5-OFFS-b1] [6-OFFS-b1] [7-NUMBER]
|
|
||||||
$seqData = readAt($fp, $orsPos[$idx], LOCK_OR_PTR_SEQ_LEN);
|
|
||||||
$newPtrOffset = //how far it "jumps"
|
|
||||||
$orsPos[$idx] +
|
|
||||||
(unpack('V', $seqData[3] . $seqData[4] . $seqData[5] . $seqData[6])[1]); //u32 bit LE
|
|
||||||
|
|
||||||
if($ptrOffset === null) {
|
|
||||||
$ptrOffset = $newPtrOffset; //Save the first one to compare in the next loop
|
|
||||||
++$equalJumps;
|
|
||||||
} elseif ($ptrOffset === $newPtrOffset) {
|
|
||||||
++$equalJumps;
|
|
||||||
}
|
|
||||||
|
|
||||||
perr(
|
|
||||||
"\t[+] Found LOCK-OR#$idx sequence @ " . decTo32bUFhex($orsPos[$idx]) . " => " .
|
|
||||||
rawToUFhex($seqData) . " [RIP+(dec)$newPtrOffset]\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ($equalJumps !== 4) {
|
|
||||||
perr("\t[-] LOCK-OR PTR offset mismatch - $equalJumps/" . LOCK_OR_PTR_SEQs_NUM . " matched\n");
|
|
||||||
//If the pointer checking failed we can at least move beyond the last LOCK-OR found as we know there's no valid
|
|
||||||
// sequence of LOCK-ORs there
|
|
||||||
$pos = $orsPos[3];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
perr("\t[+] All $equalJumps LOCK-OR PTR offsets equal - match found!\n");
|
|
||||||
break;
|
|
||||||
} while(!feof($fp));
|
|
||||||
|
|
||||||
if ($orsPos === null) { //There's a small chance no candidates with LOCK ORs were found
|
|
||||||
perr("Failed to find matching sequences", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Patch offsets
|
|
||||||
foreach ($orsPos as $seqFileOffset) {
|
|
||||||
//The offset will point at LOCK(), we need to change the OR (0x80 0x0d) to AND (0x80 0x25) so the two bytes after
|
|
||||||
$seqFileOffset = $seqFileOffset+2;
|
|
||||||
|
|
||||||
perr("Patching OR to AND @ file offset (dec)$seqFileOffset\n");
|
|
||||||
fseek($fp, $seqFileOffset);
|
|
||||||
fwrite($fp, "\x25"); //0x0d is OR, 0x25 is AND
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($argv[2])) {
|
|
||||||
perr("No output file specified - discarding data\n");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveStreamToFile($fp, $argv[2]);
|
|
||||||
fclose($fp);
|
|
@ -1,85 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* Usage: php patch-ramdisk-check.php vmlinux vmlinux-mod
|
|
||||||
*/
|
|
||||||
|
|
||||||
require __DIR__ . '/common.php';
|
|
||||||
|
|
||||||
if ($argc < 2 || $argc > 3) {
|
|
||||||
perr("Usage: " . $argv[0] . " <inFile> [<outFile>]\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = getArgFilePath(1);
|
|
||||||
perr("\nGenerating patch for $file\n");
|
|
||||||
|
|
||||||
//Strings (e.g. error for printk()) reside in .rodata - start searching there to save time
|
|
||||||
$rodataAddr = getELFSectionAddr($file, '.rodata', 2);
|
|
||||||
|
|
||||||
//Locate the precise location of "ramdisk error" string
|
|
||||||
$rdErrAddr = getELFStringLoc($file, '3ramdisk corrupt');
|
|
||||||
|
|
||||||
|
|
||||||
//offsets will be 32 bit in ASM and in LE
|
|
||||||
$errPrintAddr = $rodataAddr + $rdErrAddr;
|
|
||||||
$errPrintCAddrLEH = decTo32bLEhex($errPrintAddr - 1); //Somehow rodata contains off-by-one sometimes...
|
|
||||||
$errPrintAddrLEH = decTo32bLEhex($errPrintAddr);
|
|
||||||
perr("LE arg addr: " . $errPrintCAddrLEH . "\n");
|
|
||||||
|
|
||||||
$fp = getFileMemMapped($file); //Read the whole file to memory to make fseet/fread much faster
|
|
||||||
|
|
||||||
//Find the printk() call argument
|
|
||||||
$printkPos = findSequence($fp, hex2raw($errPrintCAddrLEH), 0, DIR_FWD, -1);
|
|
||||||
if ($printkPos === -1) {
|
|
||||||
perr("printk pos not found!\n", true);
|
|
||||||
}
|
|
||||||
perr("Found printk arg @ " . decTo32bUFhex($printkPos) . "\n");
|
|
||||||
|
|
||||||
//double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI)
|
|
||||||
fseek($fp, $printkPos - 3);
|
|
||||||
$instr = fread($fp, 3);
|
|
||||||
if (strncmp($instr, "\x48\xc7", 2) !== 0) {
|
|
||||||
perr("Expected MOV=>reg before printk error, got " . bin2hex($instr) . "\n", true);
|
|
||||||
}
|
|
||||||
$dstReg = ord($instr[2]);
|
|
||||||
if ($dstReg < 192 || $dstReg > 199) {
|
|
||||||
perr("Expected MOV w/reg operand [C0-C7], got " . bin2hex($instr[2]) . "\n", true);
|
|
||||||
}
|
|
||||||
$movPos = $printkPos - 3;
|
|
||||||
perr("Found printk MOV @ " . decTo32bUFhex($movPos) . "\n");
|
|
||||||
|
|
||||||
//now we should seek a reasonable amount (say, up to 32 bytes) for a sequence of CALL x => TEST EAX,EAX => JZ
|
|
||||||
$testPos = findSequence($fp, "\x85\xc0", $movPos, DIR_RWD, 32);
|
|
||||||
if ($testPos === -1) {
|
|
||||||
perr("Failed to find TEST eax,eax\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$jzPos = $testPos + 2;
|
|
||||||
fseek($fp, $jzPos);
|
|
||||||
$jz = fread($fp, 2);
|
|
||||||
if ($jz[0] !== "\x74") {
|
|
||||||
perr("Failed to find JZ\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$jzp = "\xEB" . $jz[1];
|
|
||||||
perr('OK - patching ' . bin2hex($jz) . " (JZ) to " . bin2hex($jzp) . " (JMP) @ $jzPos\n");
|
|
||||||
fseek($fp, $jzPos); //we should be here already
|
|
||||||
perr("Patched " . fwrite($fp, $jzp) . " bytes in memory\n");
|
|
||||||
|
|
||||||
if (!isset($argv[2])) {
|
|
||||||
perr("No output file specified - discarding data\n");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($argv[2])) {
|
|
||||||
perr("No output file specified - discarding data\n");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveStreamToFile($fp, $argv[2]);
|
|
||||||
fclose($fp);
|
|
@ -13,7 +13,7 @@
|
|||||||
echo "Insert basic USB modules..."
|
echo "Insert basic USB modules..."
|
||||||
SYNOLoadModules $USB_MODULES
|
SYNOLoadModules $USB_MODULES
|
||||||
+SYNOLoadModules "usb-storage"
|
+SYNOLoadModules "usb-storage"
|
||||||
+/addons/addons.sh early; /addons/addons.sh patches
|
+/addons/addons.sh early
|
||||||
|
|
||||||
# insert Etron USB3.0 drivers
|
# insert Etron USB3.0 drivers
|
||||||
|
|
||||||
|
@ -56,8 +56,7 @@ gzip -cd "${SCRIPT_DIR}/zImage_template.gz" > "${ZIMAGE_MOD}"
|
|||||||
dd if="${VMLINUX_MOD}" of="${ZIMAGE_MOD}" bs=16494 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
dd if="${VMLINUX_MOD}" of="${ZIMAGE_MOD}" bs=16494 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745134 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745134 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
|
|
||||||
RUN_SIZE=$(objdump -h ${VMLINUX_MOD} | sh "${SCRIPT_DIR}/calc_run_size.sh")
|
RUN_SIZE=`objdump -h ${VMLINUX_MOD} | sh "${SCRIPT_DIR}/calc_run_size.sh"`
|
||||||
size_le $RUN_SIZE | dd of=$ZIMAGE_MOD bs=15745210 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
size_le $RUN_SIZE | dd of=$ZIMAGE_MOD bs=15745210 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745244 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745244 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
# cksum $ZIMAGE_MOD # https://blog.box.com/crc32-checksums-the-good-the-bad-and-the-ugly
|
size_le $(($((16#`crc32 "${ZIMAGE_MOD}" | awk '{print$1}'`)) ^ 0xFFFFFFFF)) | dd of="${ZIMAGE_MOD}" conv=notrunc oflag=append >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
size_le $(($((16#$(php "${SCRIPT_DIR}/crc32.php" "${ZIMAGE_MOD}"))) ^ 0xFFFFFFFF)) | dd of="${ZIMAGE_MOD}" conv=notrunc oflag=append >"${LOG_FILE}" 2>&1 || dieLog
|
|
||||||
|
@ -12,14 +12,11 @@ echo -n "."
|
|||||||
# Extract vmlinux
|
# Extract vmlinux
|
||||||
/opt/arpl/bzImage-to-vmlinux.sh "${ORI_ZIMAGE_FILE}" "${TMP_PATH}/vmlinux" >"${LOG_FILE}" 2>&1 || dieLog
|
/opt/arpl/bzImage-to-vmlinux.sh "${ORI_ZIMAGE_FILE}" "${TMP_PATH}/vmlinux" >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
echo -n "."
|
echo -n "."
|
||||||
# Patch boot params
|
# Patch boot params and ramdisk check
|
||||||
/opt/arpl/patch-boot_params-check.php "${TMP_PATH}/vmlinux" "${TMP_PATH}/vmlinux-mod1" >"${LOG_FILE}" 2>&1 || dieLog
|
/opt/arpl/kpatch "${TMP_PATH}/vmlinux" "${TMP_PATH}/vmlinux-mod" >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
echo -n "."
|
|
||||||
# Patch ramdisk check
|
|
||||||
/opt/arpl/patch-ramdisk-check.php "${TMP_PATH}/vmlinux-mod1" "${TMP_PATH}/vmlinux-mod2" >"${LOG_FILE}" 2>&1 || dieLog
|
|
||||||
echo -n "."
|
echo -n "."
|
||||||
# rebuild zImage
|
# rebuild zImage
|
||||||
/opt/arpl/vmlinux-to-bzImage.sh "${TMP_PATH}/vmlinux-mod2" "${MOD_ZIMAGE_FILE}" >"${LOG_FILE}" 2>&1 || dieLog
|
/opt/arpl/vmlinux-to-bzImage.sh "${TMP_PATH}/vmlinux-mod" "${MOD_ZIMAGE_FILE}" >"${LOG_FILE}" 2>&1 || dieLog
|
||||||
|
|
||||||
echo -n "."
|
echo -n "."
|
||||||
# Update HASH of new DSM zImage
|
# Update HASH of new DSM zImage
|
||||||
|
12
kpatch/Makefile
Normal file
12
kpatch/Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
CFLAGS = -Wall -pedantic
|
||||||
|
LDFLAGS =
|
||||||
|
LIBS = /lib/x86_64-linux-gnu/libelf.a /lib/x86_64-linux-gnu/libz.a
|
||||||
|
|
||||||
|
all: kpatch
|
||||||
|
|
||||||
|
kpatch: main.o
|
||||||
|
cc $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f kpatch *.o
|
333
kpatch/main.c
Normal file
333
kpatch/main.c
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Converted from php code by Fabio Belavenuto <belavenuto@gmail.com>
|
||||||
|
*
|
||||||
|
* A quick tool for patching the boot_params check in the DSM kernel image
|
||||||
|
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
|
||||||
|
*
|
||||||
|
* The overall pattern we need to find is:
|
||||||
|
* - an CDECL function
|
||||||
|
* - does "LOCK OR [const-ptr],n" 4x
|
||||||
|
* - 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.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;
|
||||||
|
unsigned char *fileData;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void errorMsg(char *message) {
|
||||||
|
fprintf(stderr, "%s\n", message);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void errorNum() {
|
||||||
|
char str[100] = {0};
|
||||||
|
perror(str);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void elfErrno() {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((err = elf_errno()) != 0) {
|
||||||
|
fprintf(stderr, "%s\n", elf_errmsg(err));
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
//Finding a function boundary is non-trivial really as patters can vary, we can have multiple exit points, and in CISC
|
||||||
|
// there are many things which may match e.g. "PUSH EBP". Implementing even a rough disassembler is pointless.
|
||||||
|
//However, we can certainly cheat here as we know with CDECL a non-empty function will always contain one or more
|
||||||
|
// PUSH (0x41) R12-R15 (0x54-57) sequences. Then we can search like a 1K forward for these characteristic LOCK OR.
|
||||||
|
uint64_t findPUSH_R12_R15_SEQ(uint64_t start) {
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
for (i = start; i < fileSize; i++) {
|
||||||
|
if (fileData[i] == 0x41 && (fileData[i+1] >= 0x54 && fileData[i+1] <= 0x57)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
//[0xF0, 0x80, null, null, null, null, null, 0xXX],
|
||||||
|
uint64_t findORs(uint64_t start, uint32_t maxCheck) {
|
||||||
|
uint64_t i;
|
||||||
|
int c = 0;
|
||||||
|
uint8_t lb = 0x01;
|
||||||
|
|
||||||
|
for (i = start; i < fileSize; i++) {
|
||||||
|
if (fileData[i] == 0xF0 && fileData[i+1] == 0x80 && fileData[i+7] == lb) {
|
||||||
|
orPos[c++] = i;
|
||||||
|
i += 7;
|
||||||
|
lb <<= 1;
|
||||||
|
}
|
||||||
|
if (c == 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (--maxCheck == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void patchBootParams() {
|
||||||
|
uint64_t addr, pos;
|
||||||
|
uint64_t newPtrOffset, ptrOffset;
|
||||||
|
int 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)
|
||||||
|
break; //no more "functions" left
|
||||||
|
printf("\rAnalyzing f() candidate @ %lX, PUSH @ %lX", initTextOffs, addr);
|
||||||
|
//we found something looking like PUSH R12-R15, now find the ORs
|
||||||
|
n = findORs(initTextOffs, 1024);
|
||||||
|
if (n != 4) {
|
||||||
|
//We can always move forward by the function token length (obvious) but if we couldn't find any LOCK-OR tokens
|
||||||
|
// we can skip the whole look ahead distance. We CANNOT do that if we found even a single token because the next one
|
||||||
|
// might have been just after the look ahead distance
|
||||||
|
initTextOffs += 2;
|
||||||
|
if (n == 0) {
|
||||||
|
initTextOffs += 1024;
|
||||||
|
}
|
||||||
|
continue; //Continue the main search loop to find next function candidate
|
||||||
|
}
|
||||||
|
//We found LOCK(); OR ptr sequences so we can print some logs and collect ptrs (as this is quite expensive)
|
||||||
|
printf("\n[?] Found possible f() @ %lX\n", initTextOffs);
|
||||||
|
ptrOffset=0;
|
||||||
|
int ec = 0;
|
||||||
|
for (n = 0; n < 4; n++) {
|
||||||
|
//data will have the following bytes:
|
||||||
|
// [0-LOCK()] [1-OR()] [2-BYTE-PTR] [3-OFFS-b3] [4-OFFS-b2] [5-OFFS-b1] [6-OFFS-b1] [7-NUMBER]
|
||||||
|
pos = orPos[n];
|
||||||
|
//how far it "jumps"
|
||||||
|
newPtrOffset = pos + (fileData[pos+6] << 24 | fileData[pos+5] << 16 | fileData[pos+4] << 8 | fileData[pos+3]);
|
||||||
|
if (ptrOffset == 0) {
|
||||||
|
ptrOffset = newPtrOffset;
|
||||||
|
++ec;
|
||||||
|
} 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],
|
||||||
|
fileData[pos+5], fileData[pos+6], fileData[pos+7], newPtrOffset);
|
||||||
|
}
|
||||||
|
if (ec != 4) {
|
||||||
|
printf("\t[-] LOCK-OR PTR offset mismatch - %d/4 matched\n", ec);
|
||||||
|
//If the pointer checking failed we can at least move beyond the last LOCK-OR found as we know there's no valid
|
||||||
|
// sequence of LOCK-ORs there
|
||||||
|
initTextOffs = orPos[3];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("\t[+] All %d LOCK-OR PTR offsets equal - match found!\n", ec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (addr == -1) {
|
||||||
|
errorMsg("\nFailed to find matching sequences");
|
||||||
|
} else {
|
||||||
|
//Patch offsets
|
||||||
|
for (n = 0; n < 4; n++) {
|
||||||
|
//The offset will point at LOCK(), we need to change the OR (0x80 0x0d) to AND (0x80 0x25) so the two bytes after
|
||||||
|
pos = orPos[n] + 2;
|
||||||
|
printf("Patching OR to AND @ %lX\n", pos);
|
||||||
|
fileData[pos] = 0x25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
uint32_t changeEndian(uint32_t num) {
|
||||||
|
return ((num>>24)&0xff) | // move byte 3 to byte 0
|
||||||
|
((num<<8)&0xff0000) | // move byte 1 to byte 2
|
||||||
|
((num>>8)&0xff00) | // move byte 2 to byte 1
|
||||||
|
((num<<24)&0xff000000); // move byte 0 to byte 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
uint64_t findSeq(const char* seq, int len, uint32_t pos, int dir, uint64_t max) {
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
i = pos;
|
||||||
|
do {
|
||||||
|
if (strncmp((const char*)fileData+i, seq, len) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i += dir;
|
||||||
|
--max;
|
||||||
|
} while(i > 0 && i < fileSize && max > 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void patchRamdiskCheck() {
|
||||||
|
uint64_t pos, errPrintAddr;
|
||||||
|
uint64_t printkPos, testPos, jzPos;
|
||||||
|
const char str[] = "3ramdisk corrupt";
|
||||||
|
|
||||||
|
printf("Patching ramdisk check\n");
|
||||||
|
for (pos = rodataOffs; pos < fileSize; pos++) {
|
||||||
|
if (strncmp(str, (const char*)(fileData + pos), 16) == 0) {
|
||||||
|
pos -= rodataOffs;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errPrintAddr = rodataAddr + pos - 1;
|
||||||
|
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!");
|
||||||
|
}
|
||||||
|
//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 (fileData[printkPos+2] < 0xC0 || fileData[printkPos+2] > 0xC7) {
|
||||||
|
printf("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[printkPos+2]);
|
||||||
|
errorMsg("");
|
||||||
|
}
|
||||||
|
printf("Found printk MOV @ %08lX\n", printkPos);
|
||||||
|
|
||||||
|
//now we should seek a reasonable amount (say, up to 32 bytes) for a sequence of CALL x => TEST EAX,EAX => JZ
|
||||||
|
testPos = findSeq("\x85\xc0", 2, printkPos, DIR_RWD, 32);
|
||||||
|
if (testPos == -1) {
|
||||||
|
errorMsg("Failed to find TEST eax,eax\n");
|
||||||
|
}
|
||||||
|
printf("Found TEST eax,eax @ %08lX\n", testPos);
|
||||||
|
jzPos = testPos + 2;
|
||||||
|
if (fileData[jzPos] != 0x74) {
|
||||||
|
errorMsg("Failed to find JZ\n");
|
||||||
|
}
|
||||||
|
printf("OK - patching %02X%02X (JZ) to %02X%02X (JMP) @ %08lX\n",
|
||||||
|
fileData[jzPos], fileData[jzPos+1], 0xEB, fileData[jzPos+1], jzPos);
|
||||||
|
fileData[jzPos] = 0xEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct stat fileInf;
|
||||||
|
Elf_Scn *section;
|
||||||
|
GElf_Shdr sectionHeader;
|
||||||
|
char *sectionName;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
errorMsg("Use: kpatch <vmlinux> <output>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||||
|
elfErrno();
|
||||||
|
|
||||||
|
if ((fd = open(argv[1], O_RDONLY)) == -1)
|
||||||
|
errorNum();
|
||||||
|
|
||||||
|
if ((elfHandle = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||||
|
elfErrno();
|
||||||
|
if (gelf_getehdr(elfHandle, &elfExecHeader) == NULL)
|
||||||
|
elfErrno();
|
||||||
|
|
||||||
|
switch(elf_kind(elfHandle)) {
|
||||||
|
case ELF_K_NUM:
|
||||||
|
case ELF_K_NONE:
|
||||||
|
errorMsg("file type unknown");
|
||||||
|
break;
|
||||||
|
case ELF_K_COFF:
|
||||||
|
errorMsg("COFF binaries not supported");
|
||||||
|
break;
|
||||||
|
case ELF_K_AR:
|
||||||
|
errorMsg("AR archives not supported");
|
||||||
|
break;
|
||||||
|
case ELF_K_ELF:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
section = NULL;
|
||||||
|
while ((section = elf_nextscn(elfHandle, section)) != NULL) {
|
||||||
|
if (gelf_getshdr(section, §ionHeader) != §ionHeader)
|
||||||
|
elfErrno();
|
||||||
|
if ((sectionName = elf_strptr(elfHandle, elfExecHeader.e_shstrndx, sectionHeader.sh_name)) == NULL)
|
||||||
|
elfErrno();
|
||||||
|
if (strcmp(sectionName, ".init.text") == 0) {
|
||||||
|
initTextOffs = sectionHeader.sh_offset;
|
||||||
|
} else if (strcmp(sectionName, ".rodata") == 0) {
|
||||||
|
rodataAddr = sectionHeader.sh_addr & 0xFFFFFFFF;
|
||||||
|
rodataOffs = sectionHeader.sh_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elfErrno(); /* If there isn't elf_errno set, nothing will happend. */
|
||||||
|
elf_end(elfHandle);
|
||||||
|
|
||||||
|
if (fstat(fd, &fileInf) == -1)
|
||||||
|
errorNum();
|
||||||
|
|
||||||
|
fileSize = fileInf.st_size;
|
||||||
|
fileData = malloc(fileSize);
|
||||||
|
if (fileSize != read(fd, fileData, fileSize)) {
|
||||||
|
errorNum();
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
patchBootParams();
|
||||||
|
patchRamdiskCheck();
|
||||||
|
if ((fd = open(argv[2], O_WRONLY | O_CREAT, 0644)) == -1) {
|
||||||
|
errorNum();
|
||||||
|
}
|
||||||
|
if (fileSize != write(fd, fileData, fileSize)) {
|
||||||
|
errorNum();
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user