Изменение графической заставки загрузчика BeOS

Михаил Панасюк 13.02.2003 19:52


Всем знакома заставка загрузчика BeOS с зажигающимися иконками. Простая, красивая и ненавязчивая. Но если она вам все-таки надоела и вы бы хотели ее поменять или как-то по своему подкорректировать, то такая возможность действительно имеется благодаря подробному руководству, автором которого является некто Pirge.

Вы можете скачать коллекцию уже готовых заставок для R5 и Dano или заняться свободным творчеством. Все что вам нужно, так это иметь под рукой HEX-радактор и строго следовать инструкциям. В любом случае рекоммендуется создать резервную копию файла загрузчика BeOS (/boot/beos/system/zbeos) и предусмотреть возможность его аварийного восстановления (загрузка из другой копии BeOS, например с CD) в случае неудачи.

Вам понадобится знание английского языка, т.к. корректный перевод руководства на русский язык затруднен обилием в нем различных технических терминов.

Документация и коллекция готовых загрузчиков были найдены в сети Сергеем Резниковым, за что ему отдельное спасибо. Итак, приступим.

Reverse Engineering the BeOS Boot Sequence Images by Pirge 16/12/01

1. Introduction to zbeos
2. Layout of images
3. Image Format
4. Customising boot images


1. Introduction to zbeos

zbeos is the beos bootloader and kernel loader. The first 512 bytes are identical to the first 512 bytes of a linux kernel (vmlinuz). This code is basic boot sequence code. More can be learnt by looking at the linux source and the beos r3 zbeos source/object code
which is available from be ftp mirrors. This paper deals solely with the reverse engineering of the boot sequence images contained within zbeos.

From looking at the makefile for the zbeos from beos r3 zbeos source we see that zbeos is created by concatenating the boot code and two other files named beos and images. These are gzipped up (with "gzip -f -9") before concatenating.

Look at a hex dump of zbeos and search for 'images' and 'beos'. Just before these we see the following byte sequence 1f 8b 08 - from the gzip docs ( thanks Amino ;) ) we know that these are two id bytes and the compression method flag. We can use these to write a c program that will extract the gzip files from zbeos:

/////////////////////////////////////////////////////////

#include

#include


//lazy - for zbeos this is big enough

#define SIZE 2048000


static int ID1 = 0x1f;

static int ID2 = 0x8b;

static int CM = 0x08;

static int ID_BYTES = 3;


int main (int argc, char* args[]){


FILE* fin;

FILE* fout;

char outfile[50];

int i;

int numgzips = 0;

long begin = 2147438647;

long end = 0;

int buf[SIZE];

int finished = 0;

printf("*******************************************\n");

printf("*\n");

printf("* dezbeos - extracts gzip files from zbeos\n");

printf("* - bru::pirge 07-12-2001\n");

printf("* - thanks to Amino");

printf("*\n");

printf("*******************************************\n");

fin = fopen("zbeos", "rb");

if(!fin){

printf("Could not read zbeos!\nPlease run in the same directory as zbeos\n");

exit(1);

}

//read file and extract gzip files

while(!feof(fin)){

//is this a gzip file

if( fgetc(fin) == ID1 && fgetc(fin) == ID2 && fgetc(fin) == CM){

//set begin offset

begin = ftell(fin);

//count gzip files found

numgzips++;

printf("Found gzip file %d at offsets: start 0x%x ",numgzips,begin-ID_BYTES);

//save gzip we have found////////////////////////////

sprintf(outfile,"found%d.gz",numgzips);

//find end of gzip - eof or another gzip

while(!feof(fin)){

//set end offset

end = ftell(fin);

//is next a gzip id?

if( fgetc(fin) == ID1 && fgetc(fin) == ID2 && fgetc(fin) == CM){

finished = 1;

break;

}

}

//if its the end of file then set end offset

if(finished == 0)

end = ftell(fin);

//reset begin offset to include the two id bytes

//and the file pointer

begin -= ID_BYTES;

fseek(fin,begin,0);

printf("end 0x%x\n",end);

//open out file

fout = fopen(outfile,"wb");

if(!fout){

printf("could not open %s\n",outfile);

exit(1);

}

//write out the rest

fread(buf,sizeof(int),end-begin,fin);

fwrite(buf,sizeof(int),end-begin,fout);

//close new file

close(fout);

//reset file pointer

fseek(fin,end,0);

}

}

//close input

close(fin);

printf("Use: 'gzip -N -d found*.gz' to decompress the gzip files.\nFinished\n");

return 0;

}

