/* * DLL2S Uses to create GNU .a library from any PE DLL. It gets * function's names from DLL. For each function the program * creates "#.s" assembler file, compiles it with "as.exe", * adds the result "#.o" to "filename.a" with "ar.exe". DJDIR * must be in enviromment or in DJGPP.ENV Also header * ("filename.h") file is generated, but this file dosen't * content valid definetion of functions. Only function's names, * without arguments. * * * Author: Max Feoktistov * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * * Compile * command: gcc -fpack-struct -fsjlj-exceptions -O2 -s dll2s.cpp -o dll2s.exe */ #define _main_ #include #include #include #include #include #include #include #include "mdef.h" #include "pe_m.h" #if (__GNUC__ >=2) && (__GNUC_MINOR__ > 81 ) #include #else #include "mstring.h" #endif #define _Open(a,b) open((char*)a,b) #define OPEN_READ (O_BINARY|O_RDONLY) #define OPEN_WRITE (O_BINARY|O_WRONLY) #define OPEN_READ_WRITE (O_BINARY|O_RDWR) #define _Create(a,b) _creat((char*)a,b) int hfin,hfout=0,hhfout=0; char def_outnames[]="aout.s"; char def_outname[256]="libdll.a"; char def_outh[256]="libdll.h"; char *foutname=def_outname; char *fhoutname=def_outh; char in_name1[40]; char in_name[40]; char nme[80]; char nmeo[80]; char *pnme=nme; ulong flag=0; #define flgONE_ASM_FILE 0x1 #define flgNO_GENERATE_O 0x2 #define flgNO_GENERATE_H 0x4 #define flgNO_DELETE_O 0x10 #define flgNO_DELETE_S 0x20 #define flgNO_DEFINE_A 0x40 #define flgNO_GENERATE_S 0x80 #define flgADD_UNNAMED 0x100 #define flgUSE_FNC_NUMBER 0x200 #define ONE_ASM_FILE (flag&1) #define STORE_SOURCE (flag&0x20) #define STORE_OBJECTS (flag&0x10) #define UNNAMED_FUNCTION (flag&0x100) ulong first=1; char *data_bufer,*end_data_bufer, // local data pointers. *headers_bufer,*end_headers_bufer;// local headers data pointers. char *exp; long *tf; ushort *tfn; int cnt=0; char exec_as[256]; char exec_ar[256]; char msg1[]="DLL2S by Max Feoktistov E-mail: max@feokt.spb.ru\n" "Command line: \n" "%s {[-keys]}[-o out_file_name][-n filename] file.dll\n Keys:\n" "-s store source \t\t\t -j store objects\n" "-a generate one asm file only \t\t -n name to asm file\n" "-i generate one Intel asm file only \t -r generate header file only\n" "-u add \"unnamed\" functions \t\t -f don't generate #define for A-function\n" "-l always use number for link (default use name of function, if it\'s posible)\n" "-d don\'t generate header file\n" "\nSt.Petersburg (C) 1999-2000\n"; PEAOUTHDR *peh; SCNHDR *lsh; int exp_base,exp_len; #define die(a...) {printf(a );return -1;} #define dienr(a...) {printf(a );return; } #define pdbg(a...) {printf(a ); } // Flush local bufer to file. void FlushBufer() { if(ONE_ASM_FILE) { if( (end_data_bufer!=data_bufer) && (hfout>=0)) { if(!hfout) if( (hfout=_Create(foutname,0) )<0 ) { end_data_bufer=data_bufer; dienr("Unable create target"); } write(hfout,data_bufer,end_data_bufer-data_bufer); end_data_bufer=data_bufer; } else { if(hfout>0)close(hfout); hfout=-1; } }else { if(!(flag&flgNO_GENERATE_H) ) { if( (end_headers_bufer!=headers_bufer) && (hhfout>=0)) { if(!hhfout) if( (hhfout=_Create(fhoutname,0) )<0 ) { end_headers_bufer=headers_bufer; dienr("Unable create target"); } write(hhfout,headers_bufer,end_headers_bufer-headers_bufer); } else { if(hhfout>0)close(hhfout); hhfout=-1; } } end_headers_bufer=headers_bufer; } }; //------------------------- //Target functions: const char StartDefinetion[]=".text\n" ".global _Get_%s_Func; _Get_%s_Func: movl $l1,%%edx;\n" "jmp _OptFunc; l1: .long 0; .asciz \"%s\" \n"; const char StartDefinetionIntel[]=".386p\n" "_TEXT SEGMENT DWORD USE32 'CODE'\n" " EXTRN _OptFunc\n" " FNC_NEAR MACRO N\n" " PUBLIC N\n" " N PROC NEAR\n" " ENDM\n" " FNC_NEAR _Get_%s_Func \n" " mov EDX,offset L1\n" " jmp _OptFunc\n" "L1: DD 0\n" " DB \'%s\',0 \n" "_Get_%s_Func ENDP\n"; const char FncDefinetion[]=".text\n" ".global _%s; _%s: call _Get_%s_Func \n" ".asciz \"%s\" \n"; const char FncDefinetionNum[]=".text\n" ".global _%s; _%s: call _Get_%s_Func \n" ".long %u \n"; const char FncDefinetionIntel[]="FNC_NEAR _%s \n" " call NEAR PTR _Get_%s_Func; \n" " DB \'%s\',0 \n" "_%s ENDP\n"; const char FncDefinetionIntelNum[]="FNC_NEAR _%s \n" " call NEAR PTR _Get_%s_Func; \n" " DD \'%u\',0 \n" "_%s ENDP\n"; const char dfnh2[]="int stdcall %s(int a,...) __attribute__((stdcall));\n#define %s(a...) ({_%s(a);asm(\".-=3;\");})\n"; const char dfnh[]="int %s() __attribute__((stdcall));\n"; const char dfnhi[]="int %s();\n"; //------------------------- // Create library, make first common function that get pointer to DLL entry. void BeginFunc(char *nm) { end_data_bufer=data_bufer+sprintf(data_bufer,StartDefinetion, in_name,in_name, nm); if(!ONE_ASM_FILE) { if(!(flag&flgNO_GENERATE_S)) { if( (hfout=_Create("f_0.s",0) )<0 ) { end_data_bufer=data_bufer; dienr("Unable create target f_0.s"); } write(hfout,data_bufer,end_data_bufer-data_bufer); close(hfout); end_data_bufer=data_bufer; if(!(flag&flgNO_GENERATE_O)) { if(spawnl(P_WAIT,exec_as,exec_as,"f_0.s","-o","f_0.o",0)<0) printf("Error exec %s\n",exec_as); if( spawnl(P_WAIT,exec_ar,exec_ar,"-qc",foutname,"f_0.o",0)<0 ) printf("Error exec %s\n",exec_ar); if(!(flag&flgNO_DELETE_S) )unlink("f_0.s"); if(!(flag&flgNO_DELETE_O) )unlink("f_0.o"); }; }; } }; //------------------------- //Make asm "#.s" file to function. Translate it with as.exe to "#.o" //Add this "#.o" to .a with ar.exe void MakeFunc(char *nm,ulong n) { if( (*nm>='@') && (*nm<='z') && (strlen(nm)<40) ) { printf("\r%u %s \t\t\t",cnt,nm); if(flag&flgUSE_FNC_NUMBER) end_data_bufer+=sprintf(end_data_bufer, FncDefinetionNum, nm, nm, in_name, n); else end_data_bufer+=sprintf(end_data_bufer, FncDefinetion, nm, nm, in_name, nm); cnt++; if(!ONE_ASM_FILE) { if(!(flag&flgNO_GENERATE_S)) { sprintf(nme,"f%u.s",cnt); sprintf(nmeo,"f%u.o",cnt); if( (hfout=_Create(pnme,0) )<0 ) { end_data_bufer=data_bufer; dienr("Unable create target %s",pnme); } write(hfout,data_bufer,end_data_bufer-data_bufer); close(hfout); } end_data_bufer=data_bufer; end_headers_bufer+=sprintf(end_headers_bufer, dfnh, nm); if(!(flag&flgNO_DEFINE_A) ) if(nm[strlen(nm)-1]=='A') { end_headers_bufer+=sprintf(end_headers_bufer,"#define %s",nm)-1; end_headers_bufer+=sprintf(end_headers_bufer," %s\n",nm); } if(end_headers_bufer>headers_bufer+0x6000)FlushBufer(); if(!(flag&flgNO_GENERATE_O)) { if(spawnl(P_WAIT,exec_as,exec_as,nme,"-o",nmeo,0)<0) printf("Error exec %s\n",exec_as); if(spawnl(P_WAIT,exec_ar,exec_ar,"-q",foutname,nmeo,0)<0) printf("Error exec %s\n",exec_ar); if(!(flag&flgNO_DELETE_S) )unlink(nme); if(!(flag&flgNO_DELETE_O) )unlink(nmeo); }; } else if(end_data_bufer>data_bufer+0x4000)FlushBufer(); }; }; int cnt_pos=0x18; //------------------------------- int main(int argc,char *argv[],char *env[]) { int i; if(argc<2) { ex1: printf(msg1,argv[0]); return -1; }; ////////////// Command line analise /////////////////// while(*argv[first] == '-' ||*argv[first] == '/') { switch(argv[first][1]) { case 'h': case 'H': case '?': goto ex1; case 'o': case 'O': first++; foutname=argv[first]; break; case 'a': // generate one asm file only case 'A': flag|=1; break; case 'n': // name to asm file case 'N': first++; pnme=argv[first]; break; case 'j': // store objects case 'J': flag|=0x10; break; case 's': // store source case 'S': flag|=0x20; break; case 'f': // no generate #define for A-function case 'F': flag|=0x40; break; case 'd': // no generate header case 'D': flag|=0x4; break; case 'r': // generate header file only case 'R': flag|=0x82; break; case 'u': // Add \"unnamed\" function case 'U': flag|=0x100; break; case 'l': // Alwais use number for link case 'L': flag|=0x200; break; default: printf("**Warning: Unknow option \"%s\" \n",argv[first]); }; first++; if((argc-first)<=0)goto ex1; }; //------------ for(end_data_bufer=argv[first],i=0 ; *end_data_bufer ; end_data_bufer++ ) { if( ( (in_name[i] = in_name1[i] = *end_data_bufer) == '\\' ) || ( *end_data_bufer == '/' ) ) i=0; else { if(*end_data_bufer =='.')in_name[i]=0; i++; } } sprintf(def_outname,"%s.a",in_name); sprintf(def_outh,"%s.h",in_name); if((hfin=_Open(argv[first],OPEN_READ))<0) { printf("Unable to open \"%s\" ",argv[first]); return -2; }; // Prepare to create/update .o and .a files useful "as" and "ar" utilites. if( !(flag&flgNO_GENERATE_O) ) { for(;*env;env++) { if( ( (DWORD_PTR(**env)|0x20202020) == 0x69646A64 ) && ( (WORD_PTR((*env)[4])|0x20) == 0x3D72) )break; } if(!*env) { flag&=~2; printf("**Error. Have't DJDIR in enviroment.. Can't generate .o & .a :( .s only\n"); } else { sprintf(exec_as,"%s/bin/as.exe",(*env)+6); sprintf(exec_ar,"%s/bin/ar.exe",(*env)+6); } }; //------------ if(! ( data_bufer=new char[0x18000]) ) die("**Error. No enought memory :( ..."); end_headers_bufer=headers_bufer=data_bufer+0xC000; if(read(hfin,data_bufer,0x400) != 0x400 ) die("Error read file.."); if( DWORD_PTR( data_bufer[ ((uchar) data_bufer[0x3C] ) ] ) !=0x4550 ) die("**Error %s -- is't valid PE file :( ",argv[first]); peh=(PEAOUTHDR *) (data_bufer+DWORD_PTR(data_bufer[0x3C])+0x18); exp_base=peh->DataDirectory[0][0]; exp_len=peh->DataDirectory[0][1]; if(!exp_len) die("**Error %s -- have't export :( ",argv[first]); if(! ( exp=new char[exp_len+20] ) ) die("**Error. No enought memory 2 :( ..."); lsh=(SCNHDR *)(&peh[1]); for(i=WORD_PTR(data_bufer[0x86]);i;i--) { if( (exp_base>=lsh->s_vaddr) && (exp_base< (lsh->s_vaddr+lsh->s_size) ) )break; lsh++; }; if(!i) die("Can't find export section"); lseek(hfin,lsh->s_scnptr+exp_base-lsh->s_vaddr,0); if(read(hfin,exp,exp_len)!= exp_len) die("2 Error** read file.."); exp[exp_len]=0; BeginFunc(in_name1); for(i=DWORD_PTR(exp[0x18]), tf=(long *) (exp+DWORD_PTR(exp[0x20]) - exp_base), tfn=(ushort *)(exp+ DWORD_PTR(exp[0x24]) - exp_base) ; i;i--,tf++,tfn++) { MakeFunc(exp+ *tf - exp_base,*tfn); }; if(flag&flgADD_UNNAMED) { flag|=flgUSE_FNC_NUMBER; end_headers_bufer+=sprintf(end_headers_bufer,"\n\n // ----- Unnamed functions ------ \n\n"); char lbb[80]; for(i=DWORD_PTR(exp[0x14])-DWORD_PTR(exp[0x18]); i; i--,tfn++) { sprintf(lbb,"%s_%u",in_name,(ulong)*tfn); MakeFunc(lbb,*tfn); }; }; FlushBufer(); FlushBufer(); printf("\rAll right! %u -- functions stored\n",cnt); return 0; };