首页
论坛
课程
招聘
[原创]菜鸟注释PEMaker6源代码(二)
2007-9-17 14:15 5472

[原创]菜鸟注释PEMaker6源代码(二)

2007-9-17 14:15
5472
今天注释的是CITMaker类,其中应该有不少的错误,请大家附加自己的思考吧
这个类的主要作用是根据下面的字符串计算所需的导入表大小以及构建导入表
PEMaker6下载地址:http://www.mydatabus.com/public/panzhibin/pemaker6.zip
static const char *sz_IT_EXE_strings[]=
{
    "Kernel32.dll",
    "LoadLibraryA",
    "GetProcAddress",
    0,
    0,
};

const char *sz_IT_OCX_strings[]=
{
    "Kernel32.dll",
    "LoadLibraryA",
    "GetProcAddress",
    "GetModuleHandleA",
    0,
    "User32.dll",
    "GetKeyboardType",
    "WindowFromPoint",
    0,
    "AdvApi32.dll",
    "RegQueryValueExA",
    "RegSetValueExA",
    "StartServiceA",
    0,
    "Oleaut32.dll",
    "SysFreeString",
    "CreateErrorInfo",
    "SafeArrayPtrOfIndex",
    0,
    "Gdi32.dll",
    "UnrealizeObject",
    0,
    "Ole32.dll",
    "CreateStreamOnHGlobal",
    "IsEqualGUID",
    0,
    "ComCtl32.dll",
    "ImageList_SetIconSize",
    0,
    0,
};
//----------------------------------------------------------------
using namespace std;

//----------------------------------------------------------------
typedef struct
{
    CHAR szFunction[32];
}t_IMAGE_THUNK, *pt_IMAGE_THUNK;
//----------------------------------------------------------------
typedef struct
{
    CHAR szLibrary[32];
    //链表
    list <t_IMAGE_THUNK> ThunksList;
    //链表指针
    list <t_IMAGE_THUNK>::iterator ThunkIter;
    CHAR szFunction[32];
}t_IMAGE_IMPORT_TABLE, *pt_IMAGE_IMPORT_TABLE;
//----------------------------------------------------------------
static list <t_IMAGE_IMPORT_TABLE> ImportTable;
static list <t_IMAGE_IMPORT_TABLE>::iterator ImportIter;
//================================================================
CITMaker::CITMaker(int iType)
{
    //初始化
    Initialization(iType);
    //计算出所需的导入表大小
    dwSize=Get_IT_Size();
    //申请空间
    pMem=new CHAR[dwSize];
}

