| Cinema software |
< Toturials & guides

Netgemova programska oprema (firmware) - nepopolno

Naprava Netgem 8200 je pri uporabnikih Telekomove ip televizije bolj poznana pod imenom Siol Box. Gre za napravo na kateri teče Linux operacijski sistem. Modificirano jedro in (skoraj) vsa orodja, ki so pod GPL licenco so na voljo na naslovu: http://www.netgem.com/linux-community.php.

Da lahko raziščemo Siolovo različico firmwara, ga je potrebno najprej dekriptirati.
Posodobitve za Siolovo različico programske opreme se nahajajo na naslovu: http://box-fw.siol.tv. V času pisanja je bil naslov sledeč:
http://box-fw.siol.tv/upgrade/sioltv/n17-1/5.3.01-117/upgrade.bin.
Kot je vidno iz naslova povezave, gre za različico 5.3.01-117.

Trenutne funkcije (branje minix particije), omenjene v nadaljevanju, ne delujejo 100% in zato ni mogoče dekriptirati vseh datotek.

Programska oprema je sestavljena iz več različnih delov. Vse te dele se dekriptira po naslednjem postopku:

#include <stdio.h>

unsigned long DataDecode(unsigned long k,unsigned char *data,int len) {
	unsigned long newk;
	unsigned int c;
	newk=k;
	for (c=0;c<len;c++) {
			newk=(newk*0x41c64e71)+1;
			data[c]=data[c]^((newk>>16)&0xff);

	}

	return newk;
}

void extract_data(unsigned char *fname,unsigned long offseti,unsigned long len) {
	int k=0;
	int a,b,btogo,toread;
	FILE *fp;
	FILE *fpo;
	unsigned char buf[1024];
	b=1;
	btogo=len;
	fp=fopen("upgrade.bin","rb");
	fpo=fopen(fname,"wb");
	fseek(fp,offseti,SEEK_SET);

	// following IF statement didn't work in LCC.. you can uncomment this
	// and it simply won't bother checking that upgrade.bin has opened
	if ((fp>0) && (fpo>0)) {
		while ((b>0) && (btogo>0)) {
			if (btogo>sizeof(buf)) toread=sizeof(buf); else toread=btogo;
				b=fread(buf,1,toread,fp);
				btogo=btogo-b;
				if (b>0)
				{
					k=DataDecode(k,buf,b);
					fwrite(buf,1,sizeof(buf),fpo);
				}
		   }
	} else printf("Failed to open upgrade.bin for decoding.n");

	fclose(fp);
	fclose(fpo);
}

// offsets for 5.3.01-117 (siol)
int main() {
	// From standard Netgem's header =====================================

	extract_data("part_partition.img", 0x000700, 0x2E); // partition table

	extract_data("part_upgrade.img",   0x00072E, 0x079cb0); //upgrade

	// ===================================================================



	extract_data("part_ngu.img",       0x07A3DE, 0x70); // ngu

	extract_data("part_firmware.img",  0x07a44e, 0xA0414); // firmware

	////// Blank of 12 bytes (padding ??) CONSTANT in all images

	extract_data("part_elf.img",       0x11a86e, 0x004368);

	//// Offset - probably not constant

	extract_data("part_usr.img",       0x11ebde, 0x7c0000); // minixfs 1 (multiple 0xff at the end ) 

	extract_data("part_bios.img",      0x8DEBDE, 0x40000);  // 0x40000 Constant size

	extract_data("part_root.img",      0x91EBDE, 0xffffff); // minixfs 2

	return 0;
}

Pri vsaki različici so meje med posameznimi particijami seveda različne in jih je potrebno ugotoviti. To bi se sicer dalo urediti tudi programsko, vendar bom zaenkrat podal le "ročni" opis postopka.

Datoteka upgrade.bin je sestavljena iz naslednjih delov, ki so pri vseh različicah v istem vrstnem redu:

* Root in usr particiji sta včasih zamenjani.

Vsaka firmware različica se začne z glavo enakega formata:

