后记:写完后发现有更彻底的删头方案,将真正Image部分提前。
1 /* 2 ============================================= 3 | Remove the DOS Stub in PE | 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ | 5 | How: | 6 | After removing the dos program, | 7 | fix the last DWORD in MZ Head | 8 | use the space before the Section | 9 | Headers to align with FILEALIGN | 10 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| 11 | Compiled with VC6.0 | 12 ============================================= 13 */ 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <windows.h> 17 /* 18 Switches: 19 ConsoleMode: printf or not 20 DllMode: whether to compile it as a DLL 21 */ 22 #define ConsoleMode 1 23 #define DllMode 0 24 25 #if DllMode 26 #pragma comment(linker,"/DLL") 27 #define ConsoleMode 0 28 #endif 29 30 #pragma comment(linker,"/merge:.data=.text") 31 #pragma comment(linker,"/merge:.rdata=.text") 32 #pragma comment(linker,"/SECTION:.text,ERW") 33 #if ConsoleMode 34 #pragma comment(linker,"/subsystem:console") 35 #else 36 #pragma comment(linker,"/subsystem:windows") 37 #endif 38 #ifndef NDEBUG 39 #if ConsoleMode 40 #define debughex(hex) printf("\nDEBUG:%X\n",hex); 41 #endif 42 #endif 43 44 #define WcrMAX_PATH 100 45 #define MAX_BUFFER 0x200 46 #define SIZEOFMZHEAD 0x40 47 #define SIZEOFCONSTHEAD 0xF8 48 #define SIZEOFSECTIONHEAD 0x28 49 #define FILEOFFSETFROMSECTIONHEAD 0x14 50 #define FILEALIGN 0x200 /*you can read this data from PE file, but 0x200 by default*/ 51 #define macromin(MX,MY) ((MX)<(MY)?(MX):(MY)) 52 53 int 54 #if !ConsoleMode 55 __declspec(dllexport) 56 #endif 57 perform(char* nameinput){ /*if it is a dll, export ConsoleMode(char*)*/ 58 FILE *fin,*fout; 59 register long i; 60 unsigned long currentl,templ; 61 unsigned short currents,temps; 62 unsigned char currentc,tempc; 63 unsigned char is_success; 64 unsigned char mzhead[SIZEOFMZHEAD]; 65 unsigned short numofsections; 66 unsigned long peoffset; 67 long foutoffset,foutsectionheads,foutminaddress,finminaddress; 68 long dosprogramlength; 69 char filename[WcrMAX_PATH],newname[WcrMAX_PATH],blank[]=""; 70 unsigned char *buf; 71 fin=NULL; 72 fout=NULL; 73 buf=NULL; 74 is_success=0; 75 if(nameinput&&strlen(nameinput)){ 76 buf=malloc(MAX_BUFFER); 77 if(!buf){ 78 #if ConsoleMode 79 printf("\nNot enough memoery!\n"); 80 #else 81 MessageBox(NULL,"Not enough memoery!",blank,0); 82 #endif 83 goto end; 84 } 85 strcpy(filename,nameinput); 86 fin=fopen(filename,"rb"); 87 if(!fin){ 88 #if ConsoleMode 89 printf("\nError when reading the file: %s\n",filename); 90 #else 91 MessageBox(NULL,"Error when reading the file!",blank,0); 92 #endif 93 goto end; 94 } 95 fout=fopen("TEMP.WCR","wb"); 96 if(!fout){ 97 #if ConsoleMode 98 printf("\nError when creating TEMP.WCR\n"); 99 #else 100 MessageBox(NULL,"Error trying to create TEMP.WCR",blank,0); 101 #endif 102 goto end; 103 } 104 /* 105 Init: 106 1. Change the last DWORD in MZ head to 0x40 107 2. Copy the PE,Optional and DataDirent head directly 108 3. Init the various 109 */ 110 #if ConsoleMode 111 printf("\nAnalysis with: %s\n",filename); 112 #endif 113 fread(&mzhead[0],SIZEOFMZHEAD,1,fin); 114 fwrite(&mzhead[0],SIZEOFMZHEAD-4,1,fout); 115 templ=0x40; 116 fwrite(&templ,4,1,fout); 117 #if ConsoleMode 118 printf("\tMZ header copied.\n"); 119 #endif 120 fseek(fin,SIZEOFMZHEAD-4,SEEK_SET); 121 fread(¤tl,4,1,fin); 122 peoffset=currentl; 123 fseek(fin,currentl,SEEK_SET); 124 fread(buf,SIZEOFCONSTHEAD,1,fin); 125 fwrite(buf,SIZEOFCONSTHEAD,1,fout); 126 #if ConsoleMode 127 printf("\tCOFF and Optional headers copied.\n"); 128 #endif 129 /* 130 Fix the Section Head 131 1. Find out the minimum Section offset 132 2. Then align the next Section 133 */ 134 fseek(fin,peoffset+0x6,SEEK_SET); 135 fread(¤ts,2,1,fin); 136 numofsections=currents; 137 fseek(fin,peoffset+SIZEOFCONSTHEAD,SEEK_SET); 138 foutoffset=0x138; 139 foutsectionheads=foutoffset; 140 finminaddress=0xFFFFFFF; 141 for(i=0;i<numofsections;i++){ 142 fread(buf,SIZEOFSECTIONHEAD,1,fin); 143 if(*(long*)(buf+FILEOFFSETFROMSECTIONHEAD)) /*my Patch 1*/ 144 finminaddress=macromin(*(long*)(buf+FILEOFFSETFROMSECTIONHEAD),finminaddress); 145 foutoffset+=SIZEOFSECTIONHEAD; 146 #ifndef NDEBUG 147 debughex(*(long*)(buf+FILEOFFSETFROMSECTIONHEAD)); 148 #endif 149 } 150 dosprogramlength=(peoffset-SIZEOFMZHEAD);/*The Length of code, that is deleted*/ 151 foutminaddress=finminaddress-dosprogramlength; 152 while(foutoffset%FILEALIGN)foutoffset++; 153 if(foutoffset<foutminaddress){/* Check whether it is disturb by FILEALIGN*/ 154 /* 155 Modify the PointerToRawData in the Section Head 156 Copy the whole Section Head, copy the whole file 157 */ 158 fseek(fin,peoffset+SIZEOFCONSTHEAD,SEEK_SET); /*seek to the Section Head*/ 159 templ=finminaddress-foutoffset; 160 foutminaddress=foutoffset; 161 for(i=0;i<numofsections;i++){ 162 fread(buf,SIZEOFSECTIONHEAD,1,fin); 163 if(*(long*)(buf+FILEOFFSETFROMSECTIONHEAD)){ 164 (*(long*)(buf+FILEOFFSETFROMSECTIONHEAD))-=templ; 165 } 166 fwrite(buf,SIZEOFSECTIONHEAD,1,fout); 167 #ifndef NDEBUG 168 #if ConsoleMode 169 printf("After Modify:"); 170 #endif 171 debughex(*(long*)(buf+FILEOFFSETFROMSECTIONHEAD)); 172 #endif 173 } 174 foutoffset=ftell(fout); 175 buf[0]=0; 176 while(foutoffset<foutminaddress){ 177 foutoffset++; 178 fwrite(buf,1,1,fout); 179 } 180 fseek(fin,finminaddress,SEEK_SET); 181 while(1){ 182 fread(buf,1,1,fin); 183 if(!feof(fin))fwrite(buf,1,1,fout);else break; 184 } 185 /*#ifndef NDEBUG*/ 186 is_success=1; 187 /*#endif*/ 188 }else{ 189 #if ConsoleMode 190 printf("The DOS section of this program cannot be deleted!"); 191 #else 192 MessageBox(NULL,"Operation Failed!",blank,0); 193 #endif 194 } 195 /* 196 Copy the file, free the memory 197 */ 198 end: 199 free(buf); 200 fclose(fin); 201 fclose(fout); 202 if(is_success){ 203 strcpy(newname,filename); 204 strcat(newname,"~"); 205 unlink(newname); 206 rename(filename,newname); 207 rename("TEMP.WCR",filename); 208 }else{ 209 #ifndef NDEBUG 210 unlink("TEMP.WCR"); 211 #endif 212 } 213 }else{ 214 #if ConsoleMode 215 printf( 216 "\nTool to remove DOS Stub :\n\n" 217 "\tusage:\t<pe.exe/dll> <output>\n\n" 218 ); 219 #else 220 MessageBox(NULL,"Please Enter the Argument!",blank,0); 221 MessageBox(NULL, 222 "Tip:\n\nTry it also on DLL/OCX files\n\n C. Wu 2006 summer",blank,0); 223 #endif 224 } 225 #ifndef NDEBUG 226 system("pause"); 227 #endif 228 return is_success; 229 } 230 231 #if DllMode 232 int __stdcall DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved){ 233 return 1; 234 } 235 236 #else 237 #if ConsoleMode 238 int main(int arg1,char *arg2[]){ 239 if(arg1>1)return perform(arg2[1]); 240 else 241 return perform(NULL); 242 } 243 #else 244 int __stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int nShowCmd){ 245 if(lpCmdLine[0]=='\"'){ 246 lpCmdLine[strlen(lpCmdLine)-1]=0; 247 strcpy(&lpCmdLine[0],&lpCmdLine[1]); 248 } 249 return perform(lpCmdLine); 250 } 251 #endif 252 #endif