CITMaker::~CITMaker()
{
    ImportTable.clear();
    delete [] pMem;
}
//----------------------------------------------------------------
// This function makes the dll name strings, saves them to the linked list
void CITMaker::Initialization(int iType)
{
    int i;
    PCHAR *sz_IT_strings;
    t_IMAGE_IMPORT_TABLE    imageimport;
    t_IMAGE_THUNK            imagethunk;
    switch(iType)
    {
    case IMPORT_TABLE_EXE:
        sz_IT_strings=(PCHAR *)sz_IT_EXE_strings;
        break;
    case IMPORT_TABLE_OCX:
        sz_IT_strings=(PCHAR *)sz_IT_OCX_strings;
        break;
    }
    //静态全局变量--------------------------------------------
    ImportTable.clear();
    i=0;
    do
    {
        //复制库名
        strcpy(imageimport.szLibrary,sz_IT_strings[i]);
        //清空imageimport--Thunk列表
        imageimport.ThunksList.clear();
        do
        {

            i++;
            //取API函数名
            if(sz_IT_strings[i]!=0)
            {
                //向imagethunk---复制函数名
                strcpy(imagethunk.szFunction,sz_IT_strings[i]);
                //放入链表
                imageimport.ThunksList.push_back(imagethunk);
            }
        }while(sz_IT_strings[i]!=0);  //循环取得函数名
        ImportTable.push_back(imageimport);    //入ImportTable链表
        i++;
    }
    while(sz_IT_strings[i]!=0);
    //其实EXE文件只有一个表被建立--------------------------------------------
}
//----------------------------------------------------------------
// This function calculated zise of Import Table.
//计算导入表大小
//引入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组。
//每个结构包含PE文件引入函数的一个相关DLL的信息
//比如,如果该PE文件从10个不同的DLL中引入函数,那么这个数组就有10个成员。
//该数组以一个全0的成员结尾。
//这里引入另一篇文章的自建导入表的结构,借鉴一下更直观,不一定准确:
/*align 4
  v_ImportA  dd Ker_API-v_ImportA      ;IMAGE_THUNK_DATA 数组指针
  v_TimeDateA dd 0              ;文件建立时间
  v_ForChainA dd 0              ;0
  v_DllNameA dd KerName-v_ImportA      ;DLL名称
  v_FThunkA  dd vGetprocAddress-v_ImportA  ;IMAGE_THUNK_DATA 数组指针

  v_ImportB  dd Use_API-v_ImportA      ;IMAGE_THUNK_DATA 数组指针
  v_TimeDateB dd 0              ;文件建立时间
  v_ForChainB dd 0              ;0
  v_DllNameB dd UserName-v_ImportA      ;DLL名称
  v_FThunkB  dd vMessageBoxA-v_ImportA    ;IMAGE_THUNK_DATA 数组指针

        dd 20 dup (0)          ;引入表结束符

  KerName db 'KERNEL32.DLL',0
  Ker_API dd KAPI_A-v_ImportA
      dd KAPI_B-v_ImportA
      dd KAPI_C-v_ImportA
      dd KAPI_D-v_ImportA
      dd KAPI_E-v_ImportA
      dd KAPI_F-v_ImportA
      dd KAPI_G-v_ImportA
      dd KAPI_H-v_ImportA
      dd KAPI_I-v_ImportA
      dd KAPI_J-v_ImportA
      dd KAPI_K-v_ImportA
      dd KAPI_L-v_ImportA
      dd KAPI_M-v_ImportA
      dd KAPI_N-v_ImportA
      dd KAPI_O-v_ImportA
      dd KAPI_P-v_ImportA
      dd KAPI_Q-v_ImportA
      dd 0

  UserName db 'USER32.DLL',0
  Use_API dd UAPI_A-v_ImportA
      dd 0

  vGetprocAddress   dd 0
  vGetModuleHandleA  dd 0
  vLoadLibraryA    dd 0
  vExitprocess     dd 0
  vCreateFileA     dd 0
  vCreateFileMappingA dd 0
  vGetTempPathA    dd 0
  vGetTempFileNameA  dd 0
  vlstrlen       dd 0
  vMapViewOfFile    dd 0
  vWriteFile      dd 0
  vUnmapViewOfFile   dd 0
  vCloseHandle     dd 0
  vCopyFileA      dd 0
  vGetModuleFileNameA dd 0
  vDeleteFileA     dd 0
  vWinExec       dd 0

  vMessageBoxA dd 0
         dd 0

  KAPI_A db 0,0,'GetprocAddress',0
  KAPI_B db 0,0,'GetModuleHandleA',0
  KAPI_C db 0,0,'LoadLibraryA',0
  KAPI_D db 0,0,'Exitprocess',0
  KAPI_E db 0,0,'CreateFileA',0
  KAPI_F db 0,0,'CreateFileMappingA',0
  KAPI_G db 0,0,'GetTempPathA',0
  KAPI_H db 0,0,'GetTempFileNameA',0
  KAPI_I db 0,0,'lstrlen',0
  KAPI_J db 0,0,'MapViewOfFile',0
  KAPI_K db 0,0,'WriteFile',0
  KAPI_L db 0,0,'UnmapViewOfFile',0
  KAPI_M db 0,0,'CloseHandle',0
  KAPI_N db 0,0,'CopyFileA',0
  KAPI_O db 0,0,'GetModuleFileNameA',0
  KAPI_P db 0,0,'DeleteFileA',0
  KAPI_Q db 0,0,'WinExec',0

  UAPI_A db 0,0,'MessageBoxA',0

 ; 根据引入表的格式,自建的引入表。
 ;------------------------------------(上面的)--
 align 4
*/

