如何获取PE文件中的OEP
OEP(Original Entry Point)是每个PE文件被加载时的起始地址,如何获得这个地址很重要,因为修改程序中的这个值是文件加壳和脱壳时的必须步骤,一些黑客程序也是通过修改OEP值来获得对目标程序的控制权从而实施攻击。下面分别介绍如何通过文件直接访问和通过内存映射访问读取OEP值的方法,并给出完整的程序代码。
通过文件读取OEP值
获得OEP值的最简单方法是,直接从一个PE文件中读取OEP。根据以上对PE文件结构的介绍可知,OEP是PE文件的IMAGE_OPTIONAL_HEADER结构的AddressOfEntryPoint成员,在偏移此结构头40个字节处。而IMAGE_OPTIONAL_ HEADER在PE文件的起始位置由IMAGE_DOS_HEADER的e_lfanew成员来计算。注意,以上两个结构在PE文件中不是紧跟在一起的,它之间是DOS Stub,而在每个PE文件DOS Stub的长度可能不一定相等。在PE文件的头部是IMAGE_ DOS_HEADER结构,读取这个结构可以得到e_lfanew的值,因而可以得到IMAGE_ OPTIONAL_HEADER在PE文件中的位置,也就得到了OEP值。以下是通过文件访问的方法读取OEP的程序代码,即:
l
// 通过文件读取OEP值
BOOL ReadOEPbyFile(LPCSTR szFileName)
{
HANDLE hFile;
// 打开文件
if ((hFile = CreateFile(szFileName, GENERIC_READ,
FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
{
printf("Can't not open file.\n");
return FALSE;
}
DWORD dwOEP,cbRead;
IMAGE_DOS_HEADER dos_head[sizeof(IMAGE_DOS_HEADER)];
if (!ReadFile(hFile, dos_head, sizeof(IMAGE_DOS_HEADER), &cbRead, NULL)){
printf("Read image_dos_header failed.\n");
CloseHandle(hFile);
return FALSE;
}
int nEntryPos=dos_head->e_lfanew+40;
SetFilePointer(hFile, nEntryPos, NULL, FILE_BEGIN);
if (!ReadFile(hFile, &dwOEP, sizeof(dwOEP), &cbRead, NULL)){
printf("read OEP failed.\n");
CloseHandle(hFile);
return FALSE;
}
// 关闭文件
CloseHandle(hFile);
// 显示OEP地址
printf("OEP by file:%d\n",dwOEP);
return TRUE;
}
通过内存映射读取OEP值
获得OEP值的另一种方法是通过内存映射来实现,此方法也需要熟悉PE的文件结构。与直接访问PE的方法不同,内存映射的方法首先把PE文件映射到计算机的内存,再通过内存的基指针获得IMAGE_DOS_HEADER的头指针,由此再获得IMAGE_ OPTIONAL_HEADER指针,这样就可以得到AddressOfEntryPoint的值。下面是通过内存映射获得OEP值的方法:
l
// 通过文件内存映射读取OEP值
BOOL ReadOEPbyMemory(LPCSTR szFileName)
{
struct PE_HEADER_MAP
{
DWORD signature;
IMAGE_FILE_HEADER _head;
IMAGE_OPTIONAL_HEADER opt_head;
IMAGE_SECTION_HEADER section_header[6];
} *header;
HANDLE hFile;
HANDLE hMapping;
void *basepointer;
// 打开文件
if ((hFile = CreateFile(szFileName, GENERIC_READ,
FILE_SHARE_READ,0,OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,0)) == INVALID_HANDLE_VALUE)
{
printf("Can't open file.\n");
return FALSE;
}
// 创建内存映射文件
if (!(hMapping = CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT, 0,0,0)))
{
printf("Mapping failed.\n");
CloseHandle(hFile);
return FALSE;
}
// 把文件头映象存入baseointer
if (!(basepointer = MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0)))
{
printf("View failed.\n");
CloseHandle(hMapping);
CloseHandle(hFile);
return FALSE;
}
IMAGE_DOS_HEADER * dos_head =(IMAGE_DOS_HEADER *)basepointer;
// 得到PE文件头
header = (PE_HEADER_MAP *)((char *)dos_head + dos_head->e_lfanew);
// 得到OEP地址.
DWORD dwOEP=header->opt_head.AddressOfEntryPoint;
// 清除内存映射和关闭文件
UnmapViewOfFile(basepointer);
CloseHandle(hMapping);
CloseHandle(hFile);
// 显示OEP地址
printf("OEP by memory:%d\n",dwOEP);
return TRUE;
}
阅读(3183) | 评论(0) | 转发(0) |