/*
 password finder for xfd packed files
 (c) 1996-97 Denis Unger
 last changes: 14.03.97
*/

#define _VERSION "1.1"
#define __L_PASSWORD 100
#define __EVERYWORDS 1000
#define __MAXCHARS 5

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <exec/types.h>

#include <clib/xfdmaster_protos.h>
#include <pragma/xfdmaster_lib.h>
#include <libraries/xfdmaster.h>

#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>

struct Library *xfdMasterBase;

int flenght(FILE *file) {
 int l;
 int offset;

 offset = ftell(file);
 fseek(file,0,SEEK_END);
 l = ftell(file);
 fseek(file,offset,SEEK_SET);
 return(l);
}

void main(int argc, char **argv) {
 FILE *rfile = NULL; //source
 char source[FILENAME_MAX];
 FILE *wfile = NULL; //dest
 char dest[FILENAME_MAX];
 FILE *f_dic = NULL; //dictionary file
 FILE *f_chr = NULL; //character file
 int l,chrs_len;
 int i,j;
 int curr_chrs,curr_chr;
 int success;
 char *buffer;
 void *object;
 struct xfdBufferInfo bufferinfo;
 BOOL b_password = FALSE,b_key16 = FALSE,b_key32 = FALSE;
 BOOL b_dic = FALSE, b_pw = FALSE, b_chr = FALSE, b_ft = FALSE;
 char password[__L_PASSWORD];
 char dictionary[FILENAME_MAX],charfile[FILENAME_MAX];
 unsigned long filetype;
 char characters[256];
 int everywords,maxchars;
 int char_offs[__L_PASSWORD + 1];
 BOOL pw_ok;
 float time;
 int t0,t1;
 int words;

 const char version[] = "\0$VER: xfd_pwf " _VERSION " (" __DATE2__ ")";
 printf("XFD PassWordFinder (c) 1996-97 Denis Unger\n\n");

 xfdMasterBase = OpenLibrary( XFDM_NAME, XFDM_VERSION);
 if(!xfdMasterBase) {
    printf("Couldn't open " XFDM_NAME " %d\n", XFDM_VERSION);
    exit(0);
  }

 struct RDArgs *readargs;
 LONG rargs[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
 char uebergabe[] = "SOURCE/A,DEST/A,DIC/K,PW/K,CHR/K,EVERYWORDS/N,MAXCHARS/N,FILETYPE/N";

 if((readargs = ReadArgs( uebergabe, rargs, NULL))) {
    strcpy(source, (STRPTR) rargs[0]);
    strcpy(dest, (STRPTR) rargs[1]);
    if(rargs[2]) {strcpy(dictionary, (STRPTR) rargs[2]); b_dic = TRUE;}
    if(rargs[3]) {strcpy(password, (STRPTR) rargs[3]); b_pw = TRUE;}
    if(rargs[4]) {strcpy(charfile, (STRPTR) rargs[4]); b_chr = TRUE;}
    if(rargs[5]) everywords = *(LONG *)rargs[5]; else everywords = __EVERYWORDS;
    if(rargs[6]) maxchars = *(LONG *)rargs[6]; else maxchars = __MAXCHARS;
	if(rargs[7]) {filetype = *(LONG *)rargs[7]; b_ft = TRUE;}
    FreeArgs(readargs);
 } else {
	printf("Error: readargs (false syntax)\n");
    CloseLibrary(xfdMasterBase);
    exit(0);
 }

 rfile = fopen(source, "r");
 if(!rfile) {
    printf("Error opening file %s.\n",source);
    exit(0);
  }
 l = flenght(rfile);
 printf("Lenght of crunched file: %d Bytes\n",l);

 buffer = new char[l];
 fread(buffer,l,1,rfile);
 fclose(rfile);

 object = xfdAllocObject(XFDOBJ_BUFFERINFO);

 bufferinfo.xfdbi_SourceBuffer = buffer;
 bufferinfo.xfdbi_SourceBufLen = l;
 bufferinfo.xfdbi_Flags = 0;
 bufferinfo.xfdbi_PackerFlags = 0;

 success = xfdRecogBuffer(&bufferinfo);
 if(!success) {
    printf("error (%d): xfdRecogBuffer\n",bufferinfo.xfdbi_Error);
  }

 printf("Packer: %s\n",bufferinfo.xfdbi_PackerName);

 if(bufferinfo.xfdbi_PackerFlags & 1<<XFDPFB_PASSWORD) {
    printf(" crypted with password ...\n"); b_password = TRUE;
  }
 if(bufferinfo.xfdbi_PackerFlags & 1<<XFDPFB_KEY16) {
    printf(" crypted with key16 ...\n"); b_key16 = TRUE;
  }
 if(bufferinfo.xfdbi_PackerFlags & 1<<XFDPFB_KEY32) {
    printf(" crypted with key32 ...\n"); b_key32 = TRUE;
  }

 bufferinfo.xfdbi_TargetBufMemType = 0;

 t0 = clock();

 if(b_password && b_chr) {
    f_chr = fopen(charfile, "r");
    pw_ok = FALSE;
    if(f_chr) {
        if(fgets(characters, 255, f_chr)) chrs_len = strlen(characters);
        printf("Testing with %d characters.\n",chrs_len);
        fclose(f_chr);
        if(b_pw) { // ab bestimmtem password
            printf("Testing from password <%s> ...\n",password);
            curr_chrs = strlen(password);
            curr_chr = curr_chrs;
            for(j=0;j<=strlen(password);j++) {
                for(i=0;i<chrs_len;i++) {
                    if(password[j] == characters[i]) {
                        char_offs[j] = i;
                        break;
                    }
                }
            }
            for(j=(strlen(password)+1);j<__L_PASSWORD;j++) {
                password[j] = 0;
                char_offs[j] = 0;
            }
        } else {
            curr_chrs = 1;
            curr_chr = 0;
            for(j=0;j<__L_PASSWORD;j++) {
                password[j] = 0; //password mit 0 füllen
                char_offs[j] = 0; //offsets mit 0 füllen
            }
            printf("Testing all words with 1 character.\n");
        }
        i = 0;
        for(;;) {
            if(curr_chrs > maxchars) break; //erst mal aussteigen
            for(j=0;j<curr_chrs;j++)
                password[j] = characters[char_offs[j]]; //create password
            curr_chr = curr_chrs - 1;
            char_offs[curr_chr]++; //last character + 1
            if(char_offs[curr_chr] == chrs_len) {
                for(;;) {
                    curr_chr--;
                    if(curr_chr == -1) {
                        curr_chrs++; //password lenght + 1 character
                        printf("Testing all words with %d characters.\n",curr_chrs);
                        for(j=0;j<curr_chrs;j++) char_offs[j] = 0;
                        break;
                    }
                    char_offs[curr_chr]++; char_offs[curr_chr + 1] = 0;
                    if(char_offs[curr_chr]<chrs_len) break;
                }
            }
            i++;
            if(!(i % everywords)) printf("%d words checked (last password:%s)\n",i,password); //every ... words
            bufferinfo.xfdbi_Special = password;
            success = xfdDecrunchBuffer(&bufferinfo);
            if(success) {
            	if(b_ft) {
            		if(filetype == *(unsigned long *)bufferinfo.xfdbi_TargetBuffer) {
						pw_ok = TRUE;
            		}
            	} else pw_ok = TRUE;
				if(pw_ok) {
	                printf("Password is <%s>.\n",password);
	                FreeMem(bufferinfo.xfdbi_TargetBuffer,bufferinfo.xfdbi_TargetBufLen);
	                bufferinfo.xfdbi_TargetBuffer = NULL;
	                break;
	            }
            }

        }
    } else printf("Couldn't open character file %s.\n",charfile);
 } else
 if(b_password && b_dic) {
    f_dic = fopen(dictionary, "r");
    if(f_dic) {
        i = 0; pw_ok = FALSE;
        for(;;) {
            if(!fgets(password,__L_PASSWORD,f_dic)) {
                printf("No password found.\n");
                break;
            }
            i++;
            if(!(i % everywords)) printf("%d words checked (last password:%s)\n",i,password); //every ... words
            bufferinfo.xfdbi_Special = password;
            success = xfdDecrunchBuffer(&bufferinfo);
            if(success) {
            	if(b_ft) {
            		if(filetype == *(unsigned long *)bufferinfo.xfdbi_TargetBuffer) {
						pw_ok = TRUE;
            		}
            	} else pw_ok = TRUE;
				if(pw_ok) {
	                printf("Password is <%s>.\n",password);
	                FreeMem(bufferinfo.xfdbi_TargetBuffer,bufferinfo.xfdbi_TargetBufLen);
	                bufferinfo.xfdbi_TargetBuffer = NULL;
	                break;
                }
            }

        }
    } else printf("Couldn't open dictionary %s.\n",dictionary);
 } else
 if(b_password) {
    printf("password lenght: %d\n",bufferinfo.xfdbi_MaxSpecialLen);
    bufferinfo.xfdbi_Special = password;
 }
 words = i;

 success = xfdDecrunchBuffer(&bufferinfo);
 if(!success) {
    printf("Couldn't decrunch file.\n");
  }

 if(buffer) { //Ausgangsbuffer wird nicht mehr benötigt
    delete buffer; buffer = NULL;
 }

 printf("Lenght of decrunched file: %d Bytes\n",bufferinfo.xfdbi_TargetBufSaveLen);

 wfile = fopen( dest, "w");
 if(wfile) {
    fwrite(bufferinfo.xfdbi_TargetBuffer,bufferinfo.xfdbi_TargetBufSaveLen,1,wfile);
    fclose(wfile);
 } else printf("Couldn't create file %s.\n",dest);

 if(bufferinfo.xfdbi_TargetBuffer) {
    FreeMem(bufferinfo.xfdbi_TargetBuffer,bufferinfo.xfdbi_TargetBufLen);
    bufferinfo.xfdbi_TargetBuffer = NULL;
  }

 xfdFreeObject(object);

 t1 = clock();
 time = (t1-t0)/50.0;
 printf("%d words checked in %.2f seconds\n",words,time);
 printf("-> %.0f words per second\n",words/time);

 CloseLibrary(xfdMasterBase);
}
