Inital commit
[rarcrack.git] / src / rarcrack.c
blob5d340fc49ff8d4b2f3c6ceeea8aaf269acfdbf23
1 /*
2 * Copyright (C) 2009 by David Kedves <kedazo@gmail.com>
4 * This file is part of rarcrack.
6 * Rarcrack is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Rarcrack is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with rarcrack. If not, see <http://www.gnu.org/licenses/>.
21 #include "rarcrack.h"
23 /* TODO: on crack i need to use system() call, it's working on win/linux/macosx...
24 * eg.:
25 * #include <stdlib.h>
26 #include <stdio.h>
28 #define TRUE 1
30 int main(int argc, char** argv) {
31 while (TRUE) {
32 int ret = system("7z t -y -p10f0 test.7z");
33 printf("Return: %d\n", ret);
35 return 0;
40 char* ABC = (char*) &default_ABC;
41 int ABCLEN;
43 char password[PWD_LEN+1] = {'\0','\0'}; //this contains the actual password
44 char password_good[PWD_LEN+1] = {'\0', '\0'}; //this changed only once, when we found the good passord
45 unsigned int curr_len = 1; //current password length
46 long counter = 0; //this couning probed passwords
47 xmlMutexPtr pwdMutex; //mutex for password char array
48 char filename[255]; //the archive file name
49 char statname[259]; //status xml file name filename + ".xml"
50 xmlDocPtr status;
51 int finished = 0;
52 xmlMutexPtr finishedMutex;
53 char finalcmd[300] = {'\0', '\0'}; //this depending on arhive file type, it's a command to test file with password
55 char * getfirstpassword() {
56 static char ret[2];
57 ret[0] = ABC[0];
58 ret[1] = '\0';
59 return (char*) &ret;
62 inline void savestatus() {
63 xmlNodePtr root = NULL;
64 xmlNodePtr node = NULL;
65 xmlChar* tmp = NULL;
66 if ((strlen(statname) > 0) && (status != NULL)) {
67 root = xmlDocGetRootElement(status);
68 if (root) {
69 xmlMutexLock(finishedMutex);
70 for (node = root->children; node; node = node->next) {
71 if (xmlStrcmp(node->name, "current") == 0) {
72 xmlMutexLock(pwdMutex);
73 tmp = xmlEncodeEntitiesReentrant(status, (const xmlChar*) &password);
74 xmlMutexUnlock(pwdMutex);
75 if (node->children) {
76 if (password[0] == '\0')
77 xmlNodeSetContent(node->children, getfirstpassword());
78 else
79 xmlNodeSetContent(node->children, tmp);
81 xmlFree(tmp);
82 } else if ((finished == 1) && (xmlStrcmp(node->name,"good_password") == 0)) {
83 tmp = xmlEncodeEntitiesReentrant(status, (const xmlChar*) &password_good);
84 if (node->children)
85 xmlNodeSetContent(node->children, tmp);
86 xmlFree(tmp);
89 xmlMutexUnlock(finishedMutex);
91 xmlSaveFormatFileEnc(statname, status, "UTF-8", 1);
93 return;
96 inline int abcnumb(char a) {
97 int i;
98 for (i = 0; i<ABCLEN; i++)
99 if (ABC[i] == a) return i;
100 return 0;
103 int loadstatus() {
104 xmlNodePtr root = NULL;
105 xmlNodePtr node = NULL;
106 xmlParserCtxtPtr parserctxt;
107 int ret = 0;
108 char* tmp;
109 FILE* totest;
110 totest = fopen(statname, "r");
111 if (totest != NULL) {
112 fclose(totest);
113 status = xmlParseFile(statname);
115 if (status != NULL)
116 root = xmlDocGetRootElement(status);
117 else
118 status = xmlNewDoc(NULL);
119 if (root != NULL) {
120 parserctxt = xmlNewParserCtxt();
121 for (node = root->children; node; node = node->next) {
122 if (xmlStrcmp(node->name, "abc") == 0) {
123 if (node->children && (strlen(node->children->content) > 0)) {
124 ABC = xmlStringDecodeEntities(parserctxt,
125 node->children->content,XML_SUBSTITUTE_BOTH,0,0,0);
126 } else
127 ret = 1;
128 } else if (xmlStrcmp(node->name, "current") == 0) {
129 if (node->children && (strlen(node->children->content) > 0)) {
130 tmp = xmlStringDecodeEntities(parserctxt,
131 node->children->content,XML_SUBSTITUTE_BOTH,0,0,0);
132 strcpy(password,tmp);
133 curr_len = strlen(password);
134 printf("INFO: Resuming cracking from password: '%s'\n",password);
135 xmlFree(tmp);
136 } else
137 ret = 1;
138 } else if (xmlStrcmp(node->name, "good_password") == 0) {
139 if (node->children && (strlen(node->children->content) > 0)) {
140 tmp = xmlStringDecodeEntities(parserctxt,
141 node->children->content,XML_SUBSTITUTE_BOTH,0,0,0);
142 strcpy(password,tmp);
143 curr_len = strlen(password);
144 xmlMutexLock(finishedMutex);
145 finished = 1;
146 xmlMutexUnlock(finishedMutex);
147 strcpy((char*) &password_good, (char*) &password);
148 printf("GOOD: This archive was succesfully cracked\n");
149 printf(" The good password is: '%s'\n", password);
150 xmlFree(tmp);
151 ret = 1;
155 xmlFreeParserCtxt(parserctxt);
156 } else {
157 root = xmlNewNode(NULL, "rarcrack");
158 xmlDocSetRootElement(status, root);
159 node = xmlNewTextChild(root, NULL, "abc", ABC);
160 node = xmlNewTextChild(root, NULL, "current", getfirstpassword());
161 node = xmlNewTextChild(root, NULL, "good_password", "");
162 savestatus();
164 return ret;
167 void nextpass2(char* p, unsigned int n) {
168 int i;
169 if (p[n] == ABC[ABCLEN-1]) {
170 p[n] = ABC[0];
171 if (n>0)
172 nextpass2(p, n-1);
173 else {
174 for (i=curr_len; i>=0; i--)
175 p[i+1]=p[i];
176 p[0]=ABC[0];
177 p[++curr_len]='\0';
180 } else
181 p[n] = ABC[abcnumb(p[n])+1];
182 return;
185 inline char* nextpass() { //IMPORTANT: the returned string must be freed
186 char *ok = malloc(sizeof(char)*(PWD_LEN+1));
187 xmlMutexLock(pwdMutex);
188 strcpy(ok, password);
189 nextpass2((char*) &password, curr_len - 1);
190 xmlMutexUnlock(pwdMutex);
191 return ok;
194 void * status_thread() {
195 int pwds;
196 const short status_sleep = 3;
197 while(!finished) {
198 xmlMutexLock(finishedMutex);
199 pwds = counter / status_sleep;
200 counter = 0;
201 xmlMutexUnlock(finishedMutex);
202 xmlMutexLock(pwdMutex);
203 printf("Probing: '%s' [%d pwds/sec]\n", password, pwds);
204 xmlMutexUnlock(pwdMutex);
205 savestatus();
206 sleep(status_sleep);
210 void * crack_thread() {
211 char * current;
212 char ret[200];
213 char cmd[400];
214 FILE * Pipe;
215 while (1) {
216 current = nextpass();
217 sprintf((char*)&cmd, finalcmd, current, filename);
218 Pipe = popen(cmd, "r");
219 while (!feof(Pipe)) {
220 fgets((char*)&ret, 200, Pipe);
221 if (strcasestr(ret, "ok") != NULL) {
222 strcpy(password_good, current);
223 xmlMutexLock(finishedMutex);
224 finished = 1;
225 printf("GOOD: password cracked: '%s'\n", current);
226 xmlMutexUnlock(finishedMutex);
227 savestatus();
228 break;
231 pclose(Pipe);
232 xmlMutexLock(finishedMutex);
233 counter++;
234 if (finished != 0) {
235 xmlMutexUnlock(finishedMutex);
236 break;
238 xmlMutexUnlock(finishedMutex);
239 free(current);
243 void crack_start(unsigned int threads) {
244 pthread_t th[13];
245 unsigned int i;
246 for (i = 0; i < threads; i++) {
247 (void) pthread_create(&th[i], NULL, crack_thread, NULL);
249 (void) pthread_create(&th[12], NULL, stats_thread, NULL);
250 for (i = 0; i < threads; i++) {
251 (void) pthread_join(th[i], NULL);
253 (void) pthread_join(th[12], NULL);
254 return;
257 void init(int argc, char **argv) {
258 unsigned int i, j;
259 int help = 0;
260 int threads = 2;
261 int archive_type = -1;
262 FILE* totest;
263 char test[300];
264 xmlInitThreads();
265 pwdMutex = xmlNewMutex();
266 finishedMutex = xmlNewMutex();
267 if (argc == 1) {
268 printf("USAGE: rarcrack encrypted_archive.ext [--threads NUM] [--type rar|zip|7z]\n");
269 printf(" For more information please run \"rarcrack --help\"\n");
270 help = 1;
271 } else {
272 for (i = 1; i < argc; i++) {
273 if (strcmp(argv[i],"--help") == 0) {
274 printf("Usage: rarcrack encrypted_archive.ext [--threads NUM] [--type rar|zip|7z]\n\n");
275 printf("Options: --help: show this screen.\n");
276 printf(" --type: you can specify the archive program, this needed when\n");
277 printf(" the program couldn't detect the proper file type\n");
278 printf(" --threads: you can specify how many threads\n");
279 printf(" will be run, maximum 12 (default: 2)\n\n");
280 printf("Info: This program supports only RAR, ZIP and 7Z encrypted archives.\n");
281 printf(" RarCrack! usually detects the archive type.\n\n");
282 help = 1;
283 break;
284 } else if (strcmp(argv[i],"--threads") == 0) {
285 if ((i + 1) < argc) {
286 sscanf(argv[++i], "%d", &threads);
287 if (threads < 1) threads = 1;
288 if (threads > 12) {
289 printf("INFO: number of threads adjusted to 12\n");
290 threads = 12;
292 } else {
293 printf("ERROR: missing parameter for option: --threads!\n");
294 help = 1;
296 } else if (strcmp(argv[i],"--type") == 0) {
297 if ((i + 1) < argc) {
298 sscanf(argv[++i], "%s", &test);
299 for (j = 0; strcmp(TYPE[j], "") != 0; j++) {
300 if (strcmp(TYPE[j], test) == 0) {
301 strcpy(finalcmd, CMD[j]);
302 archive_type = j;
303 break;
306 if (archive_type < 0) {
307 printf("WARNING: invalid parameter --type %s!\n", argv[i]);
308 finalcmd[0] = '\0';
310 } else {
311 printf("ERROR: missing parameter for option: --type!\n");
312 help = 1;
314 } else {
315 strcpy((char*)&filename, argv[i]);
319 if (help == 1)
320 return;
321 sprintf((char*)&statname,"%s.xml",(char*)&filename);
322 totest = fopen(filename,"r");
323 if (totest == NULL) {
324 printf("ERROR: The specified file (%s) is not exists or \n", filename);
325 printf(" you don't have a right permissions!\n");
326 return;
327 } else
328 fclose(totest);
329 if (finalcmd[0] == '\0') { //when we specify the file type, the programm will skip the test
330 sprintf((char*)&test, CMD_DETECT, filename);
331 totest = popen(test,"r");
332 fscanf(totest,"%s",(char*)&test);
333 pclose(totest);
334 for (i = 0; strcmp(MIME[i],"") != 0; i++) {
335 if (strcmp(MIME[i],test) == 0) {
336 strcpy(finalcmd,CMD[i]);
337 archive_type = i;
338 break;
341 printf("INFO: detected file type: %s\n", TYPE[archive_type]);
342 } else
343 printf("INFO: the specified archive type: %s\n", TYPE[archive_type]);
344 if (finalcmd[0] == '\0') {
345 printf("ERROR: Couldn't detect archive type\n");
346 return;
348 printf("INFO: cracking %s, status file: %s\n", filename, statname);
349 if (loadstatus() == 1) {
350 printf("ERROR: The status file (%s) is corrupted!\n", statname);
351 return;
353 ABCLEN = strlen(ABC);
354 if (password[0] == '\0')
355 password[0] = ABC[0];
356 crack_start(threads);
357 return;