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: b6 01 00 00 36 00 00 00 9d 00 00 00 67 00 00 00 dec: 438 54 157 43 in axe we have to set the byte column width to 438 bytes to display the image correctly so: width=438 height=54 y=157 x=43 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. The palette: index hex dec RGB 00 00 00 00 0 0 0 Black 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 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