/* Copyright 2007,2008 Luigi Auriemma This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA http://www.gnu.org/licenses/gpl.txt */ #define _LARGE_FILES // if it's not supported the tool will work #define __USE_LARGEFILE64 // without support for large files #define __USE_FILE_OFFSET64 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include "LzmaDec.h" #include "rwbits.h" #ifdef WIN32 #include HWND mywnd; char *get_file(void); char *put_file(void); #else #define stricmp strcasecmp #endif typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; #include "daa_crypt.h" #define VER "0.1.5a" #define PRINTF64(x) (u32)(((x) >> 32) & 0xffffffff), (u32)((x) & 0xffffffff) // I64x, llx? blah #if defined(_LARGE_FILES) #if defined(__APPLE__) #define fseek fseeko #define ftell ftello #elif defined(__FreeBSD__) #elif !defined(NOLFS) // use -DNOLFS if this tool can't be compiled on your OS! #define off_t off64_t #define fopen fopen64 #define fseek fseeko64 #define ftell ftello64 #endif #endif #pragma pack(4) typedef struct { u8 sign[16]; // DAA u32 size_offset; // where starts the list of sizes of the zipped chunks u32 version; // version u32 data_offset; // where the zipped chunks start u32 b1; // must be 1 u32 b0; // ever 0 u32 chunksize; // size of each output chunk u64 isosize; // total size of the output ISO u64 daasize; // total size of the DAA file u8 hdata[16]; // it's ever zero u32 crc; // checksum calculated on the first 0x48 bytes } daa_t; #pragma pack(1) typedef struct { u8 n1; // strange way to store numbers... u8 n2; u8 n3; } daa_data_t; #pragma pack() void poweriso_is_shit(u8 *chunk, int chunksize); u8 *find_ext(u8 *fname, u8 *ext); FILE *daa_next(void); void myalloc(u8 **data, unsigned wantsize, unsigned *currsize); void myfr(FILE *fd, void *data, unsigned size); void myfw(FILE *fd, void *data, unsigned size); int unlzma(CLzmaDec *lzma, u8 *in, u32 insz, u8 *out, u32 outsz); int unzip(z_stream *z, u8 *in, u32 insz, u8 *out, u32 outsz); void l2n_daa(daa_t *daa); void l2n_16(u16 *num); void l2n_32(u32 *num); void l2n_64(u64 *num); void std_err(void); int fgetz(u8 *data, int size, FILE *fd); void myexit(FILE *fdo); static void *SzAlloc(void *p, size_t size) { return(malloc(size)); } static void SzFree(void *p, void *address) { free(address); } static ISzAlloc g_Alloc = { SzAlloc, SzFree }; int multi = 0, multinum, endian; char *multi_filename; int main(int argc, char *argv[]) { CLzmaDec lzma; z_stream z; daa_data_t *daa_data; daa_t daa; FILE *fdi, *fdo; u64 tot; u32 daa_type, i, len, insz, outsz, pwdtype, pwdcrc, daacrc, daas, last_chunk; int ztype, // for 110 bitpos, // for 110 bitsize, // for 110 bittype; // for 110 u8 ans[66], // password goes from 1 to 64 chars pwdkey[128], daakey[128], *filei, *fileo, *in, *out, *p; setbuf(stdout, NULL); fputs("\n" "DAA2ISO "VER"\n" "by Luigi Auriemma\n" "e-mail: aluigi@autistici.org\n" "web: aluigi.org\n" "\n", stdout); fdo = NULL; endian = 1; if(*(char *)&endian) endian = 0; #ifdef WIN32 mywnd = GetForegroundWindow(); if(GetWindowLong(mywnd, GWL_WNDPROC)) { p = argv[1]; argv = malloc(sizeof(char *) * 3); if(argc < 2) { argv[1] = get_file(); } else { argv[1] = p; } argv[2] = put_file(); argc = 3; p = strrchr(argv[2], '.'); if(!p || (p && (strlen(p) != 4))) strcat(argv[2], ".iso"); } #endif if(argc < 3) { printf("\n" "Usage: %s \n" "\n", argv[0]); myexit(NULL); } filei = argv[1]; fileo = argv[2]; printf("- open %s\n", filei); fdi = fopen(filei, "rb"); if(!fdi) std_err(); printf("- create %s\n", fileo); fdo = fopen(fileo, "rb"); if(fdo) { fclose(fdo); printf("- the output file already exists, do you want to overwrite it (y/N)? "); fgetz(ans, sizeof(ans), stdin); if((ans[0] != 'y') && (ans[0] != 'Y')) myexit(NULL); } fdo = fopen(fileo, "wb"); if(!fdo) std_err(); z.zalloc = (alloc_func)0; z.zfree = (free_func)0; z.opaque = (voidpf)0; if(inflateInit2(&z, -15)) { printf("\nError: zlib initialization error\n"); myexit(fdo); } ztype = 1; // zlib default bitpos = 0; bitsize = 0; bittype = 0; myfr(fdi, &daa, sizeof(daa)); daacrc = crc32(0, (u8 *)&daa, sizeof(daa) - 4); l2n_daa(&daa); if(strncmp(daa.sign, "DAA", 16)) { if(!strncmp(daa.sign, "DAA VOL", 16)) { printf("\n" "Error: you must choose the first DAA file (*.part01.daa, *.part001.daa or\n" " *.daa) because this is a splitted archive\n"); } else { printf("\nError: wrong DAA signature (%.16s)\n", daa.sign); } myexit(fdo); } if(daacrc != daa.crc) { printf("- Alert: the CRC of the DAA header differs\n"); } if(((daa.version != 0x100) && (daa.version != 0x110)) || (daa.b1 != 1)) { printf("- Alert: unknown DAA version (%08x %08x %08x)\n", daa.version, daa.b1, daa.b0); } if(daa.version == 0x100) { } else { daa.data_offset &= 0xffffff; daa.chunksize = (daa.chunksize & 0xfff) << 14; bittype = daa.hdata[5]; for(bitsize = 0, len = daa.chunksize; len != bittype; bitsize++, len >>= 1); bitsize -= bittype & (~7); // useless??? if(bitsize < 1) bitsize = 1; printf("- bits reader %d %d\n", bittype, bitsize); LzmaDec_Construct(&lzma); LzmaDec_Allocate(&lzma, daa.hdata + 7, LZMA_PROPS_SIZE, &g_Alloc); } printf("\n" " version %08x %08x %08x\n" " size offset %08x\n" " data offset %08x\n" " chunk size %08x\n" " ISO size %08x%08x\n" " DAA size %08x%08x\n" " header data %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n" " header CRC %08x\n" "\n", daa.version, daa.b1, daa.b0, daa.size_offset, daa.data_offset, daa.chunksize, PRINTF64(daa.isosize), PRINTF64(daa.daasize), daa.hdata[0], daa.hdata[1], daa.hdata[2], daa.hdata[3], daa.hdata[4], daa.hdata[5], daa.hdata[6], daa.hdata[7], daa.hdata[8], daa.hdata[9], daa.hdata[10], daa.hdata[11], daa.hdata[12], daa.hdata[13], daa.hdata[14], daa.hdata[15], daa.crc); while(ftell(fdi) < daa.size_offset) { myfr(fdi, &daa_type, 4); l2n_32(&daa_type); myfr(fdi, &len, 4); l2n_32(&len); if(daa_type == 1) { multi = 1; // multi volume, not needed but I want to be sure to catch it in any case } else if(daa_type == 3) { myfr(fdi, &pwdtype, 4); l2n_32(&pwdtype); myfr(fdi, &pwdcrc, 4); l2n_32(&pwdcrc); myfr(fdi, daakey, 128); if(pwdtype != 0) { // ??? printf("- Alert: this type of encryption/password (%d) seems not supported\n", pwdtype); } printf("- the input file is protected by password, insert it: "); fgetz(ans, sizeof(ans), stdin); daa_crypt_init(pwdkey, ans, daakey); if(pwdcrc != crc32(0, pwdkey, 128)) { printf("\nError: wrong password\n"); myexit(fdo); } } if(fseek(fdi, len - 8, SEEK_CUR)) std_err(); } fseek(fdi, 0, SEEK_END); tot = ftell(fdi); if(multi || (tot != daa.daasize)) { printf("- multi volume file\n"); if((p = find_ext(filei, "001.daa"))) { multi = 1; multinum = 2; // the number of the next archive } else if((p = find_ext(filei, "01.daa"))) { multi = 2; multinum = 2; // if the current is 1 the next is 2 } else { multi = 3; multinum = 0; p = strrchr(filei, '.'); if(!p) p = filei + strlen(filei); } len = p - filei; multi_filename = malloc(len + 16); memcpy(multi_filename, filei, len); multi_filename[len] = 0; } in = out = NULL; insz = outsz = 0; tot = 0; myalloc(&out, daa.chunksize, &outsz); daas = daa.data_offset - daa.size_offset; daa_data = malloc(daas); if(!daa_data) std_err(); if(fseek(fdi, daa.size_offset, SEEK_SET)) std_err(); myfr(fdi, daa_data, daas); printf("- start unpacking:\n"); if(daa.version == 0x100) { daas /= 3; } else { daas = (daas << 3) / (bittype + bitsize); } last_chunk = daas - 1; for(i = 0; i < daas; i++) { printf(" %03d%%\r", (i * 100) / daas); if(daa.version == 0x100) { len = (daa_data[i].n1 << 16) | (daa_data[i].n2) | (daa_data[i].n3 << 8); } else { len = read_bits(bitsize, (u8 *)daa_data, bitpos); bitpos += bitsize; len += 5; ztype = read_bits(bittype, (u8 *)daa_data, bitpos); bitpos += bittype; if(len >= daa.chunksize) ztype = -1; } myalloc(&in, len, &insz); myfr(fdi, in, len); if(daa_type == 3) daa_crypt(pwdkey, in, len); switch(ztype) { case -1: { // no compression (this ztype is used only in this tool) len = daa.chunksize; memcpy(out, in, len); break; } case 0: { // LZMA len = unlzma(&lzma, in, len, out, outsz); poweriso_is_shit(out, len); break; } case 1: { // ZLIB len = unzip(&z, in, len, out, outsz); break; } default: { printf("\nError: unknown compression type (%d)\n", ztype); myexit(fdo); break; } } if(i == last_chunk) { // last chunk if((tot + len) > daa.isosize) len = daa.isosize - tot; } else { // other chunks if(len != daa.chunksize) { printf("\nError: the uncompressed size doesn't match the chunksize (%08x %08x)\n", len, daa.chunksize); myexit(fdo); } } myfw(fdo, out, len); tot += len; } printf(" 100%%\n" "- 0x%08x%08x bytes written\n", PRINTF64(tot)); if(tot != daa.isosize) { printf("- Alert: the size of the ISO should be 0x%08x%08x bytes!\n", PRINTF64(daa.isosize)); } inflateEnd(&z); fclose(fdi); fclose(fdo); if(in) free(in); if(out) free(out); if(daa.version == 0x100) { } else { LzmaDec_Free(&lzma, &g_Alloc); } printf("- finished\n"); myexit(NULL); return(0); } // what's the purpose of this function? only deobfuscating... blah void poweriso_is_shit(u8 *chunk, int chunksize) { u32 num, bp, e10, e20, e28; int i; u8 shit[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }, shiz[8] = { 1, 1, 1, 0, 1, 0, 0, 0 }, tmp; bp = 0; e10 = -1; e20 = 5; // add esi,5 e28 = 0; for(i = 0; (i + 5) <= chunksize; i++) { if((chunk[i] & 0xfe) != 0xe8) continue; if((i - e10) <= 3) { bp = (bp << ((i - e10 - 1) & 0xff)) & 7; } else { bp = 0; } if(bp) { tmp = chunk[i - shit[bp] + 4]; if(!shiz[bp] || !tmp || (tmp == 0xff)) { bp = ((bp & 3) << 1) | 1; e10 = i; continue; } } e10 = i; if((chunk[i + 4] != 0) && (chunk[i + 4] != 0xff)) { bp = ((bp & 3) << 1) | 1; continue; } num = (chunk[i + 4] << 24) | (chunk[i + 3] << 16) | (chunk[i + 2] << 8) | chunk[i + 1]; for(;;) { if(!e28) { num -= i + e20; } else { num += i + e20; } if(!bp) break; tmp = num >> (24 - (shit[bp] << 3)); if((tmp != 0) && (tmp != 0xff)) break; num ^= ((1 << (32 - (shit[bp] << 3))) - 1); } chunk[++i] = num; chunk[++i] = num >> 8; chunk[++i] = num >> 16; chunk[++i] = ~(((num >> 24) & 1) - 1); } } #ifdef WIN32 char *get_file(void) { OPENFILENAME ofn; static char filename[4096]; static const char filter[] = "DAA file\0" "*.daa\0" "(*.*)\0" "*.*\0" "\0" "\0"; filename[0] = 0; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; ofn.lpstrFile = filename; ofn.nMaxFile = sizeof(filename); ofn.lpstrTitle = "Select the input DAA file (or the first multipart) to convert"; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_EXPLORER | OFN_HIDEREADONLY; printf("- %s\n", ofn.lpstrTitle); if(!GetOpenFileName(&ofn)) exit(1); return(filename); } char *put_file(void) { OPENFILENAME ofn; static char filename[4096 + 10]; static const char filter[] = "ISO file\0" "*.iso\0" "(*.*)\0" "*.*\0" "\0" "\0"; filename[0] = 0; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; ofn.lpstrFile = filename; ofn.nMaxFile = sizeof(filename); ofn.lpstrTitle = "Choose the name of the output ISO file to create"; ofn.Flags = OFN_PATHMUSTEXIST | OFN_LONGNAMES | OFN_EXPLORER | OFN_HIDEREADONLY; printf("- %s\n", ofn.lpstrTitle); if(!GetSaveFileName(&ofn)) exit(1); return(filename); } #endif u8 *find_ext(u8 *fname, u8 *ext) { int len, extlen; u8 *ret; len = strlen(fname); extlen = strlen(ext); ret = fname + len - extlen; if((len >= extlen) && !stricmp(ret, ext)) { return(ret); } return(NULL); } FILE *daa_next(void) { daa_t daa; FILE *fd; static char *toadd = NULL, *fmt; if(!toadd) { toadd = multi_filename + strlen(multi_filename); switch(multi) { case 1: fmt = "%03d.daa"; break; case 2: fmt = "%02d.daa"; break; default: fmt = ".d%02d"; break; } } sprintf(toadd, fmt, multinum); printf(" open %s\n", multi_filename); fd = fopen(multi_filename, "rb"); if(!fd) std_err(); myfr(fd, &daa, sizeof(daa)); l2n_daa(&daa); if(strncmp(daa.sign, "DAA VOL", 16)) { printf("\nError: wrong DAA VOL signature (%.16s)\n", daa.sign); myexit(NULL); } if(fseek(fd, daa.size_offset, SEEK_SET)) std_err(); multinum++; return(fd); } void myalloc(u8 **data, unsigned wantsize, unsigned *currsize) { if(wantsize <= *currsize) return; *data = realloc(*data, wantsize); if(!*data) std_err(); *currsize = wantsize; } void myfr(FILE *fd, void *data, unsigned size) { int len; len = fread(data, 1, size, fd); if(len == size) return; if(!multi) { printf("\nError: incomplete input file, can't read %u bytes\n", size); myexit(NULL); } fclose(fd); fd = daa_next(); myfr(fd, data + len, size - len); } void myfw(FILE *fd, void *data, unsigned size) { if(fwrite(data, 1, size, fd) == size) return; printf("\nError: problems during the writing of the output file, check your disk space\n"); myexit(fd); } int unlzma(CLzmaDec *lzma, u8 *in, u32 insz, u8 *out, u32 outsz) { ELzmaStatus status; SizeT inlen, outlen; LzmaDec_Init(lzma); inlen = insz; outlen = outsz; if(LzmaDec_DecodeToBuf(lzma, out, &outlen, in, &inlen, LZMA_FINISH_END, &status) != SZ_OK) { printf("\nError: the compressed LZMA input is wrong or incomplete (%d)\n", status); myexit(NULL); } return(outlen); } int unzip(z_stream *z, u8 *in, u32 insz, u8 *out, u32 outsz) { inflateReset(z); z->next_in = in; z->avail_in = insz; z->next_out = out; z->avail_out = outsz; if(inflate(z, Z_SYNC_FLUSH) != Z_STREAM_END) { printf("\nError: the compressed ZLIB input is wrong or incomplete\n"); myexit(NULL); } return(z->total_out); } void l2n_daa(daa_t *daa) { if(!endian) return; l2n_32(&daa->size_offset); l2n_32(&daa->version); l2n_32(&daa->data_offset); l2n_32(&daa->b1); l2n_32(&daa->b0); l2n_32(&daa->chunksize); l2n_64(&daa->isosize); l2n_64(&daa->daasize); l2n_32(&daa->crc); } void l2n_16(u16 *num) { u16 tmp; if(!endian) return; tmp = *num; *num = ((tmp & 0xff00) >> 8) | ((tmp & 0x00ff) << 8); } void l2n_32(u32 *num) { u32 tmp; if(!endian) return; tmp = *num; *num = ((tmp & 0xff000000) >> 24) | ((tmp & 0x00ff0000) >> 8) | ((tmp & 0x0000ff00) << 8) | ((tmp & 0x000000ff) << 24); } void l2n_64(u64 *num) { u64 tmp; if(!endian) return; tmp = *num; *num = (u64)((u64)(tmp & (u64)0xff00000000000000ULL) >> (u64)56) | (u64)((u64)(tmp & (u64)0x00ff000000000000ULL) >> (u64)40) | (u64)((u64)(tmp & (u64)0x0000ff0000000000ULL) >> (u64)24) | (u64)((u64)(tmp & (u64)0x000000ff00000000ULL) >> (u64)8) | (u64)((u64)(tmp & (u64)0x00000000ff000000ULL) << (u64)8) | (u64)((u64)(tmp & (u64)0x0000000000ff0000ULL) << (u64)24) | (u64)((u64)(tmp & (u64)0x000000000000ff00ULL) << (u64)40) | (u64)((u64)(tmp & (u64)0x00000000000000ffULL) << (u64)56); } void std_err(void) { perror("\nError"); myexit(NULL); } int fgetz(u8 *data, int size, FILE *fd) { u8 *p; fflush(fd); if(!fgets(data, size, fd)) { data[0] = 0; return(0); } for(p = data; *p && (*p != '\n') && (*p != '\r'); p++); *p = 0; return(p - data); } void myexit(FILE *fdo) { if(fdo) fclose(fdo); // a bit useless #ifdef WIN32 u8 ans[8]; if(GetWindowLong(mywnd, GWL_WNDPROC)) { printf("\nPress RETURN to quit"); fgetz(ans, sizeof(ans), stdin); } #endif exit(1); }