| Собственно, есть у нас есть producer - он вырабатывает новые задачи и добавляет их в очередь (в это примере стек). И есть несколько consumer'ов - он извлекает задачу из очереди и выполняет её. Задача - перебор пароля, и сравнение его хэша с введенным в программу хэшом. Диапазон перебора от 'a' до 'z' по аски. #include <stdlib.h> #include <stdio.h> #include <string.h> #include <crypt.h> #include <pthread.h> #include <semaphore.h> #define MAXXPASS_LEN 50 // макс. длина пароля #define MAXX_STACK_LEN 10000 // объём стека #define MAX_THREADS 5 // кол-во консюмеров struct task_d{ char *pass,*hash; // это структура задачи. содержит хэш и пароль }; struct tstack{ int length; // длина стека (кол-во задач в нём) struct task_d *task; // масив этих самых задач }; struct tstack *stack; // опишем глобально указатель на структуру стека char hash[50]; // а здесь будет введённый хэш, получаемый при запуске программы sem_t empts,fulls; // семафорчики, epmts - следит за кол-вом свободных задач в стека, fulls - количество занесенных задач в стека pthread_mutex_t crit; // для доступа к стеку на чтение / запись void push(struct tstack *s, struct task_d *tas){ // ну ничего интересного, помещает задачу в стек s->task=realloc(s->task,(sizeof(struct task_d))*(1+s->length)); s->task[s->length].pass=malloc(sizeof(char)*MAXXPASS_LEN); s->task[s->length].hash=malloc(sizeof(char)*MAXXPASS_LEN); strcpy(s->task[s->length].pass,tas->pass); strcpy(s->task[s->length].hash,tas->hash); s->length++; } void pop(struct tstack *s, struct task_d *tas){ // извлекает задачу из него if (s->length){ s->length--; strcpy(tas->pass,s->task[s->length].pass); strcpy(tas->hash,s->task[s->length].hash); free(s->task[s->length].hash); free(s->task[s->length].pass); s->task=realloc(s->task,(sizeof(struct task_d))*(s->length)); return; } tas->pass=tas->hash=NULL; } char *getnextpas(char *pass,int UP, int DO){ // вырабатывает новую задачу (зависит от предудыщей и от диапазона значение UP - DO [для простоты UP='a' ; DO='z'] int len,j=0; pass[0]= pass[0]+1; len=strlen(pass); for (;j<len-1;j++){ // какието хитрые действа if (pass[j]>DO) { pass[j]=UP; if (pass[j+1]!=0) { pass[j+1] = pass[j+1]+1; } else { pass[j+1] = UP; } } } if (pass[len-1]>DO){ pass[len]=UP; pass[len-1]=UP; if (pass[0]>DO){ pass[0]=UP; } } return pass; // вот и результат } int checkpas(struct task_d *task,struct crypt_data *data, char *hash){ // этим методом консюмер решает задачу return strcmp(hash,(crypt_r(task->pass,hash,data))); } void *consumer(void *argc){ // сам консюмер struct task_d *task=malloc(sizeof(struct task_d)); task->pass=malloc(sizeof(char)*MAXXPASS_LEN); task->hash=malloc(sizeof(char)*MAXXPASS_LEN); struct crypt_data *data=malloc(sizeof(struct crypt_data)); data->initialized=0; for(;;){ sem_wait(&fulls); // уменьшеть кол-во задач в стеке pthread_mutex_lock(&crit); // крит.секция pop(stack,task); // получить задачу из стека pthread_mutex_unlock(&crit); // крит.секция sem_post(&empts); // увеличени кол-ва извлеченных задач в стек if (task->pass!=task->hash) if (!checkpas(task,data,hash)) { // решает задачу printf("pass=%s\n",task->pass); // при успехе выводи результат и завершает программу exit(0); } } return NULL; } void *producer(void *argc){ char *lastpass=malloc(sizeof(char)*MAXXPASS_LEN); lastpass[0]='a'-1; struct task_d *task=malloc(sizeof(struct task_d)); task->pass=malloc(sizeof(char)*MAXXPASS_LEN); task->hash=malloc(sizeof(char)*MAXXPASS_LEN); for(;;){ sem_wait(&empts); //уменьшает кол-во свободных задач в стеке strcpy(task->pass,getnextpas(lastpass,'a','z')); // строим новую задачу strcpy(task->hash,hash); pthread_mutex_lock(&crit); // крит.секция push(stack,task); // добавляем её в стек pthread_mutex_unlock(&crit); // крит.секция sem_post(&fulls); // увеличееваем кол-во занесенных в стек задач } } int main (int argc, char **argv){ stack=malloc(sizeof(struct tstack)); stack->length=0; stack->task=NULL; pthread_t threads[MAX_THREADS]; strcpy(hash,argv[1]); sem_init(&fulls,0,0); // у нас изначально занесенных в стек задач 0 sem_init(&empts,0,MAXX_STACK_LEN); // а количество свободных мест в стеке MAXX_STACK_LEN pthread_mutex_init(&crit,NULL); int i=0; pthread_create(&threads[i],NULL,producer,NULL); // стартуем продюсера i++; for(;i<MAX_THREADS;i++){ pthread_create(&threads[i],NULL,consumer,NULL); // и консюмеров } pthread_join(threads[0],NULL); return 0; } компилируется так gcc stack.c -o stack -g -lcrypt -lpthread -D_GNU_SOURCE а запускать ./stack HASH где HASH - это хэш. чтото похожее на ZVfdoDq90ky6Y а ниже программа которая делает этот хэш... на каждый запуск выдаёт новый хэш (зависит от pid процесса) + может выдавать md5 хэши для crypt #include <crypt.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <features.h> int main (int argc, char **argv){ const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRST" "UVWXYZabcdefghijklmnopqrstuvwxyz"; char salt[11]; char hash[34]; srand(getpid()); if (argc<2) { printf("Usage: cr <pass> [-md5]\n"); return 1;} if (argc>2){ //md5 salt[0]='$';salt[1]='1';salt[2]='$'; for (int i=0;i<8;i++) salt[3+i]=seedchars[(int) (63.0 * (rand() / (RAND_MAX + 1.0)))]; } else { //des for (int i=0;i<2;i++) salt[i]=seedchars[(int) (63.0 * (rand() / (RAND_MAX + 1.0)))]; } printf("%s\n", strcpy(hash,crypt(argv[1],salt))); return 0; } она компилируется так gcc -g -lcrypt -lm -std=c99 -D_POSIX_C_SOURCE cr.c -o cr тогда в общем виде получаем, что можно запустить так ./stack $(./cr your_pass) где your_pass - ваш пароль.
|