Chinaunix首页 | 论坛 | 博客
  • 博客访问: 100733
  • 博文数量: 11
  • 博客积分: 1581
  • 博客等级: 上尉
  • 技术积分: 241
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-13 01:12
文章分类

全部博文(11)

文章存档

2012年(3)

2011年(3)

2010年(5)

我的朋友

分类: WINDOWS

2010-04-16 13:25:53

如何获取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;
}
阅读(3106) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~