hexdump -n 1792 -C upgrade_5_3_01_117.bin
00000000  4e 47 55 47 31 41 59 26  35 2e 33 2e 30 31 00 00  |NGUG1AY&5.3.01..|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  73 69 6f 6c 74 76 00 00  |........sioltv..|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000080  00 00 00 00 00 00 00 01  00 00 00 00 00 00 00 00  |................|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000000c0  00 00 00 00 00 00 00 00  01 51 eb de 00 00 05 80  |.........Q......|
000000d0  00 00 00 2e c2 d9 6f a4  f8 bb b9 73 10 fa 09 e6  |......o....s....|
000000e0  a8 c6 32 32 2c 67 84 11  00 07 9c b0 57 e5 88 ec  |..22,g......W...|
000000f0  ed 37 cf f7 85 e3 45 d1  9e 10 64 4e 3e 7e 0e b2  |.7....E...dN>~..|
00000100  00 00 00 00 00 00 00 90  85 dc 24 71 3a b0 4a 6f  |..........$q:.Jo|
00000110  7f 9c 29 af 7c 0e 6b c5  f4 19 82 f9 da a7 46 d5  |..).|.k.......F.|
00000120  90 c3 df a5 76 a6 8a d6  00 00 00 00 00 00 01 00  |....v...........|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000180  30 82 05 6e 06 09 2a 86  48 86 f7 0d 01 07 02 a0  |0..n..*.H.......|
00000190  82 05 5f 30 82 05 5b 02  01 01 31 0f 30 0d 06 09  |.._0..[...1.0...|
000001a0  60 86 48 01 65 03 04 02  01 05 00 30 0b 06 09 2a  |`.H.e......0...*|
000001b0  86 48 86 f7 0d 01 07 01  a0 82 03 8e 30 82 03 8a  |.H..........0...|
000001c0  30 82 02 72 a0 03 02 01  02 02 03 01 00 0c 30 0d  |0..r..........0.|
000001d0  06 09 2a 86 48 86 f7 0d  01 01 0b 05 00 30 72 31  |..*.H........0r1|
000001e0  0b 30 09 06 03 55 04 06  13 02 46 52 31 0c 30 0a  |.0...U....FR1.0.|
000001f0  06 03 55 04 08 13 03 49  44 46 31 0e 30 0c 06 03  |..U....IDF1.0...|
00000200  55 04 07 13 05 50 61 72  69 73 31 14 30 12 06 03  |U....Paris1.0...|
00000210  55 04 0a 13 0b 4e 65 74  67 65 6d 20 53 2e 41 2e  |U....Netgem S.A.|
00000220  31 0f 30 0d 06 03 55 04  03 13 06 4e 45 54 47 45  |1.0...U....NETGE|
00000230  4d 31 1e 30 1c 06 09 2a  86 48 86 f7 0d 01 09 01  |M1.0...*.H......|
00000240  16 0f 69 6e 66 6f 40 6e  65 74 67 65 6d 2e 63 6f  |..info@netgem.co|
00000250  6d 30 1e 17 0d 31 30 30  35 32 35 31 33 35 37 35  |m0...10052513575|
00000260  36 5a 17 0d 32 30 30 35  32 32 31 33 35 37 35 36  |6Z..200522135756|
00000270  5a 30 75 31 0b 30 09 06  03 55 04 06 13 02 73 69  |Z0u1.0...U....si|
00000280  31 11 30 0f 06 03 55 04  08 13 08 53 6c 6f 76 65  |1.0...U....Slove|
00000290  6e 69 61 31 12 30 10 06  03 55 04 07 13 09 4c 6a  |nia1.0...U....Lj|
000002a0  75 62 6c 6a 61 6e 61 31  0f 30 0d 06 03 55 04 0a  |ubljana1.0...U..|
000002b0  13 06 73 69 6f 6c 74 76  31 0f 30 0d 06 03 55 04  |..sioltv1.0...U.|
000002c0  03 13 06 73 69 6f 6c 74  76 31 1d 30 1b 06 09 2a  |...sioltv1.0...*|
000002d0  86 48 86 f7 0d 01 09 01  16 0e 70 6b 69 40 6e 65  |.H........pki@ne|
000002e0  74 67 65 6d 2e 63 6f 6d  30 82 01 22 30 0d 06 09  |tgem.com0.."0...|
000002f0  2a 86 48 86 f7 0d 01 01  01 05 00 03 82 01 0f 00  |*.H.............|
00000300  30 82 01 0a 02 82 01 01  00 c5 92 8c a7 94 09 a9  |0...............|

Opis nekaterih vrednosti
Dolžina glave je 0x180, ki se nato nadaljuje z certifikatom. V oklepaju so vrednosti za različico 5.3.01-117

Za izračun odmikov ostalih particij, si z zgornjimi informacijami ne moremo pomagati.

Naslednji del je ngu.img. Začetek je takoj za upgrade.img ali pa je vmes nekaj bajtov z vrednostjo 0x0. Velikost se preprosto ugotovi tako, da se najprej dekodira malo večja velikost in se nato pogleda kje se konča dolgo zaporedje 00.

hexdump -C part_ngu.img
00000000  4e 47 55 47 53 43 31 26  00 00 00 00 00 80 00 00  |NGUGSC1&........|
00000010  00 00 00 00 00 c0 00 00  00 00 00 00 01 40 43 68  |.............@Ch|
00000020  00 00 00 11 00 0a 03 f4  00 00 00 04 00 00 00 01  |................|
00000030  35 2e 33 2e 30 31 00 00  00 00 00 00 00 00 00 00  |5.3.01..........|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  73 69 6f 6c 74 76 00 00  00 00 00 00 00 00 00 00  |sioltv..........|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  4f 46 c1 ad bf da 34 a0  8c f8 e4 a4 2c 30 0f b2  |OF....4.....,0..|
00000080  9d ef 1d 08 bf da 34 a0  8c f8 e4 a4 2c 30 0f b2  |......4.....,0..|
( Konec ngu.img dela je viden pri 0x70. )

Temu sledi firmware.img, ki se vedno konča z 12 bajti 0x0. V tem primeru je začetek pri 0x07a44e dolžina pa je 0xA0413 bajtov.

hexdump -s 0x11a862 -n 32 -C upgrade_5_3_01_117.bin
0011a862  00 00 00 00 00 00 00 00  00 00 00 00 7f 83 d7 a1  |................|
0011a872  10 d5 fc 99 9f f6 00 82  0e cd c2 7c 36 6b d9 d0  |...........|6k..|
( 12 x 00 med firmware.img ter elf.img )

Dolžino elf.img najlažje ugotovimo s pomočjo readelf, ki obstaja tudi v različici za Windows (readelf.exe).

readelf -e part_elf.img
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          9556 (bytes into file)
  Flags:                             0x70001001, noreorder, o32, mips32r2
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         18
  Section header string table index: 15

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .reginfo          MIPS_REGINFO    00000000 000034 000018 18   A  0   0  4
  [ 2] .text             PROGBITS        00000000 000050 001fb0 00  AX  0   0 16
  [ 3] .rel.text         REL             00000000 002f18 001388 08     16   2  4
  [ 4] .modinfo          PROGBITS        00000000 002000 000090 00   A  0   0  4
  [ 5] .rodata.str1.4    PROGBITS        00000000 002090 000248 01 AMS  0   0  4
  [ 6] .rodata.cst4      PROGBITS        00000000 0022d8 00000c 04  AM  0   0  4
  [ 7] .rel.rodata.cst4  REL             00000000 0042a0 000018 08     16   6  4
  [ 8] .data             PROGBITS        00000000 0022f0 000080 00  WA  0   0 16
  [ 9] .rel.data         REL             00000000 0042b8 000058 08     16   8  4
  [10] .sbss             NOBITS          00000000 002370 000000 00 WAp  0   0  4
  [11] .bss              NOBITS          00000000 002370 000020 00  WA  0   0 16
  [12] .pdr              PROGBITS        00000000 002370 000160 00      0   0  4
  [13] .rel.pdr          REL             00000000 004310 000058 08     16  12  4
  [14] .mdebug.abi32     PROGBITS        00000000 0024d0 000000 00      0   0  1
  [15] .shstrtab         STRTAB          00000000 0024d0 000083 00      0   0  1
  [16] .symtab           SYMTAB          00000000 002824 000410 10     17  34  4
  [17] .strtab           STRTAB          00000000 002c34 0002e1 00      0   0  1
( Dolžina dela elf.img je v tem primeru 0x4310+0x58 )

Temu delu sledi datotečni sistem minix. Če začetku elf.img prištejemo 0x4310+0x58, vidimo, da se na tej lokaciji nahaja zaporedno 8x vrednost 00. Začetek prve minix particije se v tem primeru prične pri 0x11ebde.

 hexdump -s 0x11ebc9 -n 32 -C upgrade_5_3_01_117.bin
0011ebc9  f4 9c 2a 5b 46 c4 b8 97  4f 74 4c 8b 8b 00 00 00  |..*[F...OtL.....|
0011ebd9  00 00 00 00 00 61 7a 01  1b 11 d4 fc 99 11 b1 8a  |.....az.........|
( Pričetek prve minix particije. )

hexdump -n 6144 -C part_usr.img
00000000  61 bc 9a fc 00 00 01 00  8e 47 8a 53 48 b3 b5 4f  |a........G.SH..O|
00000010  3b fc af a0 38 61 89 71  7f 29 08 88 ed 73 fd b4  |;...8a.q.)...s..|
00000020  ad b5 02 b8 1d a1 39 28  e5 1d 69 6f a1 1a 46 0d  |......9(..io..F.|
00000030  3d 7e 5f a3 63 2b 08 a2  bd be fc 01 63 23 87 19  |=~_.c+......c#..|
00000040  a1 eb 6a a4 57 9a ab 11  90 7b a6 41 d7 0a 08 aa  |..j.W....{.A....|
00000050  fa 76 f0 d1 fa 23 ac bc  53 4a f5 ba 14 2c 75 86  |.v...#..SJ...,u.|
00000060  ed 1d 8b 75 d8 b1 0b 2d  20 9f c5 21 ff c3 cd 13  |...u...- ..!....|
00000070  3e 7e 10 78 3b 93 6b f3  a2 cc 3b 0f b4 f1 68 0e  |>~.x;.k...;...h.|
00000080  a3 db 47 48 1c fe cb a2  75 ce 5c 6b dd 7b df e0  |..GH....u.\k.{..|
00000090  ff 89 04 31 20 49 9f 1b  b7 e4 b3 0a 14 cf b2 ac  |...1 I..........|
000000a0  73 3f bf 63 72 e3 7d 8d  af 62 bf dc a8 73 55 54  |s?.cr.}..b...sUT|
000000b0  80 a4 87 f6 26 cb 9f 14  0d 48 87 5c a6 96 90 2a  |....&....H.\...*|
000000c0  88 d4 5f 06 88 6d 1a e8  74 f5 ff 75 b9 9f af ae  |.._..m..t..u....|
000000d0  c4 c0 e3 db dd 5b 50 b1  23 be 3d 05 4e 71 d6 d4  |.....[P.#.=.Nq..|
000000e0  e6 3e 40 f0 c6 d6 08 ba  12 78 e8 9c f0 79 fe 1d  |.>@......x...y..|
000000f0  11 84 9a b7 d9 79 07 c3  10 af b9 3f 32 f8 96 14  |.....y.....?2...|
00000100  dd 70 7d 57 a4 a2 fb 41  1d af e9 18 47 e8 c6 cc  |.p}W...A....G...|
00000110  2e c8 93 60 3a 3d f2 0f  76 3e 4c 07 9d d3 cf 10  |...`:=..v>L.....|
00000120  39 49 d3 e5 6f 14 8a d5  00 7b fc 00 00 00 00 00  |9I..o....{......|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  00 02 00 00 01 00 01 00  14 00 00 00 ff ff ff 7f  |................|
00000410  e1 38 01 00 7f 0f 00 00  00 00 00 00 00 08 00 00  |.8..............|
00000420  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000005d0  72 6f 6f 74 00 00 00 00  00 00 00 00 00 00 00 00  |root............|
000005e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000005f0  00 00 00 00 00 00 00 00  00 00 00 00 01 00 1e c7  |................|
00000600  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00001020  ff 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00001030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
( Pričetek dekodirane prve minix particije )

Za pridobitev ostalih delov moramo sedaj ugotoviti velikost te particije. Konec particije lahko prepoznate po večjem številu 0xff zaporedja ali pa zaženite orodje readminixfs, ki pokaže velikost enega bloka ter skupno število blokov. Velikost particije je (št.blokov+1) * (dolžina 1 bloka).

Netgem je vse do različice 4..4.2 (utils-netgem-4.4.2.tar.bz2) prilagal tudi izvorno kodo orodja za branje minix particije.To orodje NE deluje pri različicah > 5.3.x, saj je sedaj uporabljena višja minix različica (2.5).

Readminixfs.c sem spremenil tako, da sedaj podpira bloke z večjo velikostjo kot 1024 ter 4 bajtne kazalce na bloke. Trojnih indirektnih blokov nisem implementiral. Nekatere datoteke prebrane s tem orodjem so identične, čeprav imajo različna imena, nekaj pa je tudi izpuščenih. To je najveretneje posledica napačne implementacije, saj nisem nikjer našel specifikacij za minix različico 2.5. Zanimivo je, da nekateri vnosi direktorijev/datotek vsebujejo isto številko "Inode". Tega si ne znam razložiti, saj naj bi vsak "Inode" predstavljal svojo datoteko oz. direktorij.

hexdump -s 0xc460 -n 2000 -C part_usr.img
0000c460  d5 00 73 79 6e 63 00 00  00 00 00 00 00 00 00 00  |..sync..........|
0000c470  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c480  d5 00 74 65 65 00 00 00  00 00 00 00 00 00 00 00  |..tee...........|
0000c490  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c4a0  d5 00 74 65 73 74 00 00  00 00 00 00 00 00 00 00  |..test..........|
0000c4b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c4c0  d5 00 74 6f 75 63 68 00  00 00 00 00 00 00 00 00  |..touch.........|
0000c4d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c4e0  d5 00 74 72 75 65 00 00  00 00 00 00 00 00 00 00  |..true..........|
0000c4f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c500  d5 00 75 6e 61 6d 65 00  00 00 00 00 00 00 00 00  |..uname.........|
0000c510  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c520  d5 00 75 6e 69 71 00 00  00 00 00 00 00 00 00 00  |..uniq..........|
0000c530  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000c540  d5 00 75 73 6c 65 65 70  00 00 00 00 00 00 00 00  |..usleep........|
(Ker imajio vse datoteke isto Inode številko, so vsebine teh datotek prebrane iz napačne lokacije !?)

Razlike med readminixfs.h 4.4.2 in 5.3x implementacijo:
 --- orig-readminix/readminixfs.h    2004-02-23 15:00:00.000000000 +0100
+++ readminixfs.h    2013-11-26 21:12:20.000000000 +0100
@@ -30,8 +30,13 @@
 #define MINIX2_SUPER_MAGIC2_REV     0x7824
 #define MINIX2_SUPER_MAGIC2_COMPR_REV  0x8824
 
-#define INODE_PER_BLOCK_V1 32
-#define INODE_PER_BLOCK_V2 16
+#define MINIX25_SUPER_MAGIC2      0x38D1 /* minix V2.5 fs, 30 char names */
+#define MINIX25_SUPER_MAGIC2_COMPR 0x38E1 /* minix V2.5 fs, 30 char names, comp */
+#define MINIX25_SUPER_MAGIC2_REV      0xD138 /* minix V2.5 fs, 30 char names */
+#define MINIX25_SUPER_MAGIC2_COMPR_REV 0xE138 /* minix V2.5 fs, 30 char names, comp */
+
+/*#define INODE_PER_BLOCK_V1 32
+#define INODE_PER_BLOCK_V2 16 */
 
 #define ROOT_INODE 1
 #define MINIX_HEADER_SIZE 7
@@ -49,6 +54,22 @@
     u_short magic;
     u_short clean;
     u_long nb_zone_v2;
+    u_short s_magic_v3;       /* only used on v3 */
+    u_short s_pad2;           /* only used on v3 */
+    u_short s_blocksize;      /* used on v2.5 and v3 */
+    u_char  s_disk_version;   /* only used on v3 */
+    u_char  s_res0;
+    /* 0x20 */
+    u_char  s_pad[0x1C0 - 0x020];
+    /* 0x1C0 */
+    /* Additional structure, for Netgem extensions */
+    u_char ng_uuid[16];  /* 128 bits UUID */
+    u_char  ng_label[16]; /* volume label  */
+    /* 0x1E0 */
+    u_char  ng_pad0[28];
+#define MINIX_NG_FLAG_RO 0x0001
+    u_char ng_flags;
+    u_char ng_magic; 
 } mx_sb_disk;
 
 typedef struct {
@@ -61,6 +82,7 @@
     int max_file_size;
     int magic;
     int clean;
+    int s_blocksize;
 
     /* fieds only in memory */
     u_char *inode_map;
@@ -87,6 +109,25 @@
     u_short zone[9];
 } mx_inode_disk; /* size : 32 bytes */
 
+/* exact mapping of minix V2 inode */
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+typedef struct {
+    u_short mode;
+    u_short nlinks;
+    u_short uid;
+    u_short gid;
+    u_long size;
+    u_long atime;
+    u_long mtime;
+    u_long ctime;
+    u_long zone[10];
+} mx2_inode_disk; 
+
 typedef struct {
     int inode_num;
     int mode;
@@ -95,11 +136,11 @@
     int size;
     int time;
     int nb_link;
-    int raw_zone[9];
-    int nb_data_zone;
-    int nb_indirect_zone;
-    int *data_zones;
-    int *indirect_zones; /* 8th zone, 9th zone and 9th content */
+    u_long raw_zone[10];
+    u_long nb_data_zone;
+    u_long nb_indirect_zone;
+    u_long *data_zones;
+    u_long *indirect_zones; /* 8th zone, 9th zone and 9th content */
     char compressed; /* 0 not compressed, 1 compressed */
 } mx_inode_info;
 


Razlike med readminixfs.c 4.4.2 in 5.3x implementacijo:
 --- orig-readminix/readminixfs.c    2004-02-23 15:00:00.000000000 +0100
+++ readminixfs.c    2013-11-26 09:17:50.000000000 +0100
@@ -19,6 +19,9 @@
 #include "readminixfs.h"
 
 char errormsg[1024];    /* global variable, but used only for error output */
+u_long block_size=BLOCK_SIZE;
+u_long inode_per_block_v1=BLOCK_SIZE/sizeof(mx_inode_disk);
+u_long inode_per_block_v2=BLOCK_SIZE/sizeof(mx2_inode_disk);
 
 static u_short swap_s(u_short us)
 {
@@ -97,7 +100,7 @@
 }
 #endif
 
-static int readBlock(int fd, int blocknum, u_char *dst, int size)
+static int readBlock(mx_device *pDev, int fd, int blocknum, u_char *dst, int size)
 {
     int res, nbread;
 
@@ -106,7 +109,10 @@
         memset(dst, 0, size);
         return 0;
     }
-    res = lseek(fd, blocknum * 1024, SEEK_SET);
+    if (blocknum>1)
+        res = lseek(fd, blocknum * pDev->super->s_blocksize, SEEK_SET);
+    else
+         res = lseek(fd, 1024, SEEK_SET);       
     if (res < 0) return res;
     nbread = 0;
     while (nbread < size) {
@@ -125,8 +131,12 @@
     mx_sb_disk phys_sb;
     mx_sb_info *log_sb;
 
-    pDev->super = log_sb = NULL;
-    if (readBlock(pDev->fd, 1, (u_char*) &phys_sb, sizeof(mx_sb_disk))) {
+    log_sb = malloc(sizeof(mx_sb_info));
+    if (log_sb == NULL)
+        goto fail;
+    log_sb->s_blocksize=0;
+    pDev->super = log_sb;
+    if (readBlock(pDev, pDev->fd, 1, (u_char*) &phys_sb, sizeof(mx_sb_disk))) {
         snprintf(errormsg, sizeof(errormsg), "can\'t read superblock");
         goto fail;
     }
@@ -138,14 +148,15 @@
         && magic != MINIX_SUPER_MAGIC2_COMPR
         && magic != MINIX_SUPER_MAGIC2_COMPR_REV
         && magic != MINIX2_SUPER_MAGIC2_COMPR
-        && magic != MINIX2_SUPER_MAGIC2_COMPR_REV ) {
+        && magic != MINIX2_SUPER_MAGIC2_COMPR_REV 
+        && magic != MINIX25_SUPER_MAGIC2_COMPR
+        && magic != MINIX25_SUPER_MAGIC2_COMPR_REV
+        && magic != MINIX25_SUPER_MAGIC2_COMPR
+        && magic != MINIX25_SUPER_MAGIC2_COMPR_REV )
+        {
         snprintf(errormsg, sizeof(errormsg), "superblock : unknown magic");
         goto fail;
     }
-    log_sb = malloc(sizeof(mx_sb_info));
-    if (log_sb == NULL)
-        goto fail;
-    pDev->super = log_sb;
     log_sb->inode_map = NULL;
     log_sb->zone_map = NULL;
     log_sb->magic = magic;
@@ -161,24 +172,36 @@
         || magic == MINIX_SUPER_MAGIC2_COMPR
         || magic == MINIX_SUPER_MAGIC2_COMPR_REV
         || magic == MINIX2_SUPER_MAGIC2_COMPR
-        || magic == MINIX2_SUPER_MAGIC2_COMPR_REV )
+        || magic == MINIX2_SUPER_MAGIC2_COMPR_REV 
+        || magic == MINIX25_SUPER_MAGIC2
+        || magic == MINIX25_SUPER_MAGIC2_COMPR     
+        || magic == MINIX25_SUPER_MAGIC2_REV
+        || magic == MINIX25_SUPER_MAGIC2_COMPR_REV       
+        )
         log_sb->long_name = 1;
     else
         log_sb->long_name = 0;
     if (magic == MINIX_SUPER_MAGIC_REV || magic == MINIX_SUPER_MAGIC2_REV
         || magic == MINIX2_SUPER_MAGIC_REV || magic == MINIX2_SUPER_MAGIC2_REV
         || magic == MINIX_SUPER_MAGIC2_COMPR_REV
-        || magic == MINIX2_SUPER_MAGIC2_COMPR_REV )
+        || magic == MINIX2_SUPER_MAGIC2_COMPR_REV
+        || magic == MINIX25_SUPER_MAGIC2_REV
+        || magic == MINIX25_SUPER_MAGIC2_COMPR_REV    
+        )
         log_sb->must_swap = 1;
     else
         log_sb->must_swap = 0;
     if (magic == MINIX_SUPER_MAGIC2_COMPR
         || magic == MINIX_SUPER_MAGIC2_COMPR_REV
         || magic == MINIX2_SUPER_MAGIC2_COMPR
-        || magic == MINIX2_SUPER_MAGIC2_COMPR_REV )
+        || magic == MINIX2_SUPER_MAGIC2_COMPR_REV 
+        || magic == MINIX25_SUPER_MAGIC2_COMPR 
+        || magic == MINIX25_SUPER_MAGIC2_COMPR_REV          
+        )
         log_sb->compressed = 1;
     else
         log_sb->compressed = 0;
