www.pudn.com > AntiCrack.zip > anticrack.c


/* 
 * anticrack - a password checker against password Crackers 
 * 
 *  Copyright (C) 1996  Kazuto Tominaga 
 * 
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA. 
 * 
 * 
 * How to make: 
 * 
 * 1. Compile "anticrack.c" and "rejrule.c" within the Source directory 
 * of Crack v4.1f (crack.h, conf.h and crack-glob.h in Crack's distribution 
 * are required). 
 * 
 * 2. Compile "crack-lib.c" in Crack's distribution. 
 * 
 * 3. Link all the resulting objects (anticrack.o, rejrule.o and crack-lib.o) 
 * to make the executable `anticrack'. 
 * 
 * 
 * Usage: 
 * 
 * Anticrack requires two arguments: the first is a rule file, and the 
 * second is a dictionary file.  You can use Crack's "Scripts/dicts.rules" 
 * and "Dicts/bigdict" files respectively.  The command line would look like: 
 * 
 *	anticrack dicts.rules bigdict 
 * 
 * You will be prompted for your password candidate (twice).  Echo 
 * automatically turns off. 
 * 
 * Then, you'll get the result quite a little time after, 
 * but it heavily depends on the number of the rules, the size of 
 * the dictionary, and furthermore, the given candidate. 
 * 
 * 
 * Note: 
 * 
 * In default, neither comment lines nor empty lines are allowed in 
 * the dictionary file.  If it has some, the switch '-c' must be specified. 
 * 
 * 
 * Bugs: 
 * 
 * The 8th bit is used internally to mean special characters. 
 * 
 * The string functions (e.g., strcpy) are supposed to handle an 8-bit 
 * character in the same way as they handle a 7-bit character. 
 * 
 */ 
 
#include  
#include  
#ifdef hpux 
#include 	/* for getpass(3) */ 
#endif 
 
#include "anticrack.h" 
 
/* version info */ 
char anticrack_version[] = VERSION; 
 
/* version of this file */ 
static char version_id[] = 
    "@(#) $Id: anticrack.c,v 1.15 1993/11/18 08:24:21 tominaga Exp tominaga $"; 
 
/* to embed in binary code */ 
static char anticrack_h_version_id[] = ANTICRACK_H_VERSION; 
 
/* default values */ 
int debug = 0;		/* debug flag */ 
int comment = 0;	/* turn on if dictionary has comment or empty lines */ 
int showcracked = 0;	/* turn on if cracked candidates should be shown */ 
int acceptedrules = 0;	/* turn on to show the accepted rules */ 
int showacceptrate = 0;	/* turn on to show the rate of accepted rules */ 
 
/* stub for crack-lib.c */ 
Log(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) 
char *f; 
long x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; 
{ 
    fprintf(stderr, f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9); 
} 
 
/* optional messages are shown by this function */ 
message(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) 
char *f; 
long x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; 
{ 
    fprintf(stderr, f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9); 
} 
 
char *Malloc(s)		/* indispensable malloc; exits on failure */ 
unsigned s; 
{ 
    char *p, *malloc(); 
 
    if ((p = malloc(s)) == NULL) { 
	perror("malloc"); 
	exit(-2); 
    } 
    return p; 
} 
 
char *newstr(s) 
char *s; 
{ 
    char *p; 
    p = Malloc(strlen(s)+1); 
    strcpy(p, s); 
    return p; 
} 
 