DWORD CITMaker::Get_IT_Size()
{
    DWORD dwDLLNum=0;
    DWORD dwFunNum=0;
    DWORD dwszDLLSize=0;
    DWORD dwszFuncSize=0;
    DWORD dwImportSize=0;
    t_IMAGE_IMPORT_TABLE    imageimport;
    t_IMAGE_THUNK            imagethunk;
    //ImportIter是全局变量
    for(ImportIter=ImportTable.begin();ImportIter!=ImportTable.end();ImportIter++)
    {
        imageimport=*ImportIter;
        //注意库名长度计算,+1就是结尾的0
        dwszDLLSize=dwszDLLSize+strlen(imageimport.szLibrary)+1;
        //遍历THUnk链表
        for(imageimport.ThunkIter=imageimport.ThunksList.begin();
            imageimport.ThunkIter!=imageimport.ThunksList.end();
            imageimport.ThunkIter++)
        {
            imagethunk=*imageimport.ThunkIter;
            //注意长度计算,括号中为原始THUNK的结构
            //格式:0,0,函数名字符串,0
            dwszFuncSize=dwszFuncSize+(2+strlen(imagethunk.szFunction)+1);
            //函数计数
            dwFunNum++;
        }
        //以0结尾
        dwFunNum++;
        //库计数
        dwDLLNum++;
    }
    //以空IMAGE_IMPORT_DESCRIPTOR结构结尾
    dwDLLNum++;
    //每个DLL需要一个导入表(20字节)+(API函数数量)*(DWORD)+(所有DLL字符串长度)+(所有函数名字符串长度)
    //这个地方我计算的不是很明白,应该有两个RVA数组,一个是函数名RVA数组,一个是函数地址RVA数组
    //有知道的朋友请指出一下。
    dwImportSize=dwDLLNum*20+dwFunNum*4+dwszDLLSize+dwszFuncSize;
    return(dwImportSize);
}
//----------------------------------------------------------------
//----------------------------------------------------------------
// This function build the dll name strings, saves the ImageImportDescriptors to the loader data.
//建立导入表
void CITMaker::Build(DWORD dwRVA)
{
    //是个RVA
    DWORD                    pITBaseRVA=dwRVA;
    DWORD                    temp;
    DWORD                    dwDLLNum, dwDLLName, dwDLLFirst, dwszDLLSize;
    DWORD                    dwIIDNum, dwFunNum, dwFunFirst, dwszFuncSize;
    DWORD                    dwFirstThunk, dwImportSize;
    //局部变量
    t_IMAGE_IMPORT_TABLE    imageimport;
    t_IMAGE_THUNK            imagethunk;
    //真正导入表结构
    IMAGE_IMPORT_DESCRIPTOR import_descriptor;// -> IID
    //初始化--------------------------------------------
    import_descriptor.OriginalFirstThunk=0;
    import_descriptor.TimeDateStamp=0;
    import_descriptor.ForwarderChain=0;
    import_descriptor.Name=0;
    import_descriptor.FirstThunk=0;
    dwDLLNum=dwDLLName=dwDLLFirst=dwszDLLSize=0;
    dwIIDNum=dwFunNum=dwFunFirst=dwszFuncSize=0;
    dwFirstThunk=dwImportSize=0;
    //遍历总链表--------------------------------------------
    for(ImportIter=ImportTable.begin();ImportIter!=ImportTable.end();ImportIter++)
    {
        imageimport=*ImportIter;
        dwszDLLSize=dwszDLLSize+strlen(imageimport.szLibrary)+1;
        for(imageimport.ThunkIter=imageimport.ThunksList.begin();
            imageimport.ThunkIter!=imageimport.ThunksList.end();
            imageimport.ThunkIter++)
        {
            imagethunk=*imageimport.ThunkIter;
            dwszFuncSize=dwszFuncSize+2+strlen(imagethunk.szFunction)+1;
            dwFunNum++;
        }
        dwFunNum++;
        dwDLLNum++;
    }
    dwDLLNum++;
    //重复得出大小,跟上面一样,为什么不调用函数计算呢,晕
    dwImportSize=dwDLLNum*20+dwFunNum*4+dwszDLLSize+dwszFuncSize;
    //pMem已经初始化:在构造函数中,大小为所有引入表大小--------------------------------------------
    FillMemory(pMem,dwImportSize,0x00);
    //一些偏移量
    dwFirstThunk=dwDLLNum*20;
    dwDLLFirst=dwDLLNum*20+dwFunNum*4;
    dwFunFirst=dwDLLNum*20+dwFunNum*4+dwszDLLSize;
    //pITBaseRVA
    //--------------------------------------------
    for(ImportIter=ImportTable.begin();ImportIter!=ImportTable.end();ImportIter++)
    {
        imageimport=*ImportIter;
        //pITBaseRVA为传递的参数
        //Name:含有指向DLL名字的RVA
        //越过之前的所有IMAGE_IMPORT_DESCRIPTOR结构+所有API地址数组而到达指向DLL名字的RVA
        import_descriptor.Name=pITBaseRVA+dwDLLFirst;
        //越过之前的所有IMAGE_IMPORT_DESCRIPTOR结构得到FirstThunk的RVA
        import_descriptor.FirstThunk=pITBaseRVA+dwFirstThunk;
        //复制一系列IMAGE_IMPORT_DESCRIPTOR
        memcpy(pMem+dwIIDNum*sizeof(IMAGE_IMPORT_DESCRIPTOR),
                   &import_descriptor,
                   sizeof(IMAGE_IMPORT_DESCRIPTOR));
        //复制动态库名称,注意位置dwDLLFirst=dwDLLNum*20+dwFunNum*4!
        memcpy(pMem+dwDLLFirst,
                   imageimport.szLibrary,
                   strlen(imageimport.szLibrary)+1);
        //--------------------------------------------
        for(imageimport.ThunkIter=imageimport.ThunksList.begin();
            imageimport.ThunkIter!=imageimport.ThunksList.end();
            imageimport.ThunkIter++)
        {
            //函数名称链
            imagethunk=*imageimport.ThunkIter;
            //计算函数名称字符串RVA
            temp=pITBaseRVA+dwFunFirst;
            //复制的是一个RVA,包含函数名数组RVA的RVA数组
            //dwFirstThunk=dwDLLNum*20
            memcpy(pMem+dwFirstThunk,
                       &temp,
                       4);
            //THUNK指向的RVA数组所指向的函数名数组
            //dwFunFirst=dwDLLNum*20+dwFunNum*4+dwszDLLSize
            memcpy(pMem+dwFunFirst+2,
                       imagethunk.szFunction,
                       strlen(imagethunk.szFunction)+1);
            //指向下一个位置
            dwFunFirst=dwFunFirst+2+strlen(imagethunk.szFunction)+1;
            dwFirstThunk=dwFirstThunk+4;
        }
        //--------------------------------------------
        temp=0;
        //以零结尾
        memcpy(pMem+dwFirstThunk,
                       &temp,
                       4);
        //指向下一个位置
        dwFirstThunk=dwFirstThunk+4;
        dwDLLFirst=dwDLLFirst+strlen(imageimport.szLibrary)+1;
        //表的数量加一
        dwIIDNum++;
    }
    //莫非是最后一个表,以空表结束--------------------------------------------
    import_descriptor.Name=0;
    import_descriptor.FirstThunk=0;
    //--------------------------------------------
    memcpy(pMem+dwIIDNum*sizeof(IMAGE_IMPORT_DESCRIPTOR),
               &import_descriptor,
               sizeof(IMAGE_IMPORT_DESCRIPTOR));
}

【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

收藏
点赞0
打赏
分享
最新回复 (2)
雪    币: 235
活跃值: 活跃值 (10)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
火影 活跃值 11 2007-9-17 14:35
2
0
根据本文的计算公式,这个自定义导入表的结构好像是这个样子:
一系列IMAGE_IMPORT_DESCRIPTOR
.
.
.
一个RVA数组(包含一个函数名数组的RVA)
.
.
.
动态链接库名字符串数组
.
.
.
函数名字符串数组
.
.
.
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
colboy 活跃值 2007-9-17 16:43
3
0
[QUOTE=;]...[/QUOTE]
支持一下~~好东西!!
游客
登录 | 注册 方可回帖
返回