MemoryModule阅读与PE文件解析(二)---导入表

MemoryModule阅读与PE解析(二)---导入表

首先来了解导入表的概念

头文件:

#ifndef DLL_FUC

#define DLL_FUC extern"C" __declspec(dllimport)

#endif

实现:这里函数只是简单的输出 HelloA

 

void HelloExprotFunctionA()

{

    printf("HelloA\n");

}

 

使用:

#include "../x86Dll/x86Dll.h"

#pragma comment(lib,"../debug/x86Dll.lib")

HelloExprotFunctionA();

 

我们调试反汇编发现,其调用指向内存0x00318378 内存位置的内容,即地址0x52D013A0h,F11进去之后发现确实跳转到了该地址,该地址即为HelloExprotFunctionA函数的地址。

使用ProcessHacker得到进程模块基地址如下:

由此算到上面的那个内存地址0xC83788的RVA为:0x18378

使用CFF Explorer 打开exe 然后查看RVA 对应内容发现:

保存的是一个RVA,得到了导入函数名,后面还有模块名称

 

我们发现exe文件中并没有HelloExprotFunctionA函数的地址,该位置出存储的仅仅是一个结构的地址而已,然而当程序运行起来之后,其存储的值为函数的地址,请看下图

图片来源:http://blog.csdn.net/evileagle/article/details/12357155

导入表中有一个成员FirstThunk指向IAT结构,在PE加载入内存之前,其值与OriginalFirstThunk相同,指向一个结构体,在PE被加载之后,FirstThunk 中的内容变为函数的真实地址,在其函数中对于导入函数的引用就是取的导入表中对应位置的地址,然后跳转到目标函数运行。

我们来看call 指令的地址,计算得到其RVA后在exe 中查看其内容如下:

我们发现其存储的就是一个绝对地址,而这个地址在exe 初始化的时候由于上一节提到的修正了重定向项,其值变为真实的IAT 对应的项的地址。

PE 未加载时,该函数引用的是一个VA----其刚好对应于IAT 中对应项的RVA。这样,我们就明白了PE 文件引用外部函数的过程,导入表的修订,就是将IAT中的对应的项的地址修正为所要引用的函数的真实地址即可,所谓的对应,就是与上图中函数编号-函数名的结构体对应,根据该结构体来获得PE引用的外部函数的(DLL 名称,函数名称)来得到对应的函数地址,然后填充IAT中对应的项即可

简单介绍相关结构:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

    union {

        DWORD   Characteristics;     // 0 forterminating null import descriptor

        DWORD   OriginalFirstThunk;// PIMAGE_THUNK_DATA结构的其实RVA,为0表示结束

    } DUMMYUNIONNAME;

    DWORD   TimeDateStamp;                 //0 如果没有绑定

                                            // -1 绑定

                                            // O.W. date/time stamp of DLL bound to (Old BIND)

 

    DWORD   ForwarderChain;                 //-1 if no forwarders

    DWORD   Name;                           // DLL 名称

    DWORD   FirstThunk;                     //IAT的RVA

}IMAGE_IMPORT_DESCRIPTOR;

 

typedef struct _IMAGE_THUNK_DATA32 {

    union {

        DWORDForwarderString;      // PBYTE

        DWORD Function;            //PDWORD

        DWORDOrdinal;

        DWORDAddressOfData;        // PIMAGE_IMPORT_BY_NAME

    } u1;

}IMAGE_THUNK_DATA32;

typedef IMAGE_THUNK_DATA32* PIMAGE_THUNK_DATA32;

这里存储的是DLL 的名称和序号,所谓需要就是DLL 中导出函数的一个序号,一般不用

