阅读:1578回复:0
ZT--关于PE可执行文件的修改(3)
关于PE可执行文件的修改(3)
[ 作者: ilsy 添加时间: 2001-9-24 9:25:08 ] delete Createtime; delete Accesstime; delete Writetime; CloseHandle(hFile); return 0; } void map_exe(const void *base) { IMAGE_DOS_HEADER * dos_head; dos_head =(IMAGE_DOS_HEADER *)base; #include <pshpack1.h> typedef struct PE_HEADER_MAP { DWORD signature; IMAGE_FILE_HEADER _head; IMAGE_OPTIONAL_HEADER opt_head; IMAGE_SECTION_HEADER section_header[]; } peHeader; #include <poppack.h> if (dos_head->e_magic != IMAGE_DOS_SIGNATURE) { puts(\"unknown type of file\"); return; } peHeader * header; header = (peHeader *)((char *)dos_head + dos_head->e_lfanew);//得到PE文件头 if (IsBadReadPtr(header, sizeof(*header)) { puts(\"(no PE header, probably DOS executable)\"); return; } DWORD mods; char tmpstr[4]={0}; DWORD tmpaddress; DWORD tmpaddress1; if(strstr((const char *)header->section_header[0].Name,\".text\")!=NULL) { virtsize=header->section_header[0].Misc.VirtualSize; //此段的真实长度 physaddress=header->section_header[0].PointerToRawData; //此段的物理偏移 physsize=header->section_header[0].SizeOfRawData; //此段的物理长度 peaddress=dos_head->e_lfanew; //得到PE文件头的开始偏移 peHeader peH; tmpaddress=(unsigned long )&peH; //得到结构的偏移 tmpaddress1=(unsigned long )&(peH.section_header[0].Characteristics); //得到变量的偏移 flagaddress=tmpaddress1-tmpaddress+2; //得到属性的相对偏移 flags=0x8000; //一般情况下,“.text”段是不可读写的,如果我们要把数据写入这个段需要改变其属性,实际上这个程序并没有把数据写入“.text”段,所以并不需要更改,但如果你实现复杂的功能,肯定需要数据,肯定需要更改这个值, space=physsize-virtsize; //得到代码段的可用空间,用以判断可不可以写入我们的代码 //用此段的物理长度减去此段的真实长度就可以得到 progRAV=header->opt_head.ImageBase; //得到程序的装载地址,一般为400000 codeoffset=header->opt_head.BaseOfCode-physaddress; //得到代码偏移,用代码段起始RVA减去此段的物理偏移 //应为程序的入口计算公式是一个相对的偏移地址,计算公式为: //代码的写入地址+codeoffset entrywrite=header->section_header[0].PointerToRawData+header->section_header[0].Misc.VirtualSize; //代码写入的物理偏移 mods=entrywrite%16; //对齐边界 if(mods!=0) { entrywrite+=(16-mods); } oldentryaddress=header->opt_head.AddressOfEntryPoint; //保存旧的程序入口地址 newentryaddress=entrywrite+codeoffset; //计算新的程序入口地址 return; } void printaddress() { HINSTANCE gLibMsg=NULL; DWORD funaddress; gLibMsg=LoadLibrary(\"user32.dll\"); funaddress=(DWORD)GetProcAddress(gLibMsg,\"MessageBoxA\"); MessageBoxAadaddress=funaddress; gLibAMsg=LoadLibrary(\"kernel32.dll\"); //得到MessageBox在内存中的地址,以便我们使用 } void writefile() { int ret; long retf; DWORD address; int tmp; unsigned char waddress[4]={0}; ret=_open(filename,_O_RDWR | _O_CREAT | _O_BINARY,_S_IREAD | _S_IWRITE); if(!ret) { printf(\"error open\\n\"); return; } retf=_lseek(ret,(long)peaddress+40,SEEK_SET); //程序的入口地址在PE文件头开始的40处 if(retf==-1) { printf(\"error seek\\n\"); return; } address=newentryaddress; tmp=address>>24; waddress[3]=tmp; tmp=address<<8; tmp=tmp>>24; waddress[2]=tmp; tmp=address<<16; tmp=tmp>>24; waddress[1]=tmp; tmp=address<<24; tmp=tmp>>24; waddress[0]=tmp; retf=_write(ret,waddress,4); //把新的入口地址写入文件 if(retf==-1) { printf(\"error write: %d\\n\",GetLastError()); return; } retf=_lseek(ret,(long)entrywrite,SEEK_SET); if(retf==-1) { printf(\"error seek\\n\"); return; } retf=_write(ret,writeline,18); if(retf==-1) { printf(\"error write: %d\\n\",GetLastError()); return; } //把writeline写入我们计算出的空间 retf=_lseek(ret,(long)entrywrite+9,SEEK_SET); //更改MessageBox函数地址,它的二进制代码在writeline[10]处 if(retf==-1) { printf(\"error seek\\n\"); return; } address=MessageBoxAadaddress-(progRAV+newentryaddress+9+4); //重新计算MessageBox函数的地址,MessageBox函数的原地址减去程序的装载地址加上新的入口地址加9(它的二进制代码相对偏移)加上4(地址长度) tmp=address>>24; waddress[3]=tmp; tmp=address<<8; tmp=tmp>>24; waddress[2]=tmp; tmp=address<<16; tmp=tmp>>24; waddress[1]=tmp; tmp=address<<24; tmp=tmp>>24; waddress[0]=tmp; retf=_write(ret,waddress,4); //写入重新计算的MessageBox地址 if(retf==-1) { printf(\"error write: %d\\n\",GetLastError()); return; } retf=_lseek(ret,(long)entrywrite+14,SEEK_SET); |
|
|