Advertisement
Guest User

FileOpen

a guest
Jun 19th, 2010
487
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.77 KB | None | 0 0
  1. /* fileSaveAs.c
  2.  
  3. This program reads a pdf encrypted with the fileOpen plugin,
  4. and attempts to write a plain pdf.
  5.  
  6. Compile with:
  7. gcc -g -o fileSaveAs.exe -lssl -lcrypto fileSaveAs.c
  8.  
  9. To compile, you'll need packages libssl09-dev and libCrypto.
  10. This is a list of things that must be worked out:
  11.  
  12. 1) It does not decrypt strings, so there is no navigation bar on the left, no author, no additional info and such.
  13. 2) Often in the resulting pdf there are many white pages.
  14. 3) I had only one ebook to work with, so the salt that I have blatantly hardcoded may be different.
  15. 4) The ebook I have contains the strings '/FOPN_fLock /V 1', I guess that it is the version of the plugin. There certainly are other versions of the plugin, I don't know about them.
  16. 5) When printing, sometimes Acrobat Reader says that there are illegal characters.
  17.  
  18. So much to do...
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <openssl/md5.h>
  23. #include <sys/stat.h>
  24. #include <sys/fcntl.h>
  25. #include <getopt.h>
  26.  
  27. #define MAX_OBJ_LEN 2000000
  28. #define STREAM_STR "stream"
  29. #define END_STREAM_STR "endstream"
  30. #define OBJ_STR " obj"
  31. #define END_OBJ_DELIM "endobj"
  32. #define ENCRYPTION_STRING "/Encrypt"
  33.  
  34. /* I know this is ugly, but hey, I said there is much to do! Begin here! */
  35. unsigned char pObjBuf[MAX_OBJ_LEN];
  36.  
  37. #define SHUFFLEUP(YY, XX, ZZ, AA) { \
  38. YY=0; \
  39. YY=(char)*ZZ; \
  40. YY=YY << XX; \
  41. AA |= YY; \
  42. ZZ++; }
  43.  
  44. unsigned char S[256];
  45. unsigned char K[256];
  46.  
  47. /* This is the only thing they added on top of plain RC4. */
  48. void superSecret (unsigned char *pData, int nIntParam, MD5_CTX *pMd5Ctx)
  49. {
  50. unsigned long lTmp1,
  51. lTmp2,
  52. lTmp3,
  53. lTmp4,
  54. lTmp5,
  55. lTmp6,
  56. lTmp7;
  57. unsigned long *plPoint1;
  58. unsigned char *plMainPnt;
  59.  
  60. plMainPnt=pData;
  61. if(0 == nIntParam)
  62. return;
  63. lTmp4=pMd5Ctx->Nl;
  64. lTmp7=nIntParam;
  65. lTmp7=lTmp7<<3;
  66. lTmp4+= lTmp7;
  67. lTmp4 &= 0xFF;
  68. if(lTmp4<pMd5Ctx->Nl)
  69. pMd5Ctx->Nh++;
  70. lTmp6=nIntParam;
  71. lTmp6=lTmp6 >> 0x1d;
  72. pMd5Ctx->Nh+= lTmp6;
  73. pMd5Ctx->Nl=lTmp4;
  74.  
  75. if(0!= pMd5Ctx->num) {
  76. plPoint1=(unsigned long *)pMd5Ctx->data;
  77. lTmp5=pMd5Ctx->num;
  78. lTmp5=lTmp5 >> 2;
  79. lTmp7=pMd5Ctx->num;
  80. lTmp7&= 3;
  81. lTmp1=lTmp7;
  82. lTmp4=pMd5Ctx->num;
  83. lTmp4+= nIntParam;
  84. if(lTmp4>= 0x40) {
  85. lTmp4=plPoint1[lTmp5];
  86. switch(lTmp1) {
  87. case 0:
  88. SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
  89. case 1:
  90. SHUFFLEUP(lTmp7, 8, plMainPnt, lTmp4);
  91. case 2:
  92. SHUFFLEUP(lTmp6,0x10, plMainPnt, lTmp4);
  93. case 3:
  94. SHUFFLEUP(lTmp7, 0x18, plMainPnt, lTmp4);
  95. }
  96. plPoint1[lTmp5]=lTmp4;
  97.  
  98. lTmp5++;
  99. if(lTmp5 <0x10) {
  100. do {
  101. SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
  102. SHUFFLEUP(lTmp6, 8, plMainPnt, lTmp4);
  103. SHUFFLEUP(lTmp7, 0x10, plMainPnt, lTmp4);
  104. SHUFFLEUP(lTmp6, 0x18, plMainPnt, lTmp4);
  105. plPoint1[lTmp5]=lTmp4;
  106. } while(lTmp5<10);
  107. }
  108. lTmp7=0x40-pMd5Ctx->num;
  109. nIntParam-= lTmp7;
  110. MD5_Update (pMd5Ctx, (unsigned char *)plPoint1, 0x40);
  111. pMd5Ctx->num;
  112. } else {
  113. pMd5Ctx->num+= nIntParam;
  114. if(lTmp1+nIntParam<4) {
  115. lTmp4=plPoint1[lTmp5];
  116. switch(lTmp1) {
  117. case 0:
  118. SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
  119. nIntParam--;
  120. if(0 == nIntParam)
  121. break;
  122. case 1:
  123. SHUFFLEUP(lTmp7, 8, plMainPnt, lTmp4);
  124. nIntParam--;
  125. if(0 == nIntParam)
  126. break;
  127. case 2:
  128. SHUFFLEUP(lTmp6, 0x10, plMainPnt, lTmp4);
  129. }
  130. plPoint1[lTmp5]=lTmp4;
  131. return;
  132. }
  133. lTmp7=pMd5Ctx->num;
  134. lTmp7=lTmp7 >> 2;
  135. lTmp3=lTmp7;
  136. lTmp2=pMd5Ctx->num & 3;
  137. lTmp4=((unsigned char *)plPoint1)[4*lTmp5];
  138.  
  139. switch(lTmp1) {
  140. case 0:
  141. SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
  142. case 1:
  143. SHUFFLEUP(lTmp7, 8, plMainPnt, lTmp4);
  144. case 2:
  145. SHUFFLEUP(lTmp6, 0x10, plMainPnt, lTmp4);
  146. case 3:
  147. SHUFFLEUP(lTmp7, 0x18, plMainPnt, lTmp4);
  148. }
  149. plPoint1[lTmp5++]=lTmp4;
  150. if(lTmp5<lTmp3) {
  151. do {
  152. SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
  153. SHUFFLEUP(lTmp6, 8, plMainPnt, lTmp4);
  154. SHUFFLEUP(lTmp7, 0x10, plMainPnt, lTmp4);
  155. SHUFFLEUP(lTmp6, 0x18, plMainPnt, lTmp4);
  156. plPoint1[lTmp5++]=lTmp4;
  157. } while(lTmp5<lTmp3);
  158. }
  159. if(0 == lTmp2)
  160. return;
  161. lTmp4=0;
  162. plMainPnt+= lTmp2;
  163. switch(lTmp2) {
  164. case 0:
  165. plMainPnt--;
  166. lTmp4=0;
  167. lTmp4=(char)*plMainPnt;
  168. lTmp4 << 0x10;
  169. case 2:
  170. plMainPnt--;
  171. lTmp6=0;
  172. lTmp6=(char)*plMainPnt;
  173. lTmp6<<8;
  174. lTmp4|= lTmp6;
  175. case 1:
  176. plMainPnt--;
  177. lTmp7=0;
  178. lTmp7=(char)*plMainPnt;
  179. lTmp4|= lTmp7;
  180. case 3:
  181. plPoint1[lTmp5]=lTmp4;
  182. return;
  183. }
  184. }
  185. }
  186. if(0 == ((unsigned long)plMainPnt & 0x3)) {
  187. lTmp5=nIntParam;
  188. if ((lTmp5>> 6) >0) {
  189. lTmp5=lTmp5<<6;
  190. MD5_Update (pMd5Ctx, (unsigned char *)plMainPnt, lTmp5);
  191. plMainPnt+= lTmp5;
  192. nIntParam-= lTmp5;
  193. }
  194. }
  195. plPoint1=(unsigned long *)pMd5Ctx->data;
  196. if(nIntParam>= 0x40) {
  197. do {
  198. if(plMainPnt!= (unsigned char *)plPoint1) {
  199. memcpy((unsigned char *)plPoint1, plMainPnt, 0x40);
  200. }
  201. plMainPnt+= 0x40;
  202. MD5_Update (pMd5Ctx, (unsigned char *)pMd5Ctx->data, 0x40);
  203. } while(nIntParam>= 0x40);
  204. }
  205. lTmp1=nIntParam;
  206. pMd5Ctx->num=lTmp1;
  207. if(0 == lTmp1)
  208. return;
  209. lTmp5=lTmp1>>2;
  210. plPoint1[lTmp5]=0;
  211. memcpy((unsigned char *)plPoint1, plMainPnt, lTmp1);
  212. }
  213.  
  214. /* From 'Applied Cryptography'.
  215. Yes, they used an algorithm from a book. I can understand: after all, it is a good algorithm.
  216. But If I wanted to distribute some encrypted data, I wouldn't put the algorithm _AND_ the key in the same place. */
  217.  
  218. void CreateRc4Sbox
  219. (
  220. unsigned char *pKeySeed
  221. )
  222. {
  223. int i=0;
  224. int j=0;
  225. int nRealIndex;
  226. unsigned char nTemp;
  227.  
  228. for (i=0; i<256; i++)
  229. S[i]=i;
  230.  
  231. for (i=0; i<256; i++)
  232. K[i]=pKeySeed[i%16];
  233. nRealIndex=0;
  234. for (i=0; i<256; i++) {
  235. j=(j + S[i] + K[nRealIndex])%256;
  236. nRealIndex++;
  237. if(nRealIndex>9)
  238. nRealIndex=0;
  239. nTemp=S[i];
  240. S[i]=S[j];
  241. S[j]=nTemp;
  242. }
  243. }
  244.  
  245. /* Also from the book */
  246. int Rc4Decrypt
  247. (
  248. char *pCryptoData,
  249. int nCryptoBufLen,
  250. char *pResults,
  251. int nResultsBufSize,
  252. unsigned char *SBox
  253. )
  254. {
  255. short nByte;
  256. int nClearPos=0,
  257. nBuf=0,
  258. nBuf2=0,
  259. nCount,
  260. nSwap,
  261. nLength=nCryptoBufLen,
  262. nAdv;
  263. while(0!= nLength) {
  264. nBuf++;
  265. nBuf &= 0xFF;
  266. nCount=SBox[nBuf];
  267. nBuf2 += nCount;
  268. nBuf2 &= 0xFF;
  269. nSwap=SBox[nBuf2];
  270. nAdv=nSwap;
  271. SBox[nBuf]=nSwap;
  272. SBox[nBuf2]=nCount;
  273. nCount += nAdv;
  274. nCount &= 0xFF;
  275. nByte=SBox[nCount];
  276. nByte ^= *pCryptoData;
  277. nClearPos++;
  278. *pResults=nByte;
  279. ++pCryptoData;
  280. ++pResults;
  281. nLength--;
  282. }
  283. return nClearPos;
  284. }
  285.  
  286. /* this function calculates the key and executes the RC4 decrypt loop. Here I have hardcoded the salt: 'DgNab'.
  287. It may change in other ebooks but I only have one... */
  288.  
  289. int mainDecryptLoop (unsigned char * pCryptText, int nCryptSize, unsigned char * pClearBuffer, int nClearBufferSize, int nNumObj)
  290. {
  291. unsigned char rc4Key[16],
  292. keyBuf[8];
  293. int nClearLength, nIdx;
  294. MD5_CTX md5Ctx;
  295. unsigned char salt[20];
  296.  
  297. for(nIdx=0; nIdx<8; nIdx++)
  298. keyBuf[nIdx]=0;
  299.  
  300. *(int*)keyBuf=nNumObj;
  301. strcpy(salt, "DgNab");
  302. MD5_Init(&md5Ctx);
  303. superSecret(salt, 5, &md5Ctx);
  304. superSecret(keyBuf, 3, &md5Ctx);
  305. superSecret(keyBuf+4, 2, &md5Ctx);
  306. MD5_Final(rc4Key, &md5Ctx);
  307. CreateRc4Sbox(rc4Key);
  308. nClearLength=Rc4Decrypt(pCryptText, nCryptSize, pClearBuffer, nClearBufferSize, S);
  309. return nClearLength;
  310. }
  311.  
  312. /* The following is just some PDF parsing. The juicy part is over, I'm afraid... */
  313.  
  314. int removeSecurityString (unsigned char *pBeginBlock, unsigned char *pEndBlock)
  315. {
  316. unsigned char *pTemp;
  317. for(pTemp=pBeginBlock; pTemp!=pEndBlock; pTemp++) {
  318. if(!strncmp(pTemp, ENCRYPTION_STRING, strlen(ENCRYPTION_STRING))) {
  319. while('\n'!=*pTemp && '\r'!=*pTemp) {
  320. *pTemp=' ';
  321. pTemp++;
  322. }
  323. }
  324. }
  325.  
  326. return 0;
  327. }
  328.  
  329. int scanFile
  330. (const int fh, const int ofh, int *pnWrote)
  331. {
  332. int numObject, nCryptLen, nClearTextLength, bStayThere;
  333. unsigned char *pStart, *pStartCrypted, *pBeginBlock, *pCurrent;
  334.  
  335. for(;;) {
  336. bStayThere=1;
  337. pCurrent=pObjBuf;
  338. pCurrent+=strlen(OBJ_STR);
  339. pStart=pCurrent;
  340.  
  341. while(bStayThere) {
  342. if(1>read(fh,pCurrent,1)) {
  343. removeSecurityString(pBeginBlock, pCurrent);
  344. write(ofh, pBeginBlock, pCurrent-pBeginBlock);
  345. return 0;
  346. }
  347.  
  348. if(!strncmp(pCurrent-strlen(OBJ_STR), OBJ_STR, strlen(OBJ_STR))) {
  349. pCurrent++;
  350. write(ofh, pStart, pCurrent-pStart);
  351. while(*pCurrent!=' ')
  352. pCurrent--;
  353. pCurrent--;
  354. while(*pCurrent!=' ')
  355. pCurrent--;
  356. *pCurrent=0;
  357. numObject=atoi(pStart);
  358. bStayThere=0;
  359. }
  360. pCurrent++;
  361. }
  362.  
  363. pCurrent=pObjBuf;
  364. pCurrent+=strlen(END_OBJ_DELIM);
  365. pBeginBlock=pCurrent;
  366. bStayThere=1;
  367. while(bStayThere) {
  368. if(1>read(fh,pCurrent,1)) {
  369. write(ofh, pBeginBlock, pCurrent-pBeginBlock);
  370. return 0;
  371. }
  372.  
  373. if(strncmp(pCurrent-strlen(END_OBJ_DELIM), END_OBJ_DELIM, strlen(END_OBJ_DELIM))) {
  374. pCurrent++;
  375. continue;
  376. }
  377.  
  378. for(pStart=pObjBuf-strlen(END_OBJ_DELIM); pStart!=pCurrent ; pStart++ ) {
  379. if(!bStayThere)
  380. break;
  381. if(strncmp(pStart, STREAM_STR, strlen(STREAM_STR)))
  382. continue;
  383. pStartCrypted=pStart+strlen(STREAM_STR)+2;
  384. for(pStart=pStartCrypted; pStart!=pCurrent ; pStart++) {
  385. if(strncmp(pStart, END_STREAM_STR, strlen(END_STREAM_STR)))
  386. continue;
  387. nCryptLen=pStart-pStartCrypted-1;
  388. nClearTextLength=mainDecryptLoop(pStartCrypted,nCryptLen,pStartCrypted,nCryptLen,numObject);
  389. bStayThere=0;
  390. break;
  391. }
  392. }
  393. write(ofh, pBeginBlock, 1+pCurrent-pBeginBlock);
  394. bStayThere=0;
  395. }
  396. }
  397. return 0;
  398. }
  399.  
  400. int Usage
  401. (
  402. const char *szMessage
  403. )
  404. {
  405. fprintf(stderr, "%s\n", szMessage);
  406. fprintf(stderr, "Usage: \n");
  407. fprintf(stderr, "-h : this message\n");
  408. fprintf(stderr, "-i file : input file\n");
  409. fprintf(stderr, "-o file : output file\n");
  410. return 255;
  411. }
  412.  
  413. int main (int argc, char **argv)
  414. {
  415. int ifh, ofh, nWrote, nOffs;
  416. char *strInputFileName, *strOutputFileName, ch;
  417. struct stat statStruct;
  418. strInputFileName=NULL;
  419. strOutputFileName=NULL;
  420.  
  421. while((ch=getopt(argc, argv, "hi:o:"))!= -1) {
  422. switch(ch) {
  423. case 'h':
  424. return Usage("Help message requested");
  425. break;
  426. case 'i':
  427. strInputFileName=optarg;
  428. break;
  429. case 'o':
  430. strOutputFileName=optarg;
  431. break;
  432. }
  433. }
  434.  
  435. if(NULL == strInputFileName)
  436. return Usage("Must give input file");
  437.  
  438. if(NULL == strOutputFileName)
  439. return Usage("Must give output file");
  440.  
  441. if(stat(strInputFileName, &statStruct))
  442. return Usage("Error opening input file");
  443.  
  444. ifh=open(strInputFileName, O_RDONLY);
  445. ofh=open(strOutputFileName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
  446.  
  447. nWrote=0;
  448. if(scanFile(ifh, ofh, &nWrote))
  449. return Usage("Problems scanning file");
  450.  
  451. close(ifh);
  452. close(ofh);
  453. return 0;
  454. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement