关于PE可执行文件的修改

       在windows 9x、NT、2000下,所有的可执行文件都是基于Microsoft设计的一种新的文件格式Portable Executable File Format(可移植的执行体),即PE格式。有一些时候,我们需要对这些可执行文件进行修改,下面文字试图详细的描述PE文件的格式及对PE格式文件的修改。

1、PE文件框架构成
None.gif DOS MZ header
None.gifDOS stub
None.gifPE header
None.gifSection table
None.gifSection 
1
None.gifSection 
2
None.gifSection dot.gif
None.gifSection n
None.gif
       上表是PE文件结构的总体层次分布。所有 PE文件(甚至32位的 DLLs) 必须以一个简单的 DOS MZ header 开始,在偏移0处有DOS下可执行文件的“MZ标志”,有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随 MZ header 之后的 DOS stub。DOS stub实际上是个有效的EXE,在不支持 PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串 " This program cannot run in DOS mode " 或者程序员可根据自己的意图实现完整的 DOS代码。通常DOS stub由汇编器/编译器自动生成,对我们的用处不是很大,它简单调用中断21h服务9来显示字符串"This program cannot run in DOS mode"。

  紧接着 DOS stub 的是 PE header。 PE header 是PE相关结构 IMAGE_NT_HEADERS 的简称,其中包含了许多PE装载器用到的重要域。可执行文件在支持PE文件结构的操作系统中执行时,PE装载器将从 DOS MZ header的偏移3CH处找到 PE header 的起始偏移量。因而跳过了 DOS stub 直接定位到真正的文件头 PE header。

  PE文件的真正内容划分成块,称之为sections(节)。每节是一块拥有共同属性的数据,比如“.text”节等,那么,每一节的内容都是什么呢?实际上PE格式的文件把具有相同属性的内容放入同一个节中,而不必关心类似“.text”、“.data”的命名,其命名只是为了便于识别,所有,我们如果对PE格式的文件进行修改,理论上讲可以写入任何一个节内,并调整此节的属性就可以了。

        PE header 接下来的数组结构 section table(节表)。 每个结构包含对应节的属性、文件偏移量、虚拟偏移量等。如果PE文件里有5个节,那么此结构数组内就有5个成员。

以上就是PE文件格式的物理分布,下面将总结一下装载一PE文件的主要步骤:

  1、 PE文件被执行,PE装载器检查 DOS MZ header 里的 PE header 偏移量。如果找到,则跳转到 PE header。

  2、PE装载器检查 PE header 的有效性。如果有效,就跳转到PE header的尾部。

  3、紧跟 PE header 的是节表。PE装载器读取其中的节信息,并采用文件映射方法将这些节映射到内存,同时付上节表里指定的节属性。

  4、PE文件映射入内存后,PE装载器将处理PE文件中类似 import table(引入表)逻辑部分。

  上述步骤是一些前辈分析的结果简述。


2、PE文件头概述

  我们可以在winnt.h这个文件中找到关于PE文件头的定义:

ExpandedBlockStart.gif ContractedBlock.gif typedef  struct  _IMAGE_NT_HEADERS  dot.gif {
InBlock.gifDWORD Signature;
InBlock.gif
//PE文件头标志 :“PE\0\0”。在开始DOS header的偏移3CH处所指向的地址开始
InBlock.gif
IMAGE_FILE_HEADER FileHeader; //PE文件物理分布的信息
InBlock.gif
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //PE文件逻辑分布的信息
ExpandedBlockEnd.gif
}
 IMAGE_NT_HEADERS32,  * PIMAGE_NT_HEADERS32;
ExpandedBlockStart.gifContractedBlock.giftypedef 
struct  _IMAGE_FILE_HEADER  dot.gif {
InBlock.gifWORD Machine; 
//该文件运行所需要的CPU,对于Intel平台是14Ch
InBlock.gif
WORD NumberOfSections; //文件的节数目
InBlock.gif
DWORD TimeDateStamp; //文件创建日期和时间
InBlock.gif
DWORD PointerToSymbolTable; //用于调试
InBlock.gif
DWORD NumberOfSymbols; //符号表中符号个数
InBlock.gif
WORD SizeOfOptionalHeader; //OptionalHeader 结构大小
InBlock.gif
WORD Characteristics; //文件信息标记,区分文件是exe还是dll
ExpandedBlockEnd.gif
}
 IMAGE_FILE_HEADER,  * PIMAGE_FILE_HEADER;
