1 |
/* |
2 |
* isobar.c: ISO Boot Archive Remover. |
3 |
* |
4 |
* Jason Hood, 6, 8 & 9 March, 2005. |
5 |
* |
6 |
* Extract the boot image (or code if no emulation) from a bootable CD-ROM |
7 |
* (or an image of one). |
8 |
* |
9 |
* Adapted from the program by David Brinkman. |
10 |
* |
11 |
* v1.01, 30 May, 2005: |
12 |
* always include Image Size in display. |
13 |
* |
14 |
* v1.02, 5 & 6 June, 2005: |
15 |
* Win32 port. |
16 |
* |
17 |
* v1.03, 10 Nov, 2007: |
18 |
* Linux port by newhren <colimit@gmail.com> |
19 |
* |
20 |
* Todo: possibly replace the boot image in a CD image; |
21 |
* recognise boot sections; |
22 |
* ignore non-bootable CDs (are there any?). |
23 |
* |
24 |
* http://www.phoenix.com/NR/rdonlyres/98D3219C-9CC9-4DF5-B496-A286D893E36A/0/specscdrom.pdf |
25 |
* http://www.geocities.com/jadoxa/shsucdx/omibar32.zip |
26 |
* http://adoxa.110mb.com/shsucdx/omibar32.zip |
27 |
* http://colimit.googlepages.com/isobar.c |
28 |
* |
29 |
*/ |
30 |
|
31 |
#define PVERS "1.03" |
32 |
#define PDATE "10 Nov, 2007" |
33 |
|
34 |
#include <stdio.h> |
35 |
#include <stdlib.h> |
36 |
#include <string.h> |
37 |
#include <fcntl.h> |
38 |
#include <stdint.h> |
39 |
#include <unistd.h> |
40 |
#include <sys/stat.h> |
41 |
|
42 |
typedef uint8_t BYTE; |
43 |
typedef uint16_t WORD; |
44 |
typedef uint32_t DWORD; |
45 |
typedef unsigned int UINT; |
46 |
|
47 |
#define MAX 32 |
48 |
#define OFLAG O_CREAT | O_WRONLY | O_TRUNC |
49 |
#define OMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH |
50 |
|
51 |
char * buf; |
52 |
DWORD offset = 0, imgsize; |
53 |
int fdin; |
54 |
|
55 |
int CDRead( UINT SectorCount, DWORD StartSector ) |
56 |
{ |
57 |
return (pread(fdin, buf, SectorCount << 11, StartSector << 11) == SectorCount << 11); // Sector size = 0x800 |
58 |
} |
59 |
|
60 |
const char* platform[] = { "80x86", |
61 |
"Power PC", |
62 |
"Mac" }; |
63 |
|
64 |
const char* boot_type[] = { "no emulation", |
65 |
"1.2 meg floppy", |
66 |
"1.44 meg floppy", |
67 |
"2.88 meg floppy", |
68 |
"hard disk" }; |
69 |
|
70 |
enum |
71 |
{ |
72 |
E_OK, // No problems |
73 |
E_OPT, // Unknown/invalid option |
74 |
E_MEM, // Not enough memory |
75 |
E_NOCD, // Not a CD drive, MSCDEX/SHSUCDX not installed, |
76 |
// unknown CD format or no CD present |
77 |
E_CREATE, // Unable to create image file |
78 |
E_ABORTED // Read/write error |
79 |
}; |
80 |
|
81 |
|
82 |
void usage( void ) |
83 |
{ |
84 |
puts( |
85 |
|
86 |
"ISOBAR, Version "PVERS" ("PDATE"). Freeware.\n" |
87 |
"\n" |
88 |
"Extract the boot image (or code) from .ISO image of a bootable CD-ROM.\n" |
89 |
"\n" |
90 |
"isobar [-o file] iso-file\n" |
91 |
"\n" |
92 |
"-o file Write the boot image (or code) to the specified filename\n" |
93 |
" (without this, just boot information is displayed).\n" |
94 |
"iso-file An image of a bootable CD-ROM.\n" |
95 |
|
96 |
); |
97 |
|
98 |
exit( E_OK ); |
99 |
} |
100 |
|
101 |
|
102 |
int main( int argc, char* argv[] ) |
103 |
{ |
104 |
int i; |
105 |
int fdout = 0; |
106 |
char *outfile = NULL, *isofile = NULL; |
107 |
DWORD bootfound; |
108 |
int type; |
109 |
DWORD n; |
110 |
UINT len, w; |
111 |
|
112 |
|
113 |
if (argc > 1) |
114 |
{ |
115 |
if (argv[1][0] == '?' || argv[1][1] == '?' || !strcmp( argv[1], "--help" )) |
116 |
usage(); |
117 |
|
118 |
for (i = 1; i < argc; ++i) |
119 |
{ |
120 |
if (*argv[i] == '-') |
121 |
{ |
122 |
switch (argv[i][1] | 0x20) |
123 |
{ |
124 |
case 'o': |
125 |
if (argv[i][2] == '\0' && argv[i+1] == NULL) |
126 |
{ |
127 |
fputs( "ERROR: -o requires filename.\n", stderr ); |
128 |
return E_OPT; |
129 |
} |
130 |
outfile = (argv[i][2] == '\0') ? argv[++i] : argv[i] + 2; |
131 |
break; |
132 |
|
133 |
case 'h': |
134 |
usage (); |
135 |
break; |
136 |
|
137 |
default: |
138 |
fprintf( stderr, "ERROR: unknown option: %s.\n", argv[i] ); |
139 |
return E_OPT; |
140 |
} |
141 |
} |
142 |
else |
143 |
{ |
144 |
isofile = argv[i]; |
145 |
} |
146 |
} |
147 |
} else usage(); |
148 |
|
149 |
|
150 |
fdin = open( isofile, O_RDONLY ); |
151 |
|
152 |
if (fdin == -1) |
153 |
{ |
154 |
fprintf( stderr, "ERROR: Cannot open %s.\n", isofile ); |
155 |
return E_NOCD; |
156 |
} |
157 |
|
158 |
buf = malloc( MAX << 11 ); // transfer up to MAX Sectors (0x800) at a time |
159 |
if (buf == NULL) |
160 |
{ |
161 |
fputs( "ERROR: Not enough memory.\n", stderr ); |
162 |
return E_MEM; |
163 |
} |
164 |
|
165 |
if (!CDRead( 1, 0x11 )) // read the boot record |
166 |
{ |
167 |
fputs( "Read error!\n", stderr ); |
168 |
return E_ABORTED; |
169 |
} |
170 |
|
171 |
if (strcmp( buf+1, "CD001\01EL TORITO SPECIFICATION" )) |
172 |
{ |
173 |
fprintf( stderr, "ERROR: %s is not EL TORITO.\n", isofile ); |
174 |
return E_NOCD; |
175 |
} |
176 |
bootfound = *(DWORD *)(buf+0x47); |
177 |
printf( "Catalog Sector:\t%lx\n", (long unsigned int)bootfound ); |
178 |
|
179 |
if (!CDRead( 1, bootfound )) // read the boot catalog |
180 |
{ |
181 |
fputs( "Read error!\n", stderr ); |
182 |
return E_ABORTED; |
183 |
} |
184 |
|
185 |
// Just check the key bytes, don't worry about the checksum. |
186 |
if (buf[0x1e] != (char)0x55 || buf[0x1f] != (char)0xAA) |
187 |
{ |
188 |
fprintf( stderr, "ERROR: %s has an invalid boot catalog.\n", isofile ); |
189 |
return E_NOCD; |
190 |
} |
191 |
type = (BYTE)buf[1]; |
192 |
printf( "Platform:\t%s (%02x)\n", (type < 3) ? platform[type] : "unknown", |
193 |
type ); |
194 |
printf( "ID String:\t%.24s\n", (buf[4]) ? buf+4 : "not recorded" ); |
195 |
printf( "Bootable:\t%s (%02x)\n", (buf[0x20] == (char)0x88) ? "yes" : "no", |
196 |
(BYTE)buf[0x20] ); |
197 |
type = buf[0x21] & 15; |
198 |
printf( "Boot Type:\t%s (%02x)\n", (type < 5) ? boot_type[type] : "unknown", |
199 |
(BYTE)buf[0x21] ); |
200 |
i = *(WORD *)(buf+0x22); |
201 |
printf( "Load Segment:\t%04x\n", (i == 0) ? 0x7c0 : i ); |
202 |
printf( "System Type:\t%02x\n", (BYTE)buf[0x24] ); |
203 |
imgsize = *(WORD *)(buf+0x26); |
204 |
printf( "Sector Count:\t%02x (%d)\n", (UINT)imgsize, (UINT)imgsize ); |
205 |
offset = *(DWORD *)(buf+0x28); |
206 |
printf( "Image Sector:\t%lx\n", (long unsigned int)offset ); |
207 |
|
208 |
switch (type) |
209 |
{ |
210 |
case 0: // no emulation |
211 |
break; |
212 |
|
213 |
case 1: // 1.2meg floppy |
214 |
imgsize=1200*2; |
215 |
break; |
216 |
|
217 |
case 2: // 1.44meg floppy |
218 |
imgsize=1440*2; |
219 |
break; |
220 |
|
221 |
case 3: // 2.88meg floppy |
222 |
imgsize=2880*2; |
223 |
break; |
224 |
|
225 |
case 4: // hard disk |
226 |
CDRead( 1, offset ); // read the MBR |
227 |
imgsize = *(DWORD *)(buf+0x1c6) + *(DWORD *)(buf+0x1ca); // offset + size of the first partition |
228 |
break; |
229 |
|
230 |
default: |
231 |
fprintf( stderr, "ERROR: EL TORITO boot media type not recognized\n", isofile ); |
232 |
return E_NOCD; |
233 |
} |
234 |
|
235 |
imgsize *= 0x200; // Virtual Sector size = 0x200 |
236 |
printf( "Image Size:\t%ld bytes\n", (long int)imgsize ); |
237 |
|
238 |
if (outfile) |
239 |
{ |
240 |
fdout = open( outfile, OFLAG, OMODE ); |
241 |
if (fdout < 0) |
242 |
{ |
243 |
fprintf( stderr, "ERROR: Cannot create %s.\n", outfile ); |
244 |
return E_CREATE; |
245 |
} |
246 |
|
247 |
do |
248 |
{ |
249 |
n = imgsize >> 11; // Sector size = 0x800 |
250 |
if (n > MAX) |
251 |
n = MAX; |
252 |
else if (n == 0) |
253 |
n = 1; |
254 |
if (!CDRead( (UINT)n, offset )) |
255 |
{ |
256 |
fputs( "Read error!", stderr ); |
257 |
return E_ABORTED; |
258 |
} |
259 |
len = (UINT)n << 11; |
260 |
if (len > imgsize) |
261 |
len = (UINT)imgsize; |
262 |
w = write( fdout, buf, len ); |
263 |
if (w != len) |
264 |
{ |
265 |
fputs( "Write error!", stderr ); |
266 |
return E_ABORTED; |
267 |
} |
268 |
offset += n; |
269 |
imgsize -= len; |
270 |
} while (imgsize); |
271 |
close( fdout ); |
272 |
printf( "\nThe output image has been saved in: %s\n", outfile ); |
273 |
} |
274 |
|
275 |
close( fdin ); |
276 |
return 0; |
277 |
} |