typedef struct_IMAGE_IMPORT_BY_NAME{

    WORD    Hint;

    BYTE    Name[1];

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

下面来看修正导入表的函数

static BOOL

BuildImportTable(PMEMORYMODULEmodule)

{

   unsigned char *codeBase = module->codeBase;

   PIMAGE_IMPORT_DESCRIPTOR importDesc;

   BOOL result = TRUE;

 

   PIMAGE_DATA_DIRECTORY directory =GET_HEADER_DICTIONARY(module,IMAGE_DIRECTORY_ENTRY_IMPORT);

   if (directory->Size == 0) {

       return TRUE;

   }

 

   importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress);

   for (; !IsBadReadPtr(importDesc,sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) {

       uintptr_t *thunkRef;

       FARPROC *funcRef;

       HCUSTOMMODULE *tmp;

       HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase +importDesc->Name),module->userdata);

       if (handle == NULL) {

            SetLastError(ERROR_MOD_NOT_FOUND);

            result = FALSE;

            break;

       }

 

       tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE)));

       if (tmp == NULL) {

            module->freeLibrary(handle,module->userdata);

            SetLastError(ERROR_OUTOFMEMORY);

            result = FALSE;

            break;

       }

       module->modules = tmp;

 

       module->modules[module->numModules++] = handle;

       if (importDesc->OriginalFirstThunk) {

            thunkRef = (uintptr_t *) (codeBase +importDesc->OriginalFirstThunk);

            funcRef = (FARPROC *) (codeBase +importDesc->FirstThunk);

       } else {

            // no hint table

            thunkRef = (uintptr_t *) (codeBase +importDesc->FirstThunk);

            funcRef = (FARPROC *) (codeBase +importDesc->FirstThunk);

       }

       for (; *thunkRef; thunkRef++, funcRef++) {

            if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {

                *funcRef = module->getProcAddress(handle,(LPCSTR)IMAGE_ORDINAL(*thunkRef),module->userdata);

            } else {

                PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef));

                *funcRef = module->getProcAddress(handle,(LPCSTR)&thunkData->Name,module->userdata);

            }

            if (*funcRef == 0) {

                result = FALSE;

                break;

            }

       }

       if (!result) {

            module->freeLibrary(handle,module->userdata);

            SetLastError(ERROR_PROC_NOT_FOUND);

            break;

       }

   }

 

   return result;

}

IMAGE_SNAP_BY_ORDINAL 宏用于判断当前的导入函数是否是按照序号导入的,如果是的话,下面的宏IMAGE_ORDINAL用于取出序号。

#define IMAGE_ORDINAL_FLAG32 0x80000000

#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal &IMAGE_ORDINAL_FLAG32) != 0)

如果最高位为1,表示按照序号导入

#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff)

表示取低四字节来表示序号。

 

然后导入表的修正已经结束了,剩下的一节介绍剩余知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存加载动态库 MemoryLoadLibrary 有例子。 /* * Memory DLL loading code * Version 0.0.3 * * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is MemoryModule.h * * The Initial Developer of the Original Code is Joachim Bauch. * * Portions created by Joachim Bauch are Copyright (C) 2004-2013 * Joachim Bauch. All Rights Reserved. * */ #ifndef __MEMORY_MODULE_HEADER #define __MEMORY_MODULE_HEADER #include typedef void *HMEMORYMODULE; typedef void *HMEMORYRSRC; typedef void *HCUSTOMMODULE; #ifdef __cplusplus extern "C" { #endif typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *); typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); /** * Load DLL from memory location. * * All dependencies are resolved using default LoadLibrary/GetProcAddress * calls through the Windows API. */ HMEMORYMODULE MemoryLoadLibrary(const void *); /** * Load DLL from memory location using custom dependency resolvers. * * Dependencies will be resolved using passed callback methods. */ HMEMORYMODULE MemoryLoadLibraryEx(const void *, CustomLoadLibraryFunc, CustomGetProcAddressFunc, CustomFreeLibraryFunc, void *); /** * Get address of exported method. */ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); /** * Free previously loaded DLL. */ void MemoryFreeLibrary(HMEMORYMODULE); /** * Find the location of

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值