ExpandedBlockStart.gifContractedBlock.giftypedef 
struct  _IMAGE_OPTIONAL_HEADER  dot.gif {
InBlock.gifWORD Magic; 
//标志字(总是010bh)
InBlock.gif
BYTE MajorLinkerVersion; //连接器版本号
InBlock.gif
BYTE MinorLinkerVersion; //
InBlock.gif
DWORD SizeOfCode; //代码段大小
InBlock.gif
DWORD SizeOfInitializedData; //已初始化数据块大小
InBlock.gif
DWORD SizeOfUninitializedData; //未初始化数据块大小
InBlock.gif
DWORD AddressOfEntryPoint; //PE装载器准备运行的PE文件的第一个指令的RVA,若要改变整个执行的流程,可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。(许多文章都有介绍RVA,请去了解)
InBlock.gif
DWORD BaseOfCode; //代码段起始RVA
InBlock.gif
DWORD BaseOfData; //数据段起始RVA
InBlock.gif
DWORD ImageBase; //PE文件的装载地址
InBlock.gif
DWORD SectionAlignment; //块对齐
InBlock.gif
DWORD FileAlignment; //文件块对齐
InBlock.gif
WORD MajorOperatingSystemVersion;//所需操作系统版本号
InBlock.gif
WORD MinorOperatingSystemVersion;//
InBlock.gif
WORD MajorImageVersion; //用户自定义版本号
InBlock.gif
WORD MinorImageVersion; //
InBlock.gif
WORD MajorSubsystemVersion; //win32子系统版本。若PE文件是专门为Win32设计的
InBlock.gif
WORD MinorSubsystemVersion; //该子系统版本必定是4.0否则对话框不会有3维立体感
InBlock.gif
DWORD Win32VersionValue; //保留
InBlock.gif
DWORD SizeOfImage; //内存中整个PE映像体的尺寸
InBlock.gif
DWORD SizeOfHeaders; //所有头+节表的大小
InBlock.gif
DWORD CheckSum; //校验和
InBlock.gif
WORD Subsystem; //NT用来识别PE文件属于哪个子系统
InBlock.gif
WORD DllCharacteristics; //
InBlock.gif
DWORD SizeOfStackReserve; //
InBlock.gif
DWORD SizeOfStackCommit; //
InBlock.gif
DWORD SizeOfHeapReserve; //
InBlock.gif
DWORD SizeOfHeapCommit; //
InBlock.gif
DWORD LoaderFlags; //
InBlock.gif
DWORD NumberOfRvaAndSizes; //
InBlock.gif
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
InBlock.gif
//IMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等
ExpandedBlockEnd.gif
}
 IMAGE_OPTIONAL_HEADER32,  * PIMAGE_OPTIONAL_HEADER32;
ExpandedBlockStart.gifContractedBlock.giftypedef 
struct  _IMAGE_DATA_DIRECTORY  dot.gif {
InBlock.gifDWORD VirtualAddress; 
//表的RVA地址
InBlock.gif
DWORD Size; //大小
ExpandedBlockEnd.gif
}
 IMAGE_DATA_DIRECTORY,  * PIMAGE_DATA_DIRECTORY;
None.gif

       PE文件头后是节表,在winnt.h下如下定义
ExpandedBlockStart.gif ContractedBlock.gif typedef  struct  _IMAGE_SECTION_HEADER  dot.gif {
InBlock.gifBYTE Name[IMAGE_SIZEOF_SHORT_NAME];
//节表名称,如“.text”
ExpandedSubBlockStart.gifContractedSubBlock.gif
union dot.gif{
InBlock.gifDWORD PhysicalAddress; 
//物理地址
InBlock.gif
DWORD VirtualSize; //真实长度
ExpandedSubBlockEnd.gif
}
 Misc;
InBlock.gifDWORD VirtualAddress; 
//RVA
InBlock.gif
DWORD SizeOfRawData; //物理长度
InBlock.gif
DWORD PointerToRawData; //节基于文件的偏移量
InBlock.gif
DWORD PointerToRelocations; //重定位的偏移
InBlock.gif
DWORD PointerToLinenumbers; //行号表的偏移
InBlock.gif
WORD NumberOfRelocations; //重定位项数目
InBlock.gif
WORD NumberOfLinenumbers; //行号表的数目
InBlock.gif
DWORD Characteristics; //节属性
ExpandedBlockEnd.gif
}
 IMAGE_SECTION_HEADER,  * PIMAGE_SECTION_HEADER;
None.gif

        以上结构就是在winnt.h中关于PE文件头的定义,如何我们用C/C++来进行PE可执行文件操作,就要用到上面的所有结构,它详细的描述了PE文件头的结构。

3、修改PE可执行文件

       现在让我们把一段代码写入任何一个PE格式的可执行文件,代码如下:

None.gif --  test.asm  --
None.gif.386p
None.gif.model flat, stdcall
None.gifoption casemap:none
None.gifinclude \masm32\include\windows.inc
None.gifinclude \masm32\include\user32.inc
None.gifincludelib \masm32\lib\user32.lib
None.gif.code
None.gifstart:
None.gifINVOKE MessageBoxA,
0 , 0 , 0 ,MB_ICONINFORMATION or MB_OK
None.gifret
None.gifend start
None.gif以上代码只显示一个MessageBox框,编译后得到二进制代码如下:
ExpandedBlockStart.gifContractedBlock.gifunsigned 
char  writeline[ 18 ] = dot.gif {
InBlock.gif
0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0
ExpandedBlockEnd.gif}
;
None.gif

        好,现在让我们看看该把这些代码写到那。现在用Tdump.exe显示一个PE格式得可执行文件信息,可以发现如下描述:

None.gif Object table:
None.gif# Name VirtSize RVA PhysSize Phys off Flags
None.gif
--   --------   --------   --------   --------   --------   --------
None.gif
01  .text 0000CCC0  00001000  0000CE00  00000600   60000020  [CER]
None.gif
02  .data  00004628  0000E000 00002C00 0000D400 C0000040 [IRW]
None.gif
03  .rsrc 000003C8  00013000   00000400   00010000   40000040  [IR]
None.gifKey to section flags:
None.gif
-  contains code
None.gif
-  executable
None.gif
-  contains initialized data
None.gif
-  readable
None.gif
-  writeable
None.gif


         上面描述此文件中存在3个段及每个段得信息,实际上我们的代码可以写入任何一个段,这里我选择“.text”段。

  用如下代码得到一个PE格式可执行文件的头信息:

None.gif // writePE.cpp
None.gif
#include  < windows.h >
None.gif#include 
< stdio.h >
None.gif#include 
< io.h >
None.gif#include 
< fcntl.h >
None.gif#include 
< time.h >
None.gif#include 
< SYS\STAT.H >
ExpandedBlockStart.gifContractedBlock.gifunsigned 
char  writeline[ 18 ] = dot.gif {
InBlock.gif
0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0
ExpandedBlockEnd.gif}
;
None.gifDWORD space;
None.gifDWORD entryaddress;
None.gifDWORD entrywrite;
None.gifDWORD progRAV;
None.gifDWORD oldentryaddress;
None.gifDWORD newentryaddress;
None.gifDWORD codeoffset;
None.gifDWORD peaddress;
None.gifDWORD flagaddress;
None.gifDWORD flags;
None.gifDWORD virtsize;
None.gifDWORD physaddress;
None.gifDWORD physsize;
None.gifDWORD MessageBoxAadaddress;
None.gif
int  main( int  argc, char   *   *  argv)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifHANDLE hFile, hMapping;
InBlock.gif
void *basepointer;
InBlock.gifFILETIME 
* Createtime;
InBlock.gifFILETIME 
* Accesstime;
InBlock.gifFILETIME 
* Writetime;
InBlock.gifCreatetime 
= new FILETIME;
InBlock.gifAccesstime 
= new FILETIME;
InBlock.gifWritetime 
= new FILETIME;
InBlock.gif
if ((hFile = CreateFile(argv[1], GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)//打开要修改的文件
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifputs(
"(could not open)");
InBlock.gif
return EXIT_FAILURE;
ExpandedSubBlockEnd.gif}

InBlock.gif
if(!GetFileTime(hFile,Createtime,Accesstime,Writetime))
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"\nerror getfiletime: %d\n",GetLastError());
ExpandedSubBlockEnd.gif}

InBlock.gif
//得到要修改文件的创建、修改等时间
InBlock.gif
if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 000)))
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifputs(
"(mapping failed)");
InBlock.gifCloseHandle(hFile);
InBlock.gif
return EXIT_FAILURE;
ExpandedSubBlockEnd.gif}

InBlock.gif
if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 000)))
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifputs(
"(view failed)");
InBlock.gifCloseHandle(hMapping);
InBlock.gifCloseHandle(hFile);
InBlock.gif
return EXIT_FAILURE;
ExpandedSubBlockEnd.gif}

InBlock.gif
//把文件头映象存入baseointer
InBlock.gif
CloseHandle(hMapping);
InBlock.gifCloseHandle(hFile);
InBlock.gifmap_exe(basepointer);
//得到相关地址
InBlock.gif
UnmapViewOfFile(basepointer);
InBlock.gifprintaddress();
InBlock.gifprintf(
"\n\n");
InBlock.gif
if(space<50)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"\n空隙太小,数据不能写入.\n");
ExpandedSubBlockEnd.gif}