+  
     swap = log_sb->must_swap;
     if (swap) {
         log_sb->nb_inode = swap_s(phys_sb.nb_inode);
@@ -191,6 +214,15 @@
         log_sb->block_per_zone = 1 << swap_s(phys_sb.log_zone_size);
         log_sb->max_file_size = swap_l(phys_sb.max_file_size);
         log_sb->clean = swap_s(phys_sb.clean);
+        if (log_sb->minix_version >=2)
+        {
+            log_sb->s_blocksize=swap_s(phys_sb.s_blocksize);   
+            inode_per_block_v2 = log_sb->s_blocksize/sizeof(mx2_inode_disk);
+            printf("sBlock size is: %d\n", log_sb->s_blocksize);
+            printf("Inodes per block: %d\n", inode_per_block_v2);
+        }
+        else
+          log_sb->s_blocksize = BLOCK_SIZE; 
     } else {
         log_sb->nb_inode = phys_sb.nb_inode;
         log_sb->nb_zone = phys_sb.nb_zone;
@@ -202,21 +234,31 @@
         log_sb->block_per_zone = 1 << phys_sb.log_zone_size;
         log_sb->max_file_size = phys_sb.max_file_size;
         log_sb->clean = phys_sb.clean;
+        if (log_sb->minix_version >=2)
+        {
+            log_sb->s_blocksize=phys_sb.s_blocksize;  
+            inode_per_block_v2 = log_sb->s_blocksize/sizeof(mx2_inode_disk);            
+            printf("Block size is: %d\n", log_sb->s_blocksize);
+            printf("Inodes per block: %d\n", inode_per_block_v2);   
+        }
+        else
+           log_sb->s_blocksize = BLOCK_SIZE; 
     }
     /* and now, copy maps */
