Re: Initramfs from existing vmlinuz

From: Ian Campbell
Date: Mon Jan 05 2009 - 06:13:09 EST


On Wed, 2008-12-24 at 00:34 +0100, Willy Tarreau wrote:
> You first have to extract and uncompress the ELF image from vmlinuz.
> For this, look for the gzip signature 1F 8B 08 in your vmlinuz, and
> feed all data starting from this point to zcat.

Since v2.6.26 (I think, it was v2.08 of the x86 bzImage format anyhow,
which was the same point the payload became ELF formatted) you can find
it directly using the payload_offset and payload_length fields in the
bzImage header. Attached bzexplode.c demonstrates this. e.g. "bzexplode
vmlinuz | zcat > vmlinux.elf"

Ian.

--
Ian Campbell
Current Noise: Electric Wizard - Saturn's Children

A likely impossibility is always preferable to an unconvincing possibility.
-- Aristotle
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>

#include <inttypes.h>

#include <err.h>

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>

int main(int argc, char **argv)
{
int fd;
struct stat sb;
void *p;
uint8_t *hdr;
int setup_sectors;
uint32_t compressed_payload_offset;
uint32_t compressed_payload_length;

if (argc != 2)
errx(1, "usage: bzexplode <bzImage>");

fd = open(argv[1], O_RDONLY);
if (fd < 0)
err(1, "open");

if (fstat(fd, &sb) < 0)
err(1, "fstat");

p = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
err(1, "mmap");

hdr = p;
setup_sectors = hdr[0x1f1];
compressed_payload_offset = *(uint32_t*)&hdr[0x248];

fprintf(stderr, "setup sectors %d\n", setup_sectors);

compressed_payload_offset += (setup_sectors+1) * 512;

//compressed_payload_length = *(uint32_t*)(p + compressed_payload_offset - 4);
compressed_payload_length = *(uint32_t*)&hdr[0x24c];

fprintf(stderr, "compressed_payload_offset %"PRIx32" (abs)\n",
compressed_payload_offset);
fprintf(stderr, "compressed_payload_length %"PRIx32"\n",
compressed_payload_length);

write(1,
p + compressed_payload_offset,
compressed_payload_length);
return 0;
}