InBlock.gif
else
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifwritefile();
//写文件
ExpandedSubBlockEnd.gif
}

InBlock.gif
if ((hFile = CreateFile(argv[1], GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifputs(
"(could not open)");
InBlock.gif
return EXIT_FAILURE;
ExpandedSubBlockEnd.gif}

InBlock.gif
if(!SetFileTime(hFile,Createtime,Accesstime,Writetime))
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error settime : %d\n",GetLastError());
ExpandedSubBlockEnd.gif}

InBlock.gif
//恢复修改后文件的建立时间等
InBlock.gif
delete Createtime;
InBlock.gifdelete Accesstime;
InBlock.gifdelete Writetime;
InBlock.gifCloseHandle(hFile);
InBlock.gif
return 0;
ExpandedBlockEnd.gif}

None.gif
void  map_exe( const   void   * base )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifIMAGE_DOS_HEADER 
* dos_head;
InBlock.gifdos_head 
=(IMAGE_DOS_HEADER *)base;
InBlock.gif#include 
<pshpack1.h>
InBlock.giftypedef 
struct PE_HEADER_MAP
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifDWORD signature;
InBlock.gifIMAGE_FILE_HEADER _head;
InBlock.gifIMAGE_OPTIONAL_HEADER opt_head;
InBlock.gifIMAGE_SECTION_HEADER section_header[];
ExpandedSubBlockEnd.gif}
 peHeader;
InBlock.gif#include 
<poppack.h>
InBlock.gif
if (dos_head->e_magic != IMAGE_DOS_SIGNATURE)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifputs(
"unknown type of file");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifpeHeader 
* header;
InBlock.gifheader 
= (peHeader *)((char *)dos_head + dos_head->e_lfanew);//得到PE文件头
InBlock.gif
if (IsBadReadPtr(header, sizeof(*header))
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifputs(
"(no PE header, probably DOS executable)");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifDWORD mods;
ExpandedSubBlockStart.gifContractedSubBlock.gif
char tmpstr[4]=dot.gif{0};
InBlock.gifDWORD tmpaddress;
InBlock.gifDWORD tmpaddress1;
InBlock.gif
if(strstr((const char *)header->section_header[0].Name,".text")!=NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifvirtsize
=header->section_header[0].Misc.VirtualSize;
InBlock.gif
//此段的真实长度
InBlock.gif
physaddress=header->section_header[0].PointerToRawData;
InBlock.gif
//此段的物理偏移
InBlock.gif
physsize=header->section_header[0].SizeOfRawData;
InBlock.gif
//此段的物理长度
InBlock.gif
peaddress=dos_head->e_lfanew;
InBlock.gif
//得到PE文件头的开始偏移
InBlock.gif
peHeader peH;
InBlock.giftmpaddress
=(unsigned long )&peH;
InBlock.gif
//得到结构的偏移
InBlock.gif
tmpaddress1=(unsigned long )&(peH.section_header[0].Characteristics);
InBlock.gif
//得到变量的偏移
InBlock.gif
flagaddress=tmpaddress1-tmpaddress+2;
InBlock.gif
//得到属性的相对偏移
InBlock.gif
flags=0x8000;
InBlock.gif
//一般情况下,“.text”段是不可读写的,如果我们要把数据写入这个段需要改变其属性,实际上这个程序并没有把数据写入“.text”段,所以并不需要更改,但如果你实现复杂的功能,肯定需要数据,肯定需要更改这个值,
InBlock.gif
space=physsize-virtsize;
InBlock.gif
//得到代码段的可用空间,用以判断可不可以写入我们的代码
InBlock.gif
//用此段的物理长度减去此段的真实长度就可以得到
InBlock.gif
progRAV=header->opt_head.ImageBase;
InBlock.gif
//得到程序的装载地址,一般为400000
InBlock.gif
codeoffset=header->opt_head.BaseOfCode-physaddress;
InBlock.gif
//得到代码偏移,用代码段起始RVA减去此段的物理偏移
InBlock.gif
//应为程序的入口计算公式是一个相对的偏移地址,计算公式为:
InBlock.gif
//代码的写入地址+codeoffset
InBlock.gif
entrywrite=header->section_header[0].PointerToRawData+header->section_header[0].Misc.VirtualSize;
InBlock.gif
//代码写入的物理偏移
InBlock.gif
mods=entrywrite%16;
InBlock.gif
//对齐边界
InBlock.gif
if(mods!=0)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifentrywrite
+=(16-mods);
ExpandedSubBlockEnd.gif}

InBlock.gifoldentryaddress
=header->opt_head.AddressOfEntryPoint;
InBlock.gif
//保存旧的程序入口地址
InBlock.gif
newentryaddress=entrywrite+codeoffset;
InBlock.gif
//计算新的程序入口地址
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gif
void printaddress()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifHINSTANCE gLibMsg
=NULL;
InBlock.gifDWORD funaddress;
InBlock.gifgLibMsg
=LoadLibrary("user32.dll");
InBlock.giffunaddress
=(DWORD)GetProcAddress(gLibMsg,"MessageBoxA");
InBlock.gifMessageBoxAadaddress
=funaddress;
InBlock.gifgLibAMsg
=LoadLibrary("kernel32.dll");
InBlock.gif
//得到MessageBox在内存中的地址,以便我们使用
ExpandedSubBlockEnd.gif
}

