Code:
/* fileSaveAs.c
This program reads a pdf encrypted with the fileOpen plugin,
and attempts to write a plain pdf.
Compile with:
gcc -g -o fileSaveAs -lssl -lcrypto fileSaveAs.c
To compile, you'll need packages libssl09-dev and libCrypto.
This is a list of things that must be worked out:
1) It does not decrypt strings, so there is no navigation
bar on the left, no author, no additional info and such.
2) Often in the resulting pdf there are many white pages.
3) I had only one ebook to work with, so the salt that
I have blatantly hardcoded may be different.
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.
5) When printing, sometimes acrobat reader says that there
are illegal characters.
So much to do...
*/
#include <stdio.h>
#include <openssl/md5.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <getopt.h>
#define MAX_OBJ_LEN 2000000
#define STREAM_STR "stream"
#define END_STREAM_STR "endstream"
#define OBJ_STR " obj"
#define END_OBJ_DELIM "endobj"
#define ENCRYPTION_STRING "/Encrypt"
/* I know this is ugly, but hey, I said there is much
to do! Begin here! */
unsigned char pObjBuf[MAX_OBJ_LEN];
#define SHUFFLEUP(YY, XX, ZZ, AA) { \
YY=0; \
YY=(char)*ZZ; \
YY=YY << XX; \
AA |= YY; \
ZZ++; }
unsigned char S[256];
unsigned char K[256];
/* This is the only thing they added on top of plain RC4. */
void superSecret
(
unsigned char *pData,
int nIntParam,
MD5_CTX *pMd5Ctx
)
{
unsigned long lTmp1,
lTmp2,
lTmp3,
lTmp4,
lTmp5,
lTmp6,
lTmp7;
unsigned long *plPoint1;
unsigned char *plMainPnt;
plMainPnt=pData;
if(0 == nIntParam)
return;
lTmp4=pMd5Ctx->Nl;
lTmp7=nIntParam;
lTmp7=lTmp7<<3;
lTmp4+= lTmp7;
lTmp4 &= 0xFF;
if(lTmp4<pMd5Ctx->Nl)
pMd5Ctx->Nh++;
lTmp6=nIntParam;
lTmp6=lTmp6 >> 0x1d;
pMd5Ctx->Nh+= lTmp6;
pMd5Ctx->Nl=lTmp4;
if(0!= pMd5Ctx->num) {
plPoint1=(unsigned long *)pMd5Ctx->data;
lTmp5=pMd5Ctx->num;
lTmp5=lTmp5 >> 2;
lTmp7=pMd5Ctx->num;
lTmp7&= 3;
lTmp1=lTmp7;
lTmp4=pMd5Ctx->num;
lTmp4+= nIntParam;
if(lTmp4>= 0x40) {
lTmp4=plPoint1[lTmp5];
switch(lTmp1) {
case 0:
SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
case 1:
SHUFFLEUP(lTmp7, 8, plMainPnt, lTmp4);
case 2:
SHUFFLEUP(lTmp6,0x10, plMainPnt, lTmp4);
case 3:
SHUFFLEUP(lTmp7, 0x18, plMainPnt, lTmp4);
}
plPoint1[lTmp5]=lTmp4;
lTmp5++;
if(lTmp5 <0x10) {
do {
SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
SHUFFLEUP(lTmp6, 8, plMainPnt, lTmp4);
SHUFFLEUP(lTmp7, 0x10, plMainPnt, lTmp4);
SHUFFLEUP(lTmp6, 0x18, plMainPnt, lTmp4);
plPoint1[lTmp5]=lTmp4;
} while(lTmp5<10);
}
lTmp7=0x40-pMd5Ctx->num;
nIntParam-= lTmp7;
MD5_Update (pMd5Ctx, (unsigned char *)plPoint1, 0x40);
pMd5Ctx->num;
} else {
pMd5Ctx->num+= nIntParam;
if(lTmp1+nIntParam<4) {
lTmp4=plPoint1[lTmp5];
switch(lTmp1) {
case 0:
SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
nIntParam--;
if(0 == nIntParam)
break;
case 1:
SHUFFLEUP(lTmp7, 8, plMainPnt, lTmp4);
nIntParam--;
if(0 == nIntParam)
break;
case 2:
SHUFFLEUP(lTmp6, 0x10, plMainPnt, lTmp4);
}
plPoint1[lTmp5]=lTmp4;
return;
}
lTmp7=pMd5Ctx->num;
lTmp7=lTmp7 >> 2;
lTmp3=lTmp7;
lTmp2=pMd5Ctx->num & 3;
lTmp4=((unsigned char *)plPoint1)[4*lTmp5];
switch(lTmp1) {
case 0:
SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
case 1:
SHUFFLEUP(lTmp7, 8, plMainPnt, lTmp4);
case 2:
SHUFFLEUP(lTmp6, 0x10, plMainPnt, lTmp4);
case 3:
SHUFFLEUP(lTmp7, 0x18, plMainPnt, lTmp4);
}
plPoint1[lTmp5++]=lTmp4;
if(lTmp5<lTmp3) {
do {
SHUFFLEUP(lTmp4, 0, plMainPnt, lTmp4);
SHUFFLEUP(lTmp6, 8, plMainPnt, lTmp4);
SHUFFLEUP(lTmp7, 0x10, plMainPnt, lTmp4);
SHUFFLEUP(lTmp6, 0x18, plMainPnt, lTmp4);
plPoint1[lTmp5++]=lTmp4;
} while(lTmp5<lTmp3);
}
if(0 == lTmp2)
return;
lTmp4=0;
plMainPnt+= lTmp2;
switch(lTmp2) {
case 0:
plMainPnt--;
lTmp4=0;
lTmp4=(char)*plMainPnt;
lTmp4 << 0x10;
case 2:
plMainPnt--;
lTmp6=0;
lTmp6=(char)*plMainPnt;
lTmp6<<8;
lTmp4|= lTmp6;
case 1:
plMainPnt--;
lTmp7=0;
lTmp7=(char)*plMainPnt;
lTmp4|= lTmp7;
case 3:
plPoint1[lTmp5]=lTmp4;
return;
}
}
}
if(0 == ((unsigned long)plMainPnt & 0x3)) {
lTmp5=nIntParam;
if ((lTmp5>> 6) >0) {
lTmp5=lTmp5<<6;
MD5_Update (pMd5Ctx, (unsigned char *)plMainPnt, lTmp5);
plMainPnt+= lTmp5;
nIntParam-= lTmp5;
}
}
plPoint1=(unsigned long *)pMd5Ctx->data;
if(nIntParam>= 0x40) {
do {
if(plMainPnt!= (unsigned char *)plPoint1) {
memcpy((unsigned char *)plPoint1, plMainPnt, 0x40);
}
plMainPnt+= 0x40;
MD5_Update (pMd5Ctx, (unsigned char *)pMd5Ctx->data, 0x40);
} while(nIntParam>= 0x40);
}
lTmp1=nIntParam;
pMd5Ctx->num=lTmp1;
if(0 == lTmp1)
return;
lTmp5=lTmp1>>2;
plPoint1[lTmp5]=0;
memcpy((unsigned char *)plPoint1, plMainPnt, lTmp1);
}