吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8455|回复: 5
收起左侧

[IDA Plugin] IDB2EXE.idc 一个从IDB文件生成EXE文件的idc脚本示例

[复制链接]
Hmily 发表于 2010-1-7 16:38
标 题: 【原创】IDB2EXE.idc 一个从IDB文件生成EXE文件的idc脚本示例
作 者: nkspark
时 间: 2010-01-06,16:15
链 接: http://bbs.pediy.com/showthread.php?t=104632

#include <idc.idc>

//
//+++++++++++++++++++++++++++++++++++++++++++++
//
// IDB2EXE.idc 
//
// Written by Spark.   nkspark_at_gmail.com
// 
//          2010.01.06
//+++++++++++++++++++++++++++++++++++++++++++++
//

#define E_MAGIC               0x5a4d
#define E_LFANEW              0xe0
#define E_LFANEW_OFFSET        0x3c
#define SIGNATURE             0x00004550
#define MACHINE                0x014c
#define SECTIONNUMBER_OFFSET  0x06
#define IAT_OFFSET            0x80
#define PEHEADERLENGTH        0xf8
#define SECTIONTABLE_OFFSET    E_LFANEW + PEHEADERLENGTH
#define SECTIONENTRYLENGTH    0x28


static GetIDBFilePath()
{
  auto strIDBFilePath;//idb full path name;
  auto strEXEFileName;
  auto iNameEnd;
  auto iPathEnd;
  auto strPath;
  auto pFile;
  
  strPath = GetInputFilePath();
  strEXEFileName = GetInputFile();
  iPathEnd = strstr(strPath,strEXEFileName);
  iNameEnd = strstr(strEXEFileName,".");
  strIDBFilePath = substr(strPath,0,iPathEnd) + substr(strEXEFileName,0,iNameEnd) + ".idb";
  
  //Message("idb file lies in %s\n",strIDBFilePath);
  
  pFile = fopen(strIDBFilePath,"r");
  if(!pFile)
  {
    strIDBFilePath = AskStr(strIDBFilePath,"Please provide the path of IDB file:");
    return strIDBFilePath;
  }
  fclose(pFile);
  return   strIDBFilePath;
}

//从IDB文件中获取IAT的偏移地址
static GetIATOffset(strIDBFilePath, PEHeaderOffset)
{
    auto pIDB;
    auto IATOffset;
    
    pIDB =fopen(strIDBFilePath,"rb");

    if(!pIDB)
    {
      Message("Can not open idb file!\n");
      return -1;
    }
    
    fseek(pIDB,PEHeaderOffset + IAT_OFFSET,0);
    IATOffset = readlong(pIDB,0);

    fclose(pIDB);
    return IATOffset;
  
}

//从IDB文件中获取PE头的起始地址
static SearchPEHeader(pIDB)
{
    auto PEHeaderOffset;
    auto i;
    auto iFileSize;
    
    
    fseek(pIDB,0x0,2);
    iFileSize = ftell(pIDB);
    
    if( iFileSize == -1)
      return -1;
    
    for(i=0;i<iFileSize;i++)
    {
      fseek(pIDB,i,0);
      //Signature "PE"
      if(readlong(pIDB,0) == SIGNATURE)
        //Machine 0x014c
        if(readshort(pIDB,0) == MACHINE)
        {
          PEHeaderOffset=ftell(pIDB);
          PEHeaderOffset = PEHeaderOffset -0x06;
          return PEHeaderOffset;          
        }
    }    
    return -1;
}

//IDB中的FirstThrunk已经被IDA自动填充,需要清理回原状
static PatchIAT(addrImageBase, addrIAT)
{    
    auto addrOriginalFirstThunk;
    auto addrFirstThunk;
    auto ValueOfIAT;
    
    Message("Start patching IAT at %x\n",addrIAT);
    
    if(Dword(addrIAT) == BADADDR)
    {
      Message("IAT data was not loaded into IDB file!\n");
      return -1;
    }
    
    do
    {
      addrOriginalFirstThunk = addrImageBase + Dword(addrIAT);
      addrFirstThunk = addrImageBase + Dword(addrIAT+0x10);
      
      do
      {
        PatchDword(addrFirstThunk,Dword(addrOriginalFirstThunk));
        addrOriginalFirstThunk = addrOriginalFirstThunk +0x04;
        addrFirstThunk = addrFirstThunk +0x04;
                  
      }while(Dword(addrOriginalFirstThunk) != 0);
      
      addrIAT = addrIAT + 0x14;
      
    }while(Dword(addrIAT) != 0);
    
}