InBlock.gif
void writefile()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gif
int ret;
InBlock.gif
long retf;
InBlock.gifDWORD address;
InBlock.gif
int tmp;
ExpandedSubBlockStart.gifContractedSubBlock.gifunsigned 
char waddress[4]=dot.gif{0};
InBlock.gifret
=_open(filename,_O_RDWR | _O_CREAT | _O_BINARY,_S_IREAD | _S_IWRITE);
InBlock.gif
if(!ret)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error open\n");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifretf
=_lseek(ret,(long)peaddress+40,SEEK_SET);
InBlock.gif
//程序的入口地址在PE文件头开始的40处
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error seek\n");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifaddress
=newentryaddress;
InBlock.giftmp
=address>>24;
InBlock.gifwaddress[
3]=tmp;
InBlock.giftmp
=address<<8;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
2]=tmp;
InBlock.giftmp
=address<<16;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
1]=tmp;
InBlock.giftmp
=address<<24;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
0]=tmp;
InBlock.gifretf
=_write(ret,waddress,4);
InBlock.gif
//把新的入口地址写入文件
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error write: %d\n",GetLastError());
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifretf
=_lseek(ret,(long)entrywrite,SEEK_SET);
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error seek\n");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifretf
=_write(ret,writeline,18);
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error write: %d\n",GetLastError());
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gif
//把writeline写入我们计算出的空间
InBlock.gif
retf=_lseek(ret,(long)entrywrite+9,SEEK_SET);
InBlock.gif
//更改MessageBox函数地址,它的二进制代码在writeline[10]处
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error seek\n");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifaddress
=MessageBoxAadaddress-(progRAV+newentryaddress+9+4);
InBlock.gif
//重新计算MessageBox函数的地址,MessageBox函数的原地址减去程序的装载地址加上新的入口地址加9(它的二进制代码相对偏移)加上4(地址长度)
InBlock.gif
tmp=address>>24;
InBlock.gifwaddress[
3]=tmp;
InBlock.giftmp
=address<<8;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
2]=tmp;
InBlock.giftmp
=address<<16;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
1]=tmp;
InBlock.giftmp
=address<<24;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
0]=tmp;
InBlock.gifretf
=_write(ret,waddress,4);
InBlock.gif
//写入重新计算的MessageBox地址
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error write: %d\n",GetLastError());
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifretf
=_lseek(ret,(long)entrywrite+14,SEEK_SET);
InBlock.gif
//更改返回地址,用jpm返回原程序入口地址,其它的二进制代码在writeline[15]处
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error seek\n");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gifaddress
=0-(newentryaddress-oldentryaddress+4+15);
InBlock.gif
//返回地址计算的方法是新的入口地址减去老的入口地址加4(地址长度)加15(二进制代码相对偏移)后取反
InBlock.gif
tmp=address>>24;
InBlock.gifwaddress[
3]=tmp;
InBlock.giftmp
=address<<8;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
2]=tmp;
InBlock.giftmp
=address<<16;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
1]=tmp;
InBlock.giftmp
=address<<24;
InBlock.giftmp
=tmp>>24;
InBlock.gifwaddress[
0]=tmp;
InBlock.gifretf
=_write(ret,waddress,4);
InBlock.gif
//写入返回地址
InBlock.gif
if(retf==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifprintf(
"error write: %d\n",GetLastError());
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gif_close(ret);
InBlock.gifprintf(
"\nall donedot.gif\n");
InBlock.gif
return;
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif
//end


        由于在PE格式的文件中,所有的地址都使用RVA地址,所以一些函数调用和返回地址都要经过计算才可以得到,以上是我在实践中的心得,如果你有更好的办法,真心的希望你能告诉我。

转载于:https://www.cnblogs.com/hackerxxw/archive/2008/05/29/1210257.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值