#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STDBOOL_H #include #else typedef enum { FALSE = 0, TRUE = 1 } bool; #endif #ifdef HAVE_GETOPT_H #include #else #include "getopt.h" #endif #ifdef HAVE_GETTIMEOFDAY #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #endif #include #include #include "crack.h" static int use_unzip; static method *crack_method = methods; static int method_number = -1; static int min_length = -1; static int max_length = -1; static int residuent = 0; static int modul = 1; int brute_force_gen(void) { u8 *p = pw_end; do { u8 o = *--p; *p = bf_next [o]; if (o != bf_last) return pw_end - p; } while (p > pw); if (pw_end - pw < max_length) { p = ++pw_end; *p = 0; while (p > pw) *--p = bf_next [255]; return -1; } else return 0; } void parse_charset (char *cs) { u8 chars[800]; u8 map[256]; u8 *p = chars; while (*cs) switch (*cs++) { case 'a': strcpy ((char *)p, "abcdefghijklmnopqrstuvwxyz"); p+=26; break; case 'A': strcpy ((char *)p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); p+=26; break; case '1': strcpy ((char *)p, "0123456789"); p+=10; break; case '!': strcpy ((char *)p, "!:$%&/()=?{[]}+*~#"); p+=18; break; case ':': while (*cs) *p++ = *cs++; break; default: fprintf (stderr, "unknown charset specifier, only 'aA1!:' recognized\n"); exit (1); } *p = 0; p = chars; bf_last = *p++; memset (bf_next, bf_last, sizeof bf_next); memset (map, 0, 256); for (; *p; p++) if (!map [*p]) { map [*p] = 1; bf_next [bf_last] = *p; bf_last = *p; } bf_next [bf_last] = chars[0]; /* { int i; for (i = 0; i < 255; i++) printf ("bf_next [%3d] = %3d\n", i, bf_next[i]);};*/ } static int benchmark_count; static int benchmark_gen(void) { if (!--benchmark_count) return 0; return brute_force_gen (); } static void benchmark (void) { #ifdef HAVE_GETTIMEOFDAY int i; long j, k; struct timeval tv1, tv2; do { for (i = 0; i < HEADER_SIZE*3; i++) files[i] = i ^ (i*3); file_count = 3; strcpy (pw, "abcdefghij"); parse_charset ("a"); benchmark_count = BENCHMARK_LOOPS; verbosity = 0; printf ("%c%s: ", (crack_method - methods == default_method) ? '*' : ' ', crack_method->desc); fflush (stdout); crack_method->init_crack_pw (); gettimeofday (&tv1, 0); crack_method->crack_pw (benchmark_gen, false_callback); gettimeofday (&tv2, 0); tv2.tv_sec -= tv1.tv_sec; tv2.tv_usec -= tv1.tv_usec; j = tv2.tv_sec * 1000000 + tv2.tv_usec; k = BENCHMARK_LOOPS; printf ("cracks/s = "); for (i=7; i--; ) printf ("%d", k/j), k = (k-k/j*j)*10; printf ("\n"); crack_method++; } while (method_number < 0 && crack_method->desc); #else fprintf (stderr, "This executable was compiled without support for benchmarking\n"); exit (1); #endif } static u32 fgetu32 (FILE *f) { register u32 r; r = fgetc(f) << 0; r |= fgetc(f) << 8; r |= fgetc(f) << 16; r |= fgetc(f) << 24; return r; } static u32 fgetu16 (FILE *f) { register u32 r; r = fgetc(f) << 0; r |= fgetc(f) << 8; return r; } static void parse_zip (char *path) { FILE *f = fopen (path, "rb"); if (!f) { fprintf (stderr, "skipping '%s': %s\n", path, strerror (errno)); goto out; } while (!feof (f)) { u32 id = fgetu32 (f); if (id == 0x04034b50UL) { u16 version = fgetu16 (f); u16 flags = fgetu16 (f); u16 compression_method = fgetu16 (f); u16 lastmodtime = fgetu16 (f); u16 lastmoddate = fgetu16 (f); u32 crc32 = fgetu32 (f); u32 compr_size = fgetu32 (f); u32 uncompr_size = fgetu32 (f); u16 name_len = fgetu16 (f); u16 extra_field_len = fgetu16 (f); char zip_path [1024]; /* these are unused. */ (void) lastmoddate; (void) lastmodtime; (void) compression_method; (void) version; if (name_len < 1024) { fread (zip_path, name_len, 1, f); zip_path [name_len] = 0; } else { fprintf (stderr, "filename too long (>1023 bytes), skipping zipfile\n"); goto out; } fseek (f, extra_field_len, SEEK_CUR); if (flags & 1) { if (compr_size >= 12) { u8 *file = files + HEADER_SIZE * file_count; fread (file, FILE_SIZE, 1, f); file[FILE_SIZE ] = crc32 >> 24; file[FILE_SIZE+1] = crc32 >> 16; file_path [file_count] = strdup (path); if (verbosity) printf ("found encrypted file '%s', (size cp/uc %ld/%ld)\n", zip_path, compr_size, uncompr_size); if (++file_count >= MAX_FILES) { if (verbosity) printf ("%d file maximum reached, skipping further files\n", MAX_FILES); goto out; } compr_size -= 12; } else { fprintf (stderr, "'%s' is corrupted, skipping zipfile\n", zip_path); goto out; } } else if (verbosity) printf ("'%s' is not encrypted, skipping\n", zip_path); fseek (f, compr_size, SEEK_CUR); } else if (id == 0x08074b50UL) /* extended local sig (?) */ { fseek (f, 12, SEEK_CUR); } else if (id == 0x30304b50UL) { /* ignore */ } else if (id == 0x02014b50UL || id == 0x06054b50UL) { goto out; } else { fprintf (stderr, "found id %08lx, '%s' is not a zipfile ver 2.xx, skipping\n", (unsigned long)id, path); goto out; } } out: fclose (f); } static void usage (int ec) { fprintf (stderr, "\n" PACKAGE " version " VERSION ", a fast/free zip password cracker\n" "written by Marc Lehmann You can find more info on\n" "http://www.goof.com/pcg/marc/\n" "\n" "USAGE: fcrackzip [-bchvpium]\n" " [--brute-force] use brute force algorithm\n" " [--benchmark] execute a small benchmark\n" " [--charset characterset] use characters from charset\n" " [--help] show this message\n" " [--validate] sanity-check the algortihm\n" " [--verbose] be more verbose\n" " [--init-password string] use strings as initial password\n" " [--length min-max] check password with length min to max\n" " [--use-unzip] use unzip to weed out wrong passwords\n" " [--method num] use method number \"num\" (see below)\n" " [--modulo r/m] only calculcate 1/m of the password\n" " file... the zipfiles to crack\n" "\n" ); fprintf (stderr, "methods compiled in (* = default):\n\n"); for (crack_method = methods; crack_method->desc; crack_method++) fprintf (stderr, "%c%s\n", (crack_method - methods == default_method) ? '*' : ' ', crack_method->desc); fprintf (stderr, "\n"); exit (ec); } static struct option options[] = { { "brute-force" , no_argument , 0, 'b' }, { "benchmark" , no_argument , 0, 'B' }, { "charset" , required_argument , 0, 'c' }, { "help" , no_argument , 0, 'h' }, { "validate" , no_argument , 0, 'V' }, { "verbose" , no_argument , 0, 'v' }, { "init-password" , required_argument , 0, 'p' }, { "length" , required_argument , 0, 'l' }, { "use-unzip" , no_argument , 0, 'u' }, { "method" , required_argument , 0, 'm' }, { "modulo" , required_argument , 0, 2 }, { 0 , 0 , 0, 0 }, }; int main (int argc, char *argv[]) { int c; int option_index = 0; char *charset = "aA1!"; enum { m_benchmark, m_brute_force } mode = m_brute_force; while ((c = getopt_long (argc, argv, "bc:p:l:m:vu", options, &option_index)) != -1) switch (c) { case 'b': mode = m_brute_force; break; case 'p': strcpy (pw, optarg); break; case 'l': pw[0] = 0; switch (sscanf (optarg, "%d-%d", &min_length, &max_length)) { default: fprintf (stderr, "'%s' is an incorrect length specification\n", optarg); exit (1); case 1: max_length = min_length; case 2: } break; case 2: if (sscanf (optarg, "%d/%d", &residuent, &modul) != 2) fprintf (stderr, "malformed --modulo option, expected 'residuent/modul'\n"), exit (1); if (residuent < 0 || modul <= 0) fprintf (stderr, "residuent and modul must be positive\n"), exit (1); if (residuent >= modul) fprintf (stderr, "residuent must be less than modul\n"), exit (1); break; case 'B': mode = m_benchmark; benchmark (); exit (0); case 'v': verbosity++; break; case 'm': method_number = atoi (optarg); crack_method = methods + method_number; break; case 'V': validate (); exit (0); case 'c': charset = optarg; break; case 'u': use_unzip = 1; break; case 'h': usage (0); case ':': fprintf (stderr, "required argument missing\n"); exit (1); case '?': fprintf (stderr, "unknown option\n"); exit (1); default: usage (1); } if (optind >= argc) { fprintf (stderr, "you have to specify one or more zip files (try --help)\n"); exit (1); } for (; optind < argc; optind++) if (file_count < MAX_FILES) parse_zip (argv[optind]); else if (verbosity) printf ("%d file maximum reached, ignoring '%s'\n", MAX_FILES, argv[optind]); if (file_count == 0) { fprintf (stderr, "no usable files found\n"); exit (1); } crack_method->init_crack_pw (); switch (mode) { case m_brute_force: parse_charset (charset); if (!pw[0]) { if (min_length < 0) { fprintf (stderr, "you have to specify either --init-password or --length with --brute-force\n"); exit (1); } else { u8 *p = pw; while (p < pw + min_length) *p++ = bf_next [255]; *p++ = 0; } } if (residuent) { int xmodul = modul; modul = residuent; pw_end = pw + strlen (pw); brute_force_gen (); printf ("%s\n",pw); modul = xmodul; } crack_method->crack_pw (brute_force_gen, print_callback); break; default: fprintf (stderr, "specified mode not supported in this version\n"); exit (1); } return 0; }