//为创建的EXE文件生成一个PE头
static BuildHeader(pFile,strIDBFilePath)
{
    auto i,j;
    auto pIDB;
    auto addrPE;
    auto iSectionNumber;
    auto lByte;

    pIDB =fopen(strIDBFilePath,"rb");
    if(!pIDB)
    {
      Message("Can not open idb file!\n");
      return -1;
    }
    
    fseek(pFile,0x0,0);
    writeshort(pFile,E_MAGIC,0);
    fseek(pFile,E_LFANEW_OFFSET,0);
    writeshort(pFile,E_LFANEW,0);
    
    
    addrPE = SearchPEHeader(pIDB);
    if(addrPE == -1)
    {
      Message("Can not find PE header in IDB file!\n");
      return -1;
    }
    Message("PEHeaderOffset is %x\n",addrPE);
    
    fseek(pIDB,addrPE,0);
    fseek(pFile,E_LFANEW,0);
    
    //Copy PE header
    //IAT should be set to 0 later!!!
    for(i=0;i<PEHEADERLENGTH;i++)
    {
        lByte = fgetc(pIDB);
        fputc(lByte,pFile);
    }

    fseek(pIDB,addrPE+SECTIONNUMBER_OFFSET,0);
    
    iSectionNumber = fgetc(pIDB);
          
    Message("there are %d sections!\n",iSectionNumber);
    
    //Prepare to write section table
    fseek(pFile,SECTIONTABLE_OFFSET,0);
    fseek(pIDB,addrPE+SECTIONTABLE_OFFSET-E_LFANEW,0);
    
    for(j=0;j<iSectionNumber;j++)
    {
      
      //每个表项有6字节偏移;
      fseek(pIDB,6,1);
      //最后一个表项有多余4字节偏移;
      if(j == (iSectionNumber-1))
        fseek(pIDB,4,1);
      
      
      //section table should be corrected later!!!!    
      for(i=0;i<SECTIONENTRYLENGTH;i++)
      {
          lByte = fgetc(pIDB);
          fputc(lByte,pFile);
      }
      Message("write %d section table!\n",j);
    }
    fclose(pIDB);
    
    //返回addrPE以备后用 :)
    return addrPE;
    
}

//内存地址转换为文件地址
static RVA2FA(pFile)
{
    auto iSectionNumber;
    auto iSectionBase;
    auto i;
    
    fseek(pFile,E_LFANEW + SECTIONNUMBER_OFFSET,0);
    iSectionNumber = readshort(pFile,0);

    fseek(pFile,SECTIONTABLE_OFFSET + (iSectionNumber -1) * SECTIONENTRYLENGTH + 0x14,0);
    iSectionBase = readlong(pFile,0);      
    Message("Section base in exe file is %x\n",iSectionBase);

    return iSectionBase;
    
}
//修正PE头信息
static PEHeaderCorrect(pFile)
{
    //关键处理,暂不外传!
    return 0;
}

static main()
{
  auto temp,i;
  auto startAddr, endAddr;
  auto countOR;
  auto pFile;
  auto strOutFileName;
  auto segStart;
  auto segEnd;
  auto iImageBase;
  auto iSectionAlignment;
  auto PEHeaderOffset;
  auto IATOffset;
  auto strIDBFilePath;
  auto iSectionBase;

  startAddr = MinEA();
  endAddr = MaxEA();
  iImageBase = FirstSeg() & 0xffff0000;
  iSectionAlignment = FirstSeg() & 0xffff;
  
  Message("Base:%x ,EP:%x , Min:%x  , Max:%x  \n",iImageBase,BeginEA(),MinEA(),MaxEA());
  
  strIDBFilePath = GetIDBFilePath();
  Message("idb file lies in %s\n",strIDBFilePath);
  
  strOutFileName = strIDBFilePath + "_dump.exe";

  pFile=fopen(strOutFileName,"w+b");
  
  PEHeaderOffset = BuildHeader(pFile,strIDBFilePath);
  if (PEHeaderOffset == -1)
    return -1;
    
  IATOffset = GetIATOffset(strIDBFilePath,PEHeaderOffset);
  if (IATOffset == -1)
    return -1;
    
  iSectionBase = RVA2FA(pFile);

  PatchIAT(iImageBase,iImageBase + IATOffset);
  
  for(i=startAddr;i<endAddr;)
  {
    segStart = GetSegmentAttr(i,SEGATTR_START);
    if(segStart == BADADDR) break;
    segEnd = GetSegmentAttr(i,SEGATTR_END);
    if(segEnd == BADADDR) break;    
    savefile(pFile, iSectionBase + segStart - iImageBase -iSectionAlignment,segStart,segEnd-segStart);
    Message("seg %x : %x : %x \n",GetSegmentAttr(i,SEGATTR_ALIGN),segStart,segEnd);
    i = segEnd + 1;
  }
  
  PEHeaderCorrect(pFile);
  
  fclose(pFile);
  
  return 0;
}


关键两点:
1、建立一个PE头。这个可以直接从IDB的原始文件中提取,可能好多人没想到。知道这一点后,基本上就可以自己写这个脚本了。
2、PE头修正。导出的EXE文件如果不修正的话,可能会跑不起来,例如IDA缺省情况下是不加载资源节的,这时导出的是不完整的EXE文件。我的自用版本可以让不完整的导出EXE正常跑到资源加载处正常退出。自用版本这里就不公开了,有人出高价的话,我可以卖给他 :)

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

avzhongjiezhe 发表于 2010-2-1 15:05
看了半天,代码还是有一部分没懂
avzhongjiezhe 发表于 2010-2-3 09:50
kghong 发表于 2010-2-13 13:54
ty154w 发表于 2011-2-28 11:09
190.    for(j=0;j<iSectionNumber;j++)

191.    {

192.      

193.      //每个表项有6字节偏移;

194.      fseek(pIDB,6,1);

195.      //最后一个表项有多余4字节偏移;不同的ida偏移字节不一样v5.5为102字节

196.      if(j == (iSectionNumber-1))

197.        fseek(pIDB,4,1);

ty154w 发表于 2011-2-28 11:18
2、PE头修正。导出的EXE文件如果不修正的话,可能会跑不起来,例如IDA缺省情况下是不加载资源节的,这时导出的是不完整的EXE文件。我的自用版本可以让不完整的导出EXE正常跑到资源加载处正常退出。

主要原因是导出的PE头方法不好,采用其他方法不需要进行PE头修正。
另自用版本好像也不能不加载资源节吧?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-15 05:06

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表