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 !?)
--- 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;
--- 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.
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
��^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^GkNsVideti 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.