-    map = malloc(log_sb->nb_inode_map * BLOCK_SIZE);
+    printf("b_inode map: %d nb_zone_map: %d \n", log_sb->nb_inode_map, log_sb->nb_zone_map);
+    map = malloc(log_sb->nb_inode_map * log_sb->s_blocksize);
     if (map == NULL)
         goto fail;
     for (i=0 ; i < log_sb->nb_inode_map ; i++)
-        if (readBlock(pDev->fd, 2 + i, map + i * BLOCK_SIZE, BLOCK_SIZE))
+        if (readBlock(pDev, pDev->fd, 2 + i, map + (i * log_sb->s_blocksize), log_sb->s_blocksize))
             goto fail;
     log_sb->inode_map = map;
-    map = malloc(log_sb->nb_zone_map * BLOCK_SIZE);
+    map = malloc(log_sb->nb_zone_map * log_sb->s_blocksize);
     if (map == NULL)
         goto fail;
     for (i=0 ; i < log_sb->nb_zone_map ; i++)
-        if (readBlock(pDev->fd, 2 + log_sb->nb_inode_map + i, 
-            map + i * BLOCK_SIZE, BLOCK_SIZE))
+        if (readBlock(pDev, pDev->fd, 2 + log_sb->nb_inode_map + i, 
+            map + (i * log_sb->s_blocksize), log_sb->s_blocksize))
             goto fail;
     log_sb->zone_map = map;
     return 0;
