| 《加密解密 技术内幕》2.1 关于PE可执行文件的修改 |
| 责任编辑:酷酷の鱼 更新日期:2008-3-14 |
|
|
|
//一般情况下,“.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); //更改返回地址,用jpm返回原程序入口地址,其它的二进制代码在writeline[15]处 if(retf==-1) { printf("error seek\n"); return; }
address=0-(newentryaddress-oldentryaddress+4+15); //返回地址计算的方法是新的入口地址减去老的入口地址加4(地址长度)加15(二进制代码相对偏移)后取反 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; }
_close(ret); printf("\nall done...\n"); return; }
//end
由于在PE格式的文件中,所有的地址都使用RVA地址,所以一些函数调用和返回地址都要经过计算才可以得到,以上是我在实践中的心得,如果你有更好的办法,真心的希望你能告诉我。上一页 [1] [2] [3] |
|
| 上一篇文章: discuz安全提问算法 |
| 下一篇文章: 《加密解密 技术内幕》2.2 手工构造一个超微型的 PE 文件 |
|
|
|
|