/*-----------------------------------------------------------------*/ /* (C) by Hard Wisdom "OPTLINKer UnPacker" 26-Oct-1998y v1.0 */ /* */ /* Especially for ACCEL EDA (CAD software) */ /* */ /*-----------------------------------------------------------------*/ /* TCC.EXE -ml -eUNOPT UNOPT.C UNOPTRIP.ASM */ #include <alloc.h> #include <mem.h> #include <stdio.h> #include <string.h> #include <stdlib.h> extern unsigned short OptLink_UnPack(void far *Inp, void far *Outp, unsigned short far *W3); /*-----------------------------------------------------------------*/ /* P R O C E S S I N G */ /*-----------------------------------------------------------------*/ void DoRoll(void) { /* static int i=0; char s[]="|/-\\"; putchar(s[i++]); putchar('\b'); i&=3; */ } /*-----------------------------------------------------------------*/ void SayError(char* Msg) { printf("\nError: %s !\n",Msg); exit(-1); } /*-----------------------------------------------------------------*/ unsigned long Align(unsigned long Data, int Border) { volatile unsigned long l=Data,ll=Border,q=-1; q=~(q << ll)+1; return (l+q-1)/q*q; } /*-----------------------------------------------------------------*/ int UnPackFile2File(char *Inp, char *Outp) { FILE *InF, *OutF; char Buf[0x4000]; int e,i,j,jj,q,qq,qf; unsigned long NewExe,l,ll,l2,ll2; unsigned short SegPos,SegSh,SegCnt,w,w2,w3; struct { unsigned short SectorNum,FileArea,Flags,MemArea; } SegT[0x100]; struct { unsigned short ResSh, ResLen, Flags, Id; unsigned long DD; } ResItem; struct { unsigned short Id, Num; unsigned long DD; } ResDir; unsigned char *p,*pp,*p2,*p22; char RT[4]={0,2,3,5}; if ((InF=fopen(Inp,"rb"))==NULL) SayError("Unable to open input file"); if ((OutF=fopen(Outp,"w+b"))==NULL) SayError("Unable to create output file"); if (!fread(Buf,0x40,1,InF)) SayError("Unable to read file header"); if (memcmp(Buf,"MZ",2) && memcmp(Buf,"ZM",2)) SayError("Bad EXE signature"); memcpy(&NewExe,&Buf[0x3C],sizeof(NewExe)); if (!NewExe) SayError("Input file is non New EXE file"); printf(" þ NEW EXE Position= %.8lXh\n",NewExe); fseek(InF,NewExe,SEEK_SET); if (!fread(Buf,0x40,1,InF)) SayError("Unable to read New EXE file header"); if (memcmp(Buf,"NE",2)) SayError("This is a non NE-EXE file"); memcpy(&SegPos,&Buf[0x22],2); memcpy(&SegCnt,&Buf[0x1C],2); memcpy(&SegSh,&Buf[0x32],2); printf(" þ Segment table at: %.4Xh (%u Items)\n",SegPos,SegCnt); if (SegCnt>0x100) SayError("Too much segments, unable to proceed"); fseek(InF,SegPos+NewExe,SEEK_SET); if (fread(SegT,8,SegCnt,InF)!=SegCnt) SayError("Unable to read segments table"); l=SegT[0].SectorNum; l<<=SegSh; fseek(InF,l+0x17F,SEEK_SET); if (!fread(Buf,0x100,1,InF)) SayError("Unable to read loader signature"); if (memcmp(Buf,"OPTLOADER",9)) SayError("This is non OPTLINK packed file"); printf("\n'%s'\n\n",Buf); ll=Align(l,9); if (SegSh>9) SayError("Unsupported Seg.shift value"); if (ll>sizeof(Buf)) SayError("STUB + Headers too large, unable to proceed"); memset(Buf,'*',ll); fseek(InF,0,SEEK_SET); e=fread(Buf,l,1,InF); e+=fwrite(Buf,ll,1,OutF); if (e!=2) SayError("Unable to transfer file headers"); printf(" þ Processing segments. . .\n"); p=malloc(0xFFFF); pp=malloc(0xFFFF); if (!p || !pp) SayError("No memory for temporary buffers"); for (i=0;i<SegCnt;i++) { l2=SegT[i].SectorNum; l2<<=SegSh; if (i==SegCnt-1) { fseek(InF,0,SEEK_END); ll2=ftell(InF); } else { ll2=SegT[i+1].SectorNum; ll2<<=SegSh; } printf(" Segment %u %.8lXh - %.8lXh > ",i,l2,ll2); if ((ll2-l2)>0xFFFF) SayError("Segment too large"); fseek(InF,l2,SEEK_SET); e=fread(p,ll2-l2,1,InF); memset(pp,'*',0xFFFF); if (i==0) { memcpy(pp,p,ll2-l2); ll2-=l2; } else { memcpy(&w,p,2); w2=OptLink_UnPack(p,pp,&w3); memcpy(pp+w2,&w,2); printf("(%.4Xh) ",w); if (w) SegT[i].Flags|=0x100; ll2=w2+w*8+2; p2=p+w3+2; p22=pp+w2+2; jj=w; SegT[i].Flags&=0xFFF7; while (jj>0) { j=(unsigned char)(*(p2+1)); jj-=j; if (jj<0) SayError("Relo-subcounter too big"); if (j<=0) SayError("Relo-subcounter too small"); q=(unsigned char)(*p2); p2+=2; switch (q >> 3) { case 0: qq=*(unsigned char*)p2; p2++; break; case 1: case 2: case 3: memcpy(&qq,p2,2); p2+=2; break; case 0x1E: break; default: SayError("Invalid relo-type"); } qf=q >> 3; qf=(qf==0x1E)?0:qf; if ((q & 7)>3) qf|=4; while (j--) { DoRoll(); switch (q >> 3) { case 0: case 1: case2: *p22++=RT[q&3]; *p22++=qf; memcpy(p22,p2,2); memcpy(p22+2,&qq,2); memcpy(p22+4,p2+2,2); p22+=6; p2+=4; break; case 3: *p22++=RT[q&3]; *p22++=qf; memcpy(p22,p2,2); memcpy(p22+2,&qq,2); memset(p22+4,0,2); p22+=6; p2+=2; break; case 0x1E: *p22++=2; *p22++=qf; memcpy(p22,p2+1,2); p22+=2; *p22++=*p2; *p22++=0; *p22++=0; *p22++=0; p2+=3; break; } }/*subrelo*/ } SegT[i].FileArea=w2; } l2=ftell(OutF); ll2=Align(l2+ll2,9); printf("%.8lXh - %.8lXh ... ",l2,ll2); e+=fwrite(pp,ll2-l2,1,OutF); if (e!=2) SayError("I/O error during transferring segment"); SegT[i].SectorNum=l2/0x200; printf("Ok.\n"); } free(p); free(pp); fseek(InF,NewExe,SEEK_SET); e=fread(Buf,0x40,1,InF); memcpy(&w2,&Buf[0x24],2); Buf[0x32]=9; Buf[0xD]&=0xF7; fseek(OutF,NewExe,SEEK_SET); e+=fwrite(Buf,0x40,1,OutF); if (e!=2) SayError("Unable to store header"); printf(" þ Resources directoryes...\n"); l=NewExe+w2; fseek(InF,l,SEEK_SET); e=fread(&w3,2,1,InF); do { if (fread(&ResDir,sizeof(ResDir),1,InF)!=1) SayError("Unable to read res.directory"); if (!ResDir.Id) break; printf(" Directory ID %.4Xh (%u items)\n",ResDir.Id,ResDir.Num); while (ResDir.Num--) { ll=ftell(InF); if (!fread(&ResItem,sizeof(ResItem),1,InF)) SayError("Unable to read res.item"); ll2=ftell(InF); l2=ResItem.ResSh; l2<<=w3; fseek(InF,l2,SEEK_SET); w=ResItem.ResLen; w<<=w3; printf(" Resource ID %.4Xh %.8lXh - %.8lXh > ", ResItem.Id,l2,l2+w); if (w>sizeof(Buf)) SayError("Resource too large"); memset(Buf,'*',Align(ResItem.ResLen,9)); e=fread(Buf,w,1,InF); fseek(OutF,0,SEEK_END); l2=ftell(OutF)/0x200; ResItem.ResSh=l2; printf("%.8lXh - %.8lXh ... ",l2,Align(l2+w,9)); e+=fwrite(Buf,Align(w,9),1,OutF); if (e!=2) SayError("Unable to transfer resource"); ResItem.ResLen=Align(w,9)/0x200; fseek(OutF,ll,SEEK_SET); if (!fwrite(&ResItem,sizeof(ResItem),1,OutF)) SayError("Unable to store res.item header"); fseek(InF,ll2,SEEK_SET); printf("Ok.\n"); } } while(1); fseek(OutF,l,SEEK_SET); w3=9; if (!fwrite(&w3,2,1,OutF)) SayError("Unable to change res. alignment"); fseek(OutF,NewExe+SegPos,SEEK_SET); if (fwrite(SegT,8,SegCnt,OutF)!=SegCnt) SayError("Unable to store segments table"); fclose(InF); fclose(OutF); if (!ferror(InF) && !ferror(OutF)) puts(" û Well Done!"); else SayError("Files processing error"); } /*-----------------------------------------------------------------*/ /* E N T R Y P O I N T */ /*-----------------------------------------------------------------*/ void main(int argc, char* argv[]) { char s[256],ss[256]; printf("(C) 26-Oct-1998y by Hard Wisdom 'OPTLINKer UnPacker' v1.0\n"); printf(" ~~~~~~~~~~~~~~~~~~~~\n"); if (argc<=1) SayError("Where parameters ? Nothing to do"); strcpy(s,argv[1]); strcpy(ss,s); if (!strrchr(ss,'.')) strcat(ss,".OPT"); else strcpy(strrchr(ss,'.'),".OPT"); UnPackFile2File(s,ss); printf("\n û '%s' ---> '%s'\n",s,ss); } /*-----------------------------------------------------------------*/