@@ -266,8 +308,9 @@
 static int initInode(mx_device *pDev, mx_inode_info *inode)
 {
     int inode_num, block_num, offset, nb_blockid_per_block, i, nb;
-    u_char block[BLOCK_SIZE];
+    u_char block[BLOCK_SIZE*8];  /* max block size  */
     mx_inode_disk diskInode;
+    mx2_inode_disk diskInode2;
 
     inode->data_zones = NULL;
     inode->indirect_zones = NULL;
@@ -285,7 +328,7 @@
             inode_num);
     goto fail;
     }
-    if (pDev->super->minix_version != 1) {  /* Minix V2 inode unsupported */
+    if (pDev->super->minix_version >=3) {  /* Minix V3 inode unsupported */
         snprintf(errormsg, sizeof(errormsg), "bad version of minix FS");
     goto fail;
     }
@@ -298,30 +341,66 @@
     /* find the block number of this inode */
     block_num = 2 + pDev->super->nb_inode_map + pDev->super->nb_zone_map;
     /* first inode in first inode block is number one, not zero */
-    block_num += (inode_num -1) / INODE_PER_BLOCK_V1;
-    if (readBlock(pDev->fd, block_num, block, BLOCK_SIZE))
-    goto fail;
-    offset = ((inode_num -1) % INODE_PER_BLOCK_V1) * sizeof(mx_inode_disk);
-    memcpy(&diskInode, block+offset, sizeof(mx_inode_disk));
-    if (pDev->super->must_swap) {
-        inode->mode = swap_s(diskInode.mode);
-        inode->uid = swap_s(diskInode.uid);
-        inode->size = swap_l(diskInode.size);
-        inode->time = swap_l(diskInode.time);
-        inode->gid = swap_s(diskInode.gid);
-    inode->nb_link = diskInode.nb_link;
-        for (i = 0 ; i < 9 ; i++)
-            inode->raw_zone[i] = swap_s(diskInode.zone[i]);
-    } else {
-    inode->mode = diskInode.mode;
-    inode->uid = diskInode.uid;
-    inode->size = diskInode.size;
-    inode->time = diskInode.time;
-    inode->gid = diskInode.gid;
-    inode->nb_link = diskInode.nb_link;
-    for (i = 0 ; i < 9 ; i++)
-        inode->raw_zone[i] = diskInode.zone[i];
-    }
+    if (pDev->super->minix_version==1) 
+        block_num += (inode_num -1) / inode_per_block_v1;
+    else
+        block_num += (inode_num -1) / inode_per_block_v2;  
+    if (readBlock(pDev, pDev->fd, block_num, block, pDev->super->s_blocksize))
+        goto fail;
+    if (pDev->super->minix_version==1)    
+        offset = ((inode_num -1) % inode_per_block_v1) * sizeof(mx_inode_disk);
+    else
+        offset = ((inode_num -1) % inode_per_block_v2) * sizeof(mx2_inode_disk);     
+
+    if (pDev->super->minix_version==1)     
+        memcpy(&diskInode, block+offset, sizeof(mx_inode_disk));
+    else
+        memcpy(&diskInode2, block+offset, sizeof(mx2_inode_disk));        
+
+    if (pDev->super->minix_version==1)    
+    {    
+        if (pDev->super->must_swap) {
+            inode->mode = swap_s(diskInode.mode);
+            inode->uid = swap_s(diskInode.uid);
+            inode->size = swap_l(diskInode.size);
+            inode->time = swap_l(diskInode.time);
+            inode->gid = swap_s(diskInode.gid);
+        inode->nb_link = diskInode.nb_link;
+            for (i = 0 ; i < 9 ; i++)
+                inode->raw_zone[i] = swap_s(diskInode.zone[i]);
+        } else {
+        inode->mode = diskInode.mode;
+        inode->uid = diskInode.uid;
+        inode->size = diskInode.size;
+        inode->time = diskInode.time;
+        inode->gid = diskInode.gid;
+        inode->nb_link = diskInode.nb_link;
+        for (i = 0 ; i < 9 ; i++)
+            inode->raw_zone[i] = diskInode.zone[i];
+        }
+    }
+    else{
+        if (pDev->super->must_swap) {
+            inode->mode = swap_s(diskInode2.mode);
+            inode->uid = swap_s(diskInode2.uid);
+            inode->size = swap_l(diskInode2.size);
+            inode->time = swap_l(diskInode2.atime);
+            inode->gid = swap_s(diskInode2.gid);
+        inode->nb_link = swap_s(diskInode2.nlinks);
+            for (i = 0 ; i < 10 ; i++)
+                inode->raw_zone[i] = swap_s(diskInode2.zone[i]);
+        } else {
+        inode->mode = diskInode2.mode;
+        inode->uid = diskInode2.uid;
+        inode->size = diskInode2.size;
+        inode->time = diskInode2.atime;
+        inode->gid = diskInode2.gid;
+        inode->nb_link = diskInode2.nlinks;
+        for (i = 0 ; i < 10 ; i++)
+            inode->raw_zone[i] = diskInode2.zone[i];
+        }    
+    }
+     
     /* compressed file */
     if (pDev->super->compressed && 
         (inode->uid & MINIX_FLAGS_MASK) == MINIX_COMPRBLK_4KB) {
@@ -332,20 +411,25 @@
     if (inode->size == 0) /* empty file, nothing else to do */
         return 0;
 
-    inode->nb_data_zone = inode->size / BLOCK_SIZE;
-    if (inode->size % BLOCK_SIZE > 0)
+    inode->nb_data_zone = inode->size / pDev->super->s_blocksize;
+    if (inode->size % pDev->super->s_blocksize> 0)
     inode->nb_data_zone++;
     inode->data_zones = malloc(inode->nb_data_zone * sizeof(int));
     if (inode->data_zones == NULL)
-    goto fail;
+        goto fail;
+
     nb = (7 < inode->nb_data_zone) ? 7 : inode->nb_data_zone;
     for (i = 0 ; i < nb ; i++)
     inode->data_zones[i] = inode->raw_zone[i];
     if (inode->nb_data_zone <= 7)
-    return 0;
+        return 0;
+
 
     /* indirect block(s) */
-    nb_blockid_per_block = BLOCK_SIZE / sizeof(u_short);
+    if (pDev->super->minix_version==1)
+        nb_blockid_per_block = pDev->super->s_blocksize / sizeof(u_short);
+    else
+        nb_blockid_per_block = pDev->super->s_blocksize / sizeof(u_long);      
     /* count all not-data (simple or double indirect) blocks */
     /* put result into nb */
     if (inode->nb_data_zone <= (nb_blockid_per_block + 7)) {
@@ -360,53 +444,103 @@
     }
     inode->indirect_zones = malloc(nb * sizeof(int));
     if (inode->indirect_zones == NULL)
-    goto fail;
+        goto fail;
+
     inode->nb_indirect_zone = nb;
     inode->indirect_zones[0] = inode->raw_zone[7];
 
-    if (readBlock(pDev->fd, inode->raw_zone[7], block, BLOCK_SIZE))
-    goto fail;
-    for (i = 0 ; i < (int)(BLOCK_SIZE / sizeof(u_short)) ; i++) {
-    u_short us;
+    if (readBlock(pDev, pDev->fd, inode->raw_zone[7], block, pDev->super->s_blocksize))
+        goto fail;
+    
+    if (pDev->super->minix_version==1){
+        for (i = 0 ; i < (int)(pDev->super->s_blocksize / sizeof(u_short)) ; i++) {
+        u_short us;
+        nb = i + 7;
+        if (nb == inode->nb_data_zone)
+            return 0;
+        memcpy(&us, block + 2*i, sizeof(u_short));
+        if (pDev->super->must_swap)
+            inode->data_zones[nb] = (u_long) swap_s(us);
+        else
+            inode->data_zones[nb] = (u_long) us;
+        }
+    }
+    else{
+        for (i = 0 ; i < (int)(pDev->super->s_blocksize / sizeof(u_long)) ; i++) {
+        u_long us;
+        nb = i + 7;
+        if (nb == inode->nb_data_zone)
+            return 0;
+        memcpy(&us, block + 4*i, sizeof(u_long));
+        if (pDev->super->must_swap)
+            inode->data_zones[nb] = (u_long) swap_l(us);
+        else
+            inode->data_zones[nb] = (u_long) us;
+        }    
+    }
 
-    nb = i + 7;
-    if (nb == inode->nb_data_zone)
-        return 0;
-    memcpy(&us, block + 2*i, sizeof(u_short));
-    if (pDev->super->must_swap)
-        inode->data_zones[nb] = (int) swap_s(us);
-    else
-        inode->data_zones[nb] = (int) us;
-    }
     /* double indirect block */
     inode->indirect_zones[1] = inode->raw_zone[8];
-    if (readBlock(pDev->fd, inode->raw_zone[8], block, BLOCK_SIZE))
-    goto fail;
-    nb = 7 + nb_blockid_per_block; /* nb holds the current data block num */
-    for (i = 0 ; i < nb_blockid_per_block ; i++) {
-    u_short us1, us2;
-    u_char ind_block[BLOCK_SIZE];
-    int zone_num, j;
+    if (readBlock(pDev, pDev->fd, inode->raw_zone[8], block, pDev->super->s_blocksize))
+       goto fail;
 
-    memcpy(&us1, block+ 2*i, sizeof(u_short));
-    if (pDev->super->must_swap)
-        zone_num = swap_s(us1);
-    else
-        zone_num = us1;
-    inode->indirect_zones[2+i] = zone_num;
-    if (readBlock(pDev->fd, zone_num, ind_block, BLOCK_SIZE))
-        goto fail;
-    for (j = 0 ; j < BLOCK_SIZE / 2 ; j++) {
-        if (nb == inode->nb_data_zone)
-        return 0;
-        memcpy(&us2, ind_block + 2*j, sizeof(u_short));
-        if (pDev->super->must_swap)
-        zone_num = swap_s(us2);
-        else
-        zone_num = us2;
-        inode->data_zones[nb++] = zone_num;
-    }        
-    }
+    nb = 7 + nb_blockid_per_block; /* nb holds the current data block num */
+    
+    if (pDev->super->minix_version==1){
+        for (i = 0 ; i < nb_blockid_per_block ; i++) {
+        u_short us1, us2;
+        u_char ind_block[BLOCK_SIZE*8];
+        int zone_num, j;
+
+        memcpy(&us1, block+ 2*i, sizeof(u_short));
+        if (pDev->super->must_swap)
+            zone_num = swap_s(us1);
+        else
+            zone_num = us1;
+        inode->indirect_zones[2+i] = zone_num;
+        if (readBlock(pDev, pDev->fd, zone_num, ind_block, pDev->super->s_blocksize))
+            goto fail;
+
+        for (j = 0 ; j < pDev->super->s_blocksize / 2 ; j++) {
+            if (nb == inode->nb_data_zone)
+                return 0;
+            memcpy(&us2, ind_block + 2*j, sizeof(u_short));
+            if (pDev->super->must_swap)
+               zone_num = swap_s(us2);
+            else
+                zone_num = us2;
+            inode->data_zones[nb++] = zone_num;
+        }        
+        }
+    }
+    else{
+        for (i = 0 ; i < nb_blockid_per_block ; i++) {
+        u_long us1, us2;
+        u_char ind_block[BLOCK_SIZE*8];
+        u_long zone_num, j;
+
+        memcpy(&us1, block+ 4*i, sizeof(u_long));
+        if (pDev->super->must_swap)
+            zone_num = swap_l(us1);
+        else
+            zone_num = us1;
+        inode->indirect_zones[2+i] = zone_num;
+        if (readBlock(pDev, pDev->fd, zone_num, ind_block, pDev->super->s_blocksize))
+            goto fail;
+
+        for (j = 0 ; j < pDev->super->s_blocksize / 4 ; j++) {
+            if (nb == inode->nb_data_zone)
+                return 0;
+            memcpy(&us2, ind_block + 4*j, sizeof(u_long));
+            if (pDev->super->must_swap)
+               zone_num = swap_l(us2);
+            else
+                zone_num = us2;
+            inode->data_zones[nb++] = zone_num;
+        }        
+        }        
+    }
+    
     return 0;
 
 fail:
@@ -432,7 +566,7 @@
 /* warning : do not handle zones larger than one block */
 static int getFileContent(mx_device *pDev, u_char *buf, int inode_num)
 {
-    int nbread = 0, remaining, filesize, zone_num, i;
+    u_long nbread = 0, remaining, filesize, zone_num, i;
     mx_inode_info inode;
 
     inode.inode_num = inode_num;
@@ -444,9 +578,9 @@
             break;
     zone_num = inode.data_zones[i];
     remaining = filesize - nbread;
-    if (remaining > BLOCK_SIZE)
-        remaining = BLOCK_SIZE;
-    if (readBlock(pDev->fd, zone_num, buf+nbread, remaining)) {
+    if (remaining > pDev->super->s_blocksize)
+        remaining = pDev->super->s_blocksize;
+    if (readBlock(pDev, pDev->fd, zone_num, buf+nbread, remaining)) {
             resetInode(&inode);
             snprintf(errormsg, sizeof(errormsg), 
                 "error in reading file content");
@@ -636,6 +770,7 @@
     i += 16;
     printf("\n");
     }
+    
     free(buf);
     resetInode(&inode);
 }
@@ -762,6 +897,8 @@
     mx_inode_info inode;
     char mode_string[8];
     char *extractPath = NULL;
+    
+    fprintf(pFile, "INODE: %d \n", inode_num);
 
     inode.inode_num = inode_num;
     if (initInode(pDev, &inode) != 0)
@@ -776,7 +913,7 @@
         int i, child_inode, entrylen = 16;
         u_short us;
 
-        fprintf(pFile, "%s %s %d %d\n", path, mode_string, 
+        fprintf(pFile, "dir: %s %s %d %d\n", path, mode_string, 
             inode.uid, inode.gid);
         /* create local dir here */
         if (extractDir != NULL) {
@@ -858,7 +995,7 @@
             goto fail;
         }
         filecontent[inode.size] = 0;
-        fprintf(pFile, "%s %s %d %d %s\n", path, mode_string, inode.uid, 
+        fprintf(pFile, "soft l.: %s %s %d %d %s\n", path, mode_string, inode.uid, 
             inode.gid, filecontent);
 
     }
@@ -867,13 +1004,12 @@
         char *relpath;
         unsigned char *filecontent;
         int filesize, nbwritten, fd;
-
         relpath = path;
         while (relpath[0] != '\0' && relpath[0] == '/') /* skip leading "/" */
             relpath++;
         if (relpath[0] == '\0')
             goto fail;
-        fprintf(pFile, "%s %s %d %d %s\n", path, mode_string, 
+        fprintf(pFile, "file: %s %s %d %d %s\n", path, mode_string, 
             inode.uid & MINIX_UID_MASK, inode.gid, relpath);
         if (extractDir != NULL) {
             filesize = inode.size;
@@ -904,7 +1040,7 @@
                 if (getFileContent(pDev, filecontent, inode.inode_num)) {
                     free(filecontent);
                     goto fail;
-                }
+                }printf("Size: %d\n", filesize);
                 if (inode.compressed) {
                     unsigned char *uncompressed;
 
@@ -947,7 +1083,7 @@
         /* file size is null, buf first zone num is used for major and minor */
         major = inode.raw_zone[0] >> 8;
         minor = inode.raw_zone[0] & 0xFF;
-        fprintf(pFile, "%s %s %d %d %d %d\n", path, mode_string, inode.uid, 
+        fprintf(pFile, "block. dev.: %s %s %d %d %d %d\n", path, mode_string, inode.uid, 
             inode.gid, major, minor);
     }
     resetInode(&inode);
@@ -968,7 +1104,7 @@
         "%d %d\n"
         "# root dir perm\n", pDev->super->nb_zone, pDev->super->nb_inode);
     if (printProtoLine(pFile, "", pDev, 1, extractDir) != 0)
-        return -1;
+       return -1;  
     fprintf(pFile, "$\n");
     return 0;
 }
@@ -1124,6 +1260,11 @@
 
         memset(inbuf, 0, cluster_size);
         memset(outbuf, 0, cluster_size);
+        if (tab[cluster_idx+1] < tab[cluster_idx] ){/* ???????????????????????????????????????? */
+            memcpy(out,in,filesize);
+            printf("Error in decompression.");
+            return 0;
+        }
         memcpy(inbuf, in + tab[cluster_idx], 
             tab[cluster_idx+1] - tab[cluster_idx]);
         if (minix_uncompress_cluster(outbuf, cluster_size, inbuf,
 

Aplicirajte "patch" in nato prevedite izvorno kodo, npr. z gcc:

gcc -g -o readminixfs readminixfs.c -lz

Zaženite readminixfs:

./readminixfs -d usr part_usr.img
Block size is: 2048
Inodes per block: 32
b_inode map: 1 nb_zone_map: 1 
# minix fs description
boot description (ignored)
# number of blocks, number of inodes
3967 512
# root dir perm
INODE: 1 
dir:  d---755 0 0
INODE: 2 
dir: /dev d---755 0 0
INODE: 45 
block. dev.: /dev/hpt c---644 0 0 10 221
INODE: 46 
block. dev.: /dev/ddc0 c---660 0 100 240 0
INODE: 47 
block. dev.: /dev/hdmi0 c---660 0 100 241 0
INODE: 95 
block. dev.: /dev/mum c---660 0 100 126 0
...
Velikost datotečnega sistema je v tem primeru (3968 * 2048) = 0x7c0000.

Bios.img se začne se prične takoj za prvo minix particijo. V tem primeru je to 0x11ebde. Velikost biosa je že nekaj časa konstantna in znaša 0x40000 bajtov. Takoj za biosom pa do konca datoteke se nahaja druga minix particija.


Prva minix particija (mapa ./sbin). Datoteke z isto številko "Inode" so enake !?


Druga minix particija (mapa ./operator).

V obeh particijah ni nič kaj preveč zanimivega. Vsi ključi za ssh so seveda javni in se jih ne da uporabiti za ssh dostop do naprave. Morda bi bil uporaben le verimatrix.pem certifikat, ki bi se ga dalo uporabiti z ViewRight predvajalnikom ...

Zanimive so datoteke z lbr končnico, ki se nahajajo v mapi lib/netgem. Za razpakiranje lbr arhiva je bilo potrebno narediti tudi manjši popravek programa, ki odpre lbr arhiv. Nekatere datoteke v arhivu so najveretneje kompresirane, česar pa nisem še implementiral.

/* 
* This program extracts the files from .lbr archives, as found in the 
* Netgem root image.  The program takes two arguments:  the name of the 
* .lbr file and a directory into which to extract the files.  The directory 
* must exist before running the program. 
* 
* Note that the .lbr files contain binary data in little-endian format. 
* This program will have to be modified to work on big-endian machines. 
*/ 
#include <stdio.h> 
#include <string.h> 
#include <malloc.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <string.h> 
 
char *strdup(const char *str) 
{ 
    int n = strlen(str) + 1; 
    char *dup = malloc(n); 
    if(dup) 
    { 
        strcpy(dup, str); 
    } 
    return dup; 
} 
 
void check_dir(char *path) 
{ 
   char *s, *t; 
   struct stat buf; 
 
   t = strdup(path); 
   if ( (s=strrchr(t, '/')) != NULL ) { 
       *s = '\0'; 
       if ( stat(t, &buf) != 0 || !S_ISDIR(buf.st_mode) ) { 
           /* not a directory */ 
           check_dir(t); 
           mkdir(t, 0777); 
       } 
   } 
   free(t); 
} 
 
int readNode(FILE *fd, char *dirname) 
{ 
   int len, offset; 
   short lnode; 
   char *s, *name, *path, *buf; 
   long pos; 
   FILE *out; 
 
   fread(&len, 4, 1, fd);     /* length of file */ 
   fread(&offset, 4, 1, fd);  /* offset to start of file */ 
   fread(&lnode, 2, 1, fd);   /* size of directory node */ 
   name = malloc(lnode); 
   fseek(fd, 2, SEEK_CUR); 
   fread(name, lnode-12, 1, fd); 
 
   path = malloc(strlen(dirname)+lnode); 
   sprintf(path, "%s/%s", dirname, name); 
 
   /* remember position */ 
   pos = ftell(fd); 
 
   /* check that output directory exists */ 
  check_dir(path); 
 
   fprintf(stderr, "extracting %s\n", path); 
 
   /* copy data to output file */ 
   if ( (out=fopen(path, "w")) == NULL ) { 
       fprintf(stderr, "failed to open file %s\n", path); 
       return lnode; 
   } 
 
   fseek(fd, offset, SEEK_SET); 
 
   buf = malloc(len); 
   fread(buf, len, 1, fd); 
   fwrite(buf, len, 1, out); 
   free(buf); 
 
   fclose(out); 
 
   /* restore position */ 
   fseek(fd, pos, SEEK_SET); 
 
   free(name); 
   free(path); 
 
   return lnode; 
} 
 
int main(int argc, char **argv) 
{ 
   struct stat buf; 
   FILE *fd; 
   int dir_size, bytes_read; 
 
   if ( argc != 3 ) { 
       fprintf(stderr, "usage: %s file dir\n", argv[0]); 
       return 1; 
   } 
 
   if ( stat(argv[2], &buf) != 0 || !S_ISDIR(buf.st_mode) ) { 
       fprintf(stderr, "%s: failed to access directory %s\n", argv[0], 
               argv[2]); 
       return 1; 
   } 
 
   if ( (fd=fopen(argv[1], "r")) == NULL ) { 
       fprintf(stderr, "%s: failed to open lbr file %s\n", argv[0], argv[1]); 
       return 1; 
   } 
 
   /* size of directory is in last 4 bytes */ 
   fseek(fd, -(4L+32), SEEK_END); 
   fread(&dir_size, 4, 1, fd); 
   fseek(fd, -(dir_size+12+32), SEEK_END); 
 
   /* read directory entries */ 
   for ( bytes_read=0; bytes_read < dir_size; ) { 
       bytes_read += readNode(fd, argv[2]); 
   } 
 
   fclose(fd); 
 
   return 0; 
}

Shranite kodo v unlbr.c. in jo pretvorite v binarno ...

gcc -g -o unlbr unlbr.c
./unlbr root/lib/netgem/app_sioltv.lbr lbr

Razpakiran arhiv app_sioltv.lbr, mapa mediacenter/images/ :



Veliko tekstovnih datotek(JavaScript) vsebuje dele z naključnimi znaki, vse slike pa so dekodirane pravilno.
��^A^@�v^@^NchannelListSet^QchannelListSearch^OchannelListNext^RchannelIsNotHidden^GChannel
sListWrite      prototype^NgetNextChannel^HtoString^Fequals^SfillInternalService^RServiceLockTypeGet^SgetChannelByService$
middleware^Fslists^KserviceList^KgetVariable^KgetListById
isObsolete^YisCatchupFeatureAvailable^TisStartoverAvailable
isFavorite^KfavoriteSet^HisLocked^GlockSet^H_flagSet^GgetData^GsetData^L_getIdByName^R_getIdByDVBTriplet^EsetId^Q_getIdUs$
dvbtriplet^Dname^Bid^P__defineGetter__^OUSERFLAG_HIDDEN^PUSERFLAG_SKIPZAP^QUSERFLAG_FAVORITE^QUSERFLAG_RENUMBER^NserviceL$
serviceGet^MdvbServiceGet^L_getPVRState^OisTimeShiftable^LisRecordable^Drank^QgetFromDVBService^As^Csls^GdvbFlag^EArray^E$
searchFunc^EisNaN^Bch^Bfw^GdoCheck      checkFunc^Edelta^Gchannel^Fhidden       userFlags^EisDVB^Dskip^Cdvb^Fprefix^Fuval$
GENERIC666^QrecForbidden39648^HliveList^NgetChannelById^OLiveListChannel^D^@^A^@^D^@^K^@.^@^@�^�@^Q^@�M^A^Q^A�M^B^Q^B�M^C$
K^Ek^G^Q        �l^K^Q
�M^L^Q^K�M^M^Q^L�M^N^Q^M�M^O^Q^N�M^P^Q^O�M^Q^Q^P�M^R^Q^Q�M^S^Q^R�M^T^Q^S�M^U^Q^T�M^V^Q^U�M^W^Q^V�M^X^Q^W�M^YK^Zk^[k^\M^]K$
l?K^Ek^G^Ll@K^Ek^G^O^HlAK^Ek^G^Q'�lBK^Ek^G^Q(�lCK^Ek^G^Q)�lDK^Ek^G^Q*�lEK^Ek^G^Q+�lFK^Ek^G^Q,�lGK^Ek^G^HlHK^E^Q-�:lII^@^D$
_L"^DI_L!^DIH^@H>A;;r>JKL<^D^B^C^A      ^E^_^A^@^D^A^N_KMk^GkNs�OdK"e_kPfQ^W^S^_2F^K_^H+z^MI^HgB^_^^H_a+z^M,Q^F^�QF^F^^H+$
^G-^B^@^D^C^W�^SQ&9D    7RzWF^DQIKMk^GkNs
Videti je, da so tekstovne datoteke znotraj lbr arhiva kompresirane. Vse se začnejo z zaporedjem 0xc0 0xc0 0x01 0x00 in na začetku vsebujejo berljiv tekst (slovar) in nato neberljiv tekst. Na začetku je pred tekstom 1 bajt katerega vresnost je dolžina teksta, ki sledi.
Tega verjetno ne bo težko dekompresirati...