/////////////////////////////////////////////////////////


From here we just use gzip to decompress the two files as beos and images. (You can just cut and paste the bytes for images.gz from a hex editor if you want it goes from offset 0x00010bf5 to the end of the file)


2. Layout of images

Watching the boot sequence we see that there may be five separate images: Icons, Lit Icons, BeOS text, version, logo
I guessed five separate because of, the icons lighting, the version number appearing quite separate from the other images,
for efficiency in keeping the size of zbeos low AND if you use the set VESA mode app from bebits for unsupported video cards you can watch the images move relative to each other when the screen resolution goes from 640x480 to say 1024x768.
Lets take a look.

Using the windows (shame on me) hex editor called Axe we can display the hex bytes as colours. This is fantastically useful for finding images in executables and I have found no hex editor under linux or beos which provides this functionality (there's a project).
All we have to do is know how wide the images are! The smaller images are easier to find so after some experimenting we find this:

Offset Image Dimensions

0x00000348 Row of lit icons 438 x 54

0x00005fbc Title Be Operating System 372 x 86

0x0000dcc4 Row of unlit icons 438 x 54

0x00013938 version 5 99 x 49

0x00014c3b Be logo 94 x 38


Where did I get the dimensions from?
Preceding each image data are 16 bytes (four 32 bit integers?) What are these for? What do we need to know to display images? - image data, image size, image origin and maybe a palette.

Both the icon images have the same header so it must be common information.
As we have a file with packed images and it seems reasonable to assume these are x, y coordinates and width, height sizes. for example both the icon images have these bytes preceding the image data:
(remember i386 processor has high byte last)

hex: b6010000 36000000 9d000000 67000000

dec: 438 54 157 103 // <- 103 is correct, 43 is the old wrong number

// this is a simple thing to understand

loon:

Okay, there was a bit of a messup by Pirge here. the last # should have been 103. It is the difference
of the top cordinate (157) and the image height(54) in this case, but is not always so.

The images are preceded by four numbers, converted to hex in the xx xx xx xx layout.

A hex calculator will return someting like this for 94: 0x5eh
Converted, it looks like this: 5e 00 00 00

Notice the 5e ? You will actually be needing to get in the habit of reading from the right first. Take off the h (just says it is hex formatted), and take the two preceding numbers and place them first. In this case, it is 5e.
So what we have now is 5e for the first position.

So where did 00 00 00 come from? It is actually just filler... remember we are reading from the right, so it is 00 00 00 e5 !!
So you did not modify its value by adding 00 00 00.
Just ignore the 0x.

Simple, eh? ... Not so fast! This was a simple example, let us move onto something more advanced: 400
Here, you can use a hex calculator. It will return 0x190h or something similar. Now notice there are three numbers before the h flag.

So you might expect it to be: 19 00 00 00... but it is not.. that would be 25! (0x19h)
You may also expect it to be: 90 10 00 00... but, alas, it is not either... 4240!! (0x1090h)

You should come up with 90 01 00 00.
As you can tell, this is an important item to understand!

A shortcut:

Take the two numbers just before the h ...how about in 0x2710h.. You get 10.

That is the first block!! So now you have:..


10 xx xx xx


Now take the two numbers to the left of those two numbers.. 27.. and that is your second block


10 27 xx xx


Now, whenever you hit 0x, you will in with ZEROs.


So, what do you do when you have something like 0x287h ??

If you come up with 87 20 00 00.. your wrong.. you need to remember that 2 is actually 02!! and 9 is 09..but 87 is 87.

So here you would come up with 87 02 xx xx .. but then you hit the x, which tells you to substitue the remainder with
the number it is hugging (0).. so you come up with 87 02 00 00


This is the info for a 93x38 pixel image you want to have centered at the bottom of the screen.
First you need to convert the width and height as aforementioned.

WIDTH (94)
5e 00 00 00

HEIGHT (38)
26 00 00 00

Now, we need to figure out where we need to place the image.

Since we want to hug it to the bottom, and center it, it is pretty easy.

Xc will be where we throw the X coordinate for the final image placement
Xmax is not our choice, it is 640
W is the width of the image ( in this example, 94)

The formula:


Xc=((Xmax / 2) - (W / 2))


With the valus plugged in:


Xc=((640 / 2) - (94 / 2))


Xc=((320) - (47))

Xc=273


Now, because we want to put this on the bottom of the screen, we do this:

Yc=((Ymax) - (H))


Yep, that is it.


Yc=((480) - (38))

Yc=442

So we now need to tell the zbeos image file this about our new image:

W H X Y

94 38 273 442

Middle Bottom


But, it doesn't undertstand that.. we need to speak a foreign language.. so we translate..

5e 00 00 00
26 00 00 00
11 01 00 00
ba 01 00 00

You then enter them in place of the old information.. depending on which images you were replacing.

Of course it will look like this when you put it in the file:

5e 00 00 00 26 00 00 00 11 01 00 00 ba 01 00 00

hmm.. lovely!


/loon

in axe we have to set the byte column width to 438 bytes to display the image correctly so:
width=438 height=54 x=157 y=43 // Pirge had the x and y backwards, but in the right places ;-0

Now we know how to specify image dimensions and we know there are five images in the file.
What about the file format of the images?


3. Image Format

The image data looks like a byte per pixel (ie 8 bits per pixel image = paletted bitmap image) but closer inspection reveals that that every byte of the image has 4 bits of info and four bits zero (00-0F only) so each byte must be an index into a 16 colour palette.

A colour palette is made up of potentially 256 24 bit colour values (1 byte each for RGB) so a palette is 256 * 3 = 768 bytes and the palette usually directly precedes the image data. The images here are packed together so the palette will be at the start of the file.
Looking at the hex dump we see 0x00000048 - 0x00000348 looks like a palette with 16 colors specified and the rest set to black.

loon: Please note, everything below in ()s are my comments/corrections


The palette:


index hex dec RGB

00 00 00 00 0 0 0 Black (Wrong.. it is actually Transparent,

the bg color just happened to be black as it was)

01 98 00 33 152 0 51 Brown

02 66 00 33 102 0 51 Purple

03 cb 33 cb 203 51 203 Light Pink

04 98 33 cb 152 51 203 Light Purple

05 cb 66 ff 203 102 255 Light Pink

06 66 33 98 102 0 152 Purple

07 33 00 66 51 0 102 Dark Purple

08 00 33 cb 0 51 203 Cyan

09 00 33 98 0 51 152 Blue

0a 00 33 66 0 51 102 Blue

0b ff 98 98 255 152 152 Light Red

0c ff ff ff 255 255 255 White (Umm.. try this.. *THIS IS BLACK*./.

Not sure why.. but it is!)

0d 80 80 80 128 128 128 Grey

0e 50 50 50 80 80 80 Dark Grey

0f cc 00 33 204 128 51 Red


The first entry appears to be used as the background colour

Now we have everything we need to customise the boot images:
image format, image header (dimensions), image palette.


4. Customising boot images

I am working on an app to perform all the following steps but until then
to make our own custom boot images we need to do the following:

- take the RGB images you wish to use

- convert to index colour with 4 bits per pixel (16 colours).
I have constructed a palette, beboot.act, in Photoshop that matches the palette in images.
If you are using Photoshop when it prompts for the palette select Custom and load the beboot.act palette.
This ensures that the image data points to the correct index in the palette. If you are replacing all
the boot images you can of course use your own palette.
As all the boot images use one palette though you must make sure you use the same palette when creating all your images.

- convert image to RAW data format. Photoshop (windows) allows this and maybe The GIMP(linux).
This results in a file with just the raw image bytes. Other formats are not good as they compress
or invert the image data.

- record the dimensions of your images and save the custom palette.

- the tedious bit:

Image Data:
replace the image data of the standard boot images in 'images' with the data from the RAW custom images.

Image Dimensions:
if your images are new sizes or new coordinates edit the dimensions (careful with byte order).

Image Palette:
if your images use a different palette from the standard then you must edit the palette in images header
to match your custom palette.

- When the file is remade with the new custom images ensure it is named 'images' otherwise beos will not find it.

- gzip up images using 'gzip -f -9 images' to give you images.gz

- take a copy of zbeos and name it zbeos.custom. Find the start of the images file (offset 0x00010bf5).
Cut all the bytes from here to the end of the file. Then paste the whole of images.gz to the end (or cat it).

- Copy /boot/beos/bin/makebootfloppy to the same directory as zbeos.custom and edit it to use zbeos.custom
rather than zbeos. Write a boot floppy using your new script, reboot from the floppy and enjoy you new images!

- Once you have tesed from a boot floppy you can overwrite the zbeos in /boot/beos/system on your harddrive.

pirge
bru - http://pirge.cjb.net

 

Hosted by uCoz