wok view syslinux/stuff/iso2exe/iso2exe.c @ rev 18781

syslinux/isohybrib.exe: check EXE file (again)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Fri Jan 01 23:25:32 2016 +0100 (2016-01-01)
parents ec7b15533c2d
children 1bbbc99b3df2
line source
1 #ifdef __TURBOC__
2 #include <io.h>
3 #endif
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #ifdef WIN32
10 #include <windows.h>
11 #endif
12 #ifdef __MSDOS__
13 #define ftruncate(a,b)
14 #endif
15 #ifdef __MINGW32__
16 #define ftruncate chsize
17 #endif
18 #if !defined(__MSDOS__) && !defined(WIN32)
19 #define O_BINARY 0
20 #endif
21 typedef unsigned char uint8_t;
22 typedef unsigned long uint32_t;
23 #include "iso2exe.h"
25 static int fd, forced, uninstall;
26 static unsigned status = 1;
27 static char *append, *initrd;
28 static char tazlitoinfo[0x8000U - BOOTISOSZ];
29 #define buffer tazlitoinfo
30 #define BUFFERSZ 2048
31 #define WORD(n) * (unsigned short *) (n)
32 #define LONG(n) * (unsigned long *) (n)
34 static void readsector(unsigned long sector)
35 {
36 if (lseek(fd, sector * BUFFERSZ, SEEK_SET) == -1 ||
37 read(fd, buffer, BUFFERSZ) != BUFFERSZ) {
38 puts(bootiso+READSECTORERR);
39 exit(1);
40 }
41 }
43 static unsigned long getcustomsector(void)
44 {
45 readsector(16UL);
46 return 16UL + LONG(buffer + 80);
47 }
49 static int skipmd5 = 0;
50 #define ALIGN1
52 typedef struct {
53 uint32_t l;
54 uint32_t h;
55 } uint64_t;
56 static uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
57 static uint64_t total64; /* must be directly before hash[] */
58 static uint32_t hash[8]; /* 4 elements for md5, 5 for sha1, 8 for sha256 */
60 //#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
61 static uint32_t rotl32(uint32_t x, unsigned n)
62 {
63 return (x << n) | (x >> (32 - n));
64 }
66 static void md5_process_block64(void);
68 /* Feed data through a temporary buffer.
69 * The internal buffer remembers previous data until it has 64
70 * bytes worth to pass on.
71 */
72 static void common64_hash(const void *buffer, size_t len)
73 {
74 unsigned bufpos = total64.l & 63;
76 total64.l += len; if (total64.l < len) total64.h++;
78 while (1) {
79 unsigned remaining = 64 - bufpos;
80 if (remaining > len)
81 remaining = len;
82 /* Copy data into aligned buffer */
83 memcpy(wbuffer + bufpos, buffer, remaining);
84 len -= remaining;
85 buffer = (const char *)buffer + remaining;
86 bufpos += remaining;
87 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
88 bufpos -= 64;
89 if (bufpos != 0)
90 break;
91 /* Buffer is filled up, process it */
92 md5_process_block64();
93 /*bufpos = 0; - already is */
94 }
95 }
97 /* Process the remaining bytes in the buffer */
98 static void common64_end(void)
99 {
100 unsigned bufpos = total64.l & 63;
101 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
102 wbuffer[bufpos++] = 0x80;
104 /* This loop iterates either once or twice, no more, no less */
105 while (1) {
106 unsigned remaining = 64 - bufpos;
107 memset(wbuffer + bufpos, 0, remaining);
108 /* Do we have enough space for the length count? */
109 if (remaining >= 8) {
110 /* Store the 64-bit counter of bits in the buffer */
111 //uint64_t t = total64 << 3;
112 uint32_t *t = (uint32_t *) (&wbuffer[64 - 8]);
113 /* wbuffer is suitably aligned for this */
114 //*(uint64_t *) (&wbuffer[64 - 8]) = t;
115 t[0] = total64.l << 3;
116 t[1] = (total64.h << 3) | (total64.l >> 29);
117 }
118 md5_process_block64();
119 if (remaining >= 8)
120 break;
121 bufpos = 0;
122 }
123 }
125 /* These are the four functions used in the four steps of the MD5 algorithm
126 * and defined in the RFC 1321. The first function is a little bit optimized
127 * (as found in Colin Plumbs public domain implementation).
128 * #define FF(b, c, d) ((b & c) | (~b & d))
129 */
130 #undef FF
131 #undef FG
132 #undef FH
133 #undef FI
134 #define FF(b, c, d) (d ^ (b & (c ^ d)))
135 #define FG(b, c, d) FF(d, b, c)
136 #define FH(b, c, d) (b ^ c ^ d)
137 #define FI(b, c, d) (c ^ (b | ~d))
139 /* Hash a single block, 64 bytes long and 4-byte aligned */
140 static void md5_process_block64(void)
141 {
142 uint32_t *words = (void*) wbuffer;
143 uint32_t A = hash[0];
144 uint32_t B = hash[1];
145 uint32_t C = hash[2];
146 uint32_t D = hash[3];
148 const uint32_t *pc;
149 const char *pp;
150 const char *ps;
151 int i;
152 uint32_t temp;
155 pc = C_array;
156 pp = P_array;
157 ps = S_array - 4;
159 for (i = 0; i < 64; i++) {
160 if ((i & 0x0f) == 0)
161 ps += 4;
162 temp = A;
163 switch (i >> 4) {
164 case 0:
165 temp += FF(B, C, D);
166 break;
167 case 1:
168 temp += FG(B, C, D);
169 break;
170 case 2:
171 temp += FH(B, C, D);
172 break;
173 case 3:
174 temp += FI(B, C, D);
175 }
176 temp += words[(int) (*pp++)] + *pc++;
177 temp = rotl32(temp, ps[i & 3]);
178 temp += B;
179 A = D;
180 D = C;
181 C = B;
182 B = temp;
183 }
184 /* Add checksum to the starting values */
185 hash[0] += A;
186 hash[1] += B;
187 hash[2] += C;
188 hash[3] += D;
190 }
191 #undef FF
192 #undef FG
193 #undef FH
194 #undef FI
196 /* Initialize structure containing state of computation.
197 * (RFC 1321, 3.3: Step 3)
198 */
199 static void md5_begin(void)
200 {
201 hash[0] = 0x67452301;
202 hash[1] = 0xefcdab89;
203 hash[2] = 0x98badcfe;
204 hash[3] = 0x10325476;
205 total64.l = total64.h = 0;
206 }
208 /* Used also for sha1 and sha256 */
209 #define md5_hash common64_hash
211 /* Process the remaining bytes in the buffer and put result from CTX
212 * in first 16 bytes following RESBUF. The result is always in little
213 * endian byte order, so that a byte-wise output yields to the wanted
214 * ASCII representation of the message digest.
215 */
216 #define md5_end common64_end
218 static int writenhash(void *buffer, size_t len)
219 {
220 md5_hash(buffer, len);
221 return write(fd, buffer, len);
222 }
224 static void md5sum(void)
225 {
226 unsigned long sectors = 0;
227 int count;
229 lseek(fd, 32768UL, SEEK_SET);
231 md5_begin();
232 while ((count = read(fd, buffer, BUFFERSZ)) > 0) {
233 if (sectors == 0)
234 sectors = LONG(buffer + 80);
235 md5_hash(buffer, count);
236 if (--sectors == 0)
237 break;
238 }
240 if (count < 0)
241 return;
243 md5_end();
245 lseek(fd, 32752UL, SEEK_SET);
246 write(fd, hash, 16);
247 memcpy(bootiso + BOOTISOSZ - 16, hash, 16);
248 }
250 static unsigned chksum(unsigned start, unsigned stop)
251 {
252 unsigned i, n = 0;
254 lseek(fd, 0UL /* (unsigned long) (start / BUFFERSZ) */, SEEK_SET);
255 while (1) {
256 if (read(fd, buffer, BUFFERSZ) != BUFFERSZ)
257 return 0;
258 for (i = start % BUFFERSZ; i < BUFFERSZ; i += 2, start += 2) {
259 if (start >= stop)
260 return - n;
261 n += WORD(buffer + i);
262 }
263 }
264 }
266 static void clear_config(unsigned i)
267 {
268 for (;i % 512; i++) {
269 /* clear custom config */
270 write(fd, buffer + 2048, 2048);
271 }
272 }
274 static unsigned install(char *filename)
275 {
276 #define heads 64
277 #define sectors 32
278 #define partition (446+16)
279 #define trksz (512UL * heads * sectors)
280 unsigned long size, catalog, lba;
281 int cylinders, i, j, isohybrid;
282 unsigned n;
283 #ifdef __MSDOS__
284 for (bootiso = (char *) install;
285 bootiso[0] != 'M' || bootiso[1] != 'Z' || bootiso[2] != '\xEB';
286 bootiso++) if (bootiso < (char *) install) {
287 bootiso = "No bootiso data";
288 return 0;
289 }
290 #endif
291 if (!filename)
292 return USAGE;
293 fd = open(filename,O_RDWR|O_BINARY);
294 if (fd == -1)
295 return OPENERR;
297 if (uninstall) {
298 struct { char check[sizeof(tazlitoinfo) - BUFFERSZ - 1024]; };
299 readsector(0UL);
300 n = BUFFERSZ; /* fill with zeros */
301 if (WORD(buffer) == 23117) {
302 /* restore isolinux hybrid boot */
303 readsector((unsigned long) buffer[417]);
304 n = 0; /* fill with hybrid boot */
305 }
306 lseek(fd, 0UL, SEEK_SET);
307 for (i = 0; i < 32; i++, n = BUFFERSZ) {
308 write(fd, buffer + n, 1024);
309 }
310 i = getcustomsector();
311 lseek(fd, i * 2048UL, SEEK_SET);
312 clear_config(i);
313 ftruncate(fd, i * 2048UL);
314 close(fd);
315 status = 0;
316 return UNINSTALLMSG;
317 }
319 readsector(0UL);
320 if (buffer[0] == 'M' && buffer[1] == 'Z') {
321 if (forced == 0)
322 return ALREADYEXEERR;
323 n = (buffer[417] + 1) * 512;
324 i = 0x8000 - 1024;
325 if (i > sizeof(tazlitoinfo))
326 i = sizeof(tazlitoinfo);
327 if (lseek(fd, n, SEEK_SET) == -1 ||
328 read(fd, tazlitoinfo, sizeof(tazlitoinfo)) != sizeof(tazlitoinfo) ||
329 lseek(fd, 1024UL, SEEK_SET) == -1 ||
330 write(fd, tazlitoinfo, i) != i) {
331 puts(bootiso+READSECTORERR);
332 exit(1);
333 }
334 }
336 do {
337 /* Install hybridiso boot sector */
338 readsector(17UL);
339 status = ELTORITOERR;
340 if (strncmp(buffer+7, bootiso+ELTORITOERR+ELTORITOOFS, 23))
341 break;
342 catalog = LONG(buffer + 71);
343 readsector(catalog);
344 status = CATALOGERR;
345 if (LONG(buffer) != 1 || LONG(buffer + 30) != 0x88AA55UL)
346 break;
347 lba = LONG(buffer + 40);
348 readsector(lba);
349 status = HYBRIDERR;
350 if (LONG(buffer + 64) != 1886961915UL)
351 break;
352 isohybrid = bootiso[417] * 512;
353 LONG(bootiso + isohybrid + 432) = lba * 4;
354 LONG(bootiso + isohybrid + 440) = rand();
355 LONG(bootiso + isohybrid + partition) = 0x10080UL;
356 WORD(bootiso + isohybrid + 510) = 0xAA55U;
357 #if 0
358 size = lseek(fd, 0UL, SEEK_END);
359 size += 0x000FFFFFUL;
360 size &= 0xFFF00000UL;
361 #else
362 for (size = 0x000FFFFFUL; /* 1M - 1 */
363 read(fd, tazlitoinfo, 1024) == 1024;
364 size += 1024);
365 size &= 0xFFF00000UL; /* round */
366 #endif
367 cylinders = (size >> 20) - 1;
368 bootiso[isohybrid + partition + 4] = 23; /* "Windows hidden IFS" */
369 bootiso[isohybrid + partition + 5] = heads - 1;
370 bootiso[isohybrid + partition + 6] = ((cylinders & 0x300) >> 2) + sectors;
371 bootiso[isohybrid + partition + 7] = cylinders & 0xFF;
372 LONG(bootiso + isohybrid + partition + 8) = 0;
373 LONG(bootiso + isohybrid + partition + 12) = (size >> 9);
375 /* Copy the partition table */
376 memcpy(bootiso + 0x1BE, bootiso + isohybrid + 0x1BE, 66);
377 status = 0;
378 } while (0);
380 if (forced == 0 && status)
381 return status;
383 status = 1;
384 if (append || initrd) {
385 unsigned long pos = getcustomsector() * 2048UL;
386 lseek(fd, pos, SEEK_SET);
387 clear_config(pos);
388 lseek(fd, pos, SEEK_SET);
389 write(fd, "#!boot 00000000000000000000000000000000\n", 40);
390 md5_begin();
391 if (append) {
392 writenhash("append=", 7);
393 writenhash(append, strlen(append));
394 writenhash("\n", 1);
395 }
396 if (initrd) {
397 char number[16], *p;
398 unsigned long end, x;
399 int data = open(initrd,O_RDONLY|O_BINARY);
400 if (data == -1)
401 return OPENINITRDERR;
402 for (end = 0;; end += i) {
403 i = read(data, buffer, BUFFERSZ);
404 if (i <= 0)
405 break;
406 }
407 p = number + sizeof(number) -1;
408 x = end; *p-- = '\n';
409 do {
410 *p-- = '0' + (x % 10);
411 x /= 10;
412 } while (x);
413 if (*++p != '0') {
414 writenhash("initrd:", 7);
415 i = number - p + sizeof(number);
416 writenhash(p, i);
417 lseek(data, 0UL, SEEK_SET);
418 do {
419 i = read(data, buffer, BUFFERSZ);
420 if (i <= 0)
421 break;
422 if (i > end)
423 i = end;
424 writenhash(buffer, i);
425 end -= i;
426 } while (end != 0);
427 }
428 close(data);
429 }
430 md5_end();
431 {
432 static char h[] = "0123456789abcdef";
433 char string[32], *s = string + 30;
434 unsigned char *p = (void *) hash;
436 lseek(fd, 7 + pos, SEEK_SET);
437 for (p += 15; s >= string; p--, s -= 2) {
438 s[1] = h[ *p & 15 ];
439 s[0] = h[ *p >> 4 ];
440 }
441 write(fd, string, 32);
442 }
443 }
445 /* Install iso2exe boot sector */
446 LONG(bootiso + 440) = time(NULL);
448 /* read tazlito flavor data */
449 lseek(fd, 1024UL, SEEK_SET);
450 read(fd, tazlitoinfo, sizeof(tazlitoinfo));
452 /* Update iso image */
453 n = (bootiso[417] + 1) * 512;
454 lseek(fd, 0UL, SEEK_SET);
455 write(fd, bootiso, n); /* EXE/PE + isohybrid mbr */
456 write(fd, tazlitoinfo, sizeof(tazlitoinfo));
457 write(fd, bootiso + n, BOOTISOSZ - n); /* COM + rootfs + EXE/DOS */
459 /* Compute the boot checksums */
460 if (!skipmd5) {
461 puts(bootiso + MD5MSG);
462 md5sum();
463 lseek(fd, 0UL, SEEK_SET);
464 write(fd, bootiso, 512);
465 n = WORD(bootiso + 2) - 512*(WORD(bootiso + 4) - 1);
466 WORD(bootiso + 18) = chksum(0, (unsigned short) n) - 1;
467 }
468 lseek(fd, 0UL, SEEK_SET);
469 write(fd, bootiso, 512);
470 close(fd);
471 status = 0;
472 return SUCCESSMSG;
473 }
475 int main(int argc, char *argv[])
476 {
477 int i;
478 char *s;
480 while (argc > 2) {
481 s = argv[1];
482 if (*s != '-') break;
483 while (*s == '-') s++;
484 switch (*s | 0x20) {
485 case 'a' : append=argv[2]; break;
486 case 'i' : initrd=argv[2]; break;
487 }
488 argv += 2;
489 argc -= 2;
490 }
491 for (i = 2; i < argc; i++) {
492 char *s = argv[i];
493 while ((unsigned)(*s - '-') <= ('/' - '-')) s++;
494 switch (*s | 0x20) {
495 case 'f' : forced++; break;
496 case 'q' : skipmd5++; break;
497 case 'u' : uninstall++; break;
498 }
499 }
500 puts(bootiso + install(argv[1]));
501 if (status > 1)
502 puts(bootiso + FORCEMSG);
503 #ifdef WIN32
504 Sleep(2000);
505 #endif
506 return status;
507 }