VOGONS


First post, by sander

User metadata
Rank Newbie
Rank
Newbie

While looking at some VLSI VL82C483 bios dumps I stumbled upon the Dell OptiPlex 486 MTE motherboard. Within the uncompressed DELL update executable there is a bios image which is exactly 131.072 bytes (For example. 4xxLeA08.exe). As I don't own one of these machines I'm unsure if the bios is uncompressed on boot (is this even possible when the video ROM is compressed as well?) or if this image is written to ROM and is unpacked and written to ROM in a second stage update.

[EDIT]I should have mentioned that although the 'uncompressed' ROM is 131.072 bytes, the data in there is obviously compressed. There is a little section where I found the decompression routine, but to me it currently looks like that's part of the firmware update procedure.[/EDIT]

As I've reverse-engineered the decompression routine (which was cumbersome to find) I'm posting it here for archiving purposes:

/*
This routine was reverse-engineered from a compressed Dell Optiplex ROM
and is released for public domain.

It's used for older style Dell (Optiplex?) ROMs as a second stage?
decompression / deobfuscation routine. This routine is used for at least
the following systems:

OptiPlex GN Plus
OptiPlex N
OptiPlex GL Plus
OptiPlex GM Plus
OptiPlex GMT Plus
OptiPlex GXL
OptiPlex GXM
OptiPlex GXMT
OptiPlex G1
OptiPlex 486 LE
OptiPlex 486 MTE
OptiPlex 486 MXE

This is a quick and dirty implementation, it will possibly crash.
Who needs bounds checking..?

Note. this only runs on little endian machines (x86).

*/
#define _CRT_SECURE_NO_DEPRECATE

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int decompress_rom_block(const uint8_t *src, uint8_t *dst, int blk)
{
uint16_t seg_size = 0;
const uint8_t *src_end, *src_p = src, *dst_p = dst;

for (int i = 0; i < blk; i++) {
seg_size = *(uint16_t*)src_p;
src_p += 2;

if (i + 1 != blk) {
src_p += seg_size;
}
}
src_end = src_p + seg_size;

while (src_p < src_end) {
uint16_t blkofs;
uint8_t blksize, instr = *(src_p++);

if (instr & 0xf)
{
blksize = (instr & 0xf) + 1;
blkofs = (((uint16_t)instr << 4) & 0xff00) | *(src_p++);
memcpy(dst_p, dst_p - blkofs - 1, blksize);
dst_p += blksize;
}
Show last 52 lines
        else
{
blksize = (instr >> 4) + 1;
memcpy(dst_p, src_p, blksize);
dst_p += blksize;
src_p += blksize;
}
}
return dst_p - dst;
}

int main(int argc, char *argv[])
{
FILE* f;

if (argc != 4)
{
printf("Usage: %s inputfile outputfile blocknr\n", argv[0]);
exit(1);
}

f = fopen(argv[1], "rb");
if (!f) {
return -1;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);

uint8_t* src = (uint8_t * ) malloc(fsize);
if (src != NULL) {
fread(src, fsize, 1, f);
}
fclose(f);

uint8_t* dst = (uint8_t * )malloc(32768);
if (dst != NULL) {
int sz = decompress_rom_block(src, dst, atoi(argv[3]));

f = fopen(argv[2], "wb");
if (f) {
fwrite(dst, 1, sz, f);
fclose(f);
}
}

free(dst);
free(src);

return 0;
}

Original listing:

decompress_rom_block proc near
cld

loc_F49F3:
mov ax, si
shr ax, 4
mov dx, ds
add dx, ax
mov ds, dx
and si, 0Fh
lodsw
mov dx, ax
dec bl
jz short loc_F4A0C
add si, dx
jmp short loc_F49F3

loc_F4A0C:
add dx, si
sub ch, ch

loc_F4A10:
cmp si, dx
jnb short locret_F4A3F
lodsb
test al, 0Fh
jnz short loc_F4A24
shr al, 4
mov cl, al
inc cl
rep movsb
jmp short loc_F4A10

loc_F4A24:
mov cl, al
and cl, 0Fh
inc cl
sub ah, ah
shl ax, 4
lodsb
mov bx, si
mov si, di
sub si, ax
dec si
rep movs byte ptr es:[di], byte ptr es:[si]
mov si, bx
jmp short loc_F4A10

locret_F4A3F:
retn
decompress_rom_block endp