main(ac, av) 
int ac; 
char **av; 
{ 
    char *rfile, *dfile, *flags; 
    FILE *rules, *dic; 
    char pwline[MAXPWLINE], pwline2[MAXPWLINE], rawpw[MAXPWLINE]; 
    char *getpass(); 
    struct RULE *rtop, *prepit(); 
    int cracked; 
 
    switch (ac) { 
	case 3: 
	    rfile = av[1]; 
	    dfile = av[2]; 
	    break; 
	case 4: 
	    if (*av[1] == '-') { 
		for (flags = av[1] + 1; *flags != '\0'; flags++) { 
		    switch (*flags) { 
			case 'c': comment = 1; break; 
			case 's': showcracked = 1; break; 
			case 'd': debug = 1; break; 
			case 'a': acceptedrules = 1; break; 
			case 'p': showacceptrate = 1; break; 
			default: 
			    fprintf(stderr, "unknown option -%c\n", *flags); 
			    exit(-3); 
		    } 
		} 
		rfile = av[2]; 
		dfile = av[3]; 
		break; 
	    } 
	    /* don't break */ 
	default: 
	    fprintf(stderr, "%s\n", VERSION); 
	    fprintf(stderr, 
		"usage:\n\t%s [-csdap]  \n", *av); 
	    fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 
		"user options:", 
		"\tc: the dictionary has comment or empty lines", 
		"\ts: show matching rule and result if cracked", 
		"debug options:", 
		"\td: show debug info of processing", 
		"\ta: show all accepted rules", 
		"\tp: show rate of acception"); 
	    exit(-1); 
    } 
    /*** notice to the user ***/ 
    if (debug) { 
	fprintf(stderr, "WARNING: THE CANDIDATE WILL BE SHOWN\n"); 
	fflush(stdout); 
    } 
    if (showcracked) { 
	fprintf(stderr, 
	    "WARNING: THE CANDIDATE WILL BE SHOWN IF CRACKED\n"); 
	fflush(stdout); 
    } 
    if (acceptedrules) { 
	fprintf(stderr, 
	    "CAUTION: Hints for the candidate will be shown\n"); 
	fflush(stdout); 
    } 
    /* prompt user to input */ 
    fprintf(stderr, "Welcome to AntiCrack.\n"); 
    strcpy(pwline, getpass("Your password candidate: ")); 
    strcpy(pwline2, getpass("Type it again: ")); 
    if (strcmp(pwline, pwline2)) { 
	fprintf(stderr, "You typed different strings; try again.\n"); 
	exit(6); 
    } 
    if ((rules = fopen(rfile, "r")) == NULL) { 
	perror("fopen"); 
	exit(11); 
    } 
    if ((dic = fopen(dfile, "r")) == NULL) { 
	perror("fopen"); 
	exit(2); 
    } 
    /* truncate the password up to PWLEN characters */ 
    /* (it must have been done by getpass, but to be sure) */ 
    strncpy(rawpw, pwline, PWLEN); 
    rawpw[PWLEN] = '\0'; 
    if (debug) 
	message("debug: candidate is \"%s\"\n", rawpw); 
 
    rtop = prepit(rules, rawpw); 
    if (acceptedrules) 
	showrules(rtop); 
    if (docrack(rawpw, rtop, dic)) { 
	/* hit */ 
	fprintf(stderr, "Cracked. Try another candidate.\n"); 
	cracked = 1; 
    } else { 
	/* ok */ 
	fprintf(stderr, "Not Cracked.\n"); 
	cracked = 0; 
    } 
    fclose(rules); 
    fclose(dic); 
    exit(cracked); 
} 
 
/* load rules from file rejecting unsuitable ones */ 
struct RULE *prepit(rf, pw) 
FILE *rf; 
char *pw; 
{ 
    char rbuf[RBUFSIZE]; 
    void Trim(); 
    struct RULE top, *p; 
    int all=0, accepted=0; 
 
    p = ⊤ 
    while (fgets(rbuf, DBUFSIZE, rf) != NULL) { 
	Trim(rbuf); 
	if (rbuf[0] == '\0' || rbuf[0] == '#') 
	    continue; 
	all++; 
	if (rejrule(rbuf, pw) < 0) {	/* reject not suitable rules */ 
	    if (debug) 
		message("debug: Rejecting \"%s\"\n", rbuf); 
	    continue; 
	} else { 
	    if (debug) 
		message("debug: Accepting \"%s\"\n", rbuf); 
	} 
	accepted++; 
	p->next = (struct RULE *)Malloc(sizeof(struct RULE)); 
	p->next->rule = newstr(rbuf); 
	p = p->next; 
    } 
    p->next = NULL; 
    if (showacceptrate) 
	message("%d/%d rules are accepted\n", accepted, all); 
    return top.next; 
} 
 
docrack(pw, rules, df) 
char *pw; 
struct RULE *rules; 
FILE *df; 
{ 
    register char *mangled; 
    register struct RULE *rp; 
    struct RULE rtop; 
    char dword[DBUFSIZE]; 
 
    rtop.next = rules; 
    while (fgets(dword, DBUFSIZE, df) != NULL) { 
	if (comment) { 
	    Trim(dword);	/* remove space characters at end of line */ 
	    if (dword[0] == '\0' || dword[0] == '#') 
		continue;	/* skip comments and empty lines */ 
	} else { 
	    dword[strlen(dword)-1] = '\0';	/* remove the newline */ 
	} 
	rp = &rtop; 
	while (rp->next != NULL) { 
	    mangled = Mangle(dword, rp->next->rule); 
	    if (mangled == (char *)0) 
		goto contpoint;		/* the rule is rejected */ 
	    if (!strncmp(pw, mangled, PWLEN)) { 
		if (showcracked) 
		    message("\"%s\" (%s) -> \"%s\"\n", 
			dword, rp->next->rule, pw); 
		return 1; 
	    } 
contpoint: 
	    rp = rp->next; 
	} 
    } 
    return 0; 
} 
 
showrules(rules) 
struct RULE *rules; 
{ 
    struct RULE top, *rp; 
    top.next = rules; 
    rp = ⊤ 
    message("*** accepted rules ***\n"); 
    while (rp->next != NULL) { 
	message("\"%s\"\n", rp->next->rule); 
	rp = rp->next; 
    } 
    return; 
}