首页
社区
课程
招聘
求助:编写PELoader及修改PE某一区段的大小程序的问题
发表于: 2005-6-18 09:33 8933

求助:编写PELoader及修改PE某一区段的大小程序的问题

2005-6-18 09:33
8933
最近学习PE格式,顺便编了一个给exe文件添加初始化代码,以及给PE文件添加段的程序,敬请指教,另外我试图编一个EXE Loader,初步想法是先用LoadLibrary装载程序,再将数据装载到申请的一段内存中,最后用一条jmp指令条转到OEP中,结果总是不成功,不知哪里还有错误。
/*由于VC不支持db,dd等伪代码,并且发现不能将asm段中的标号直接赋值给变量,因此写了一个函数将codestart与codeend之间的代码作为数据保存到缓冲区中,返回缓冲区的首地址,并且修改len为代码大小*/
LPBYTE Code2Data2(DWORD *len)
{
        BYTE *data;
        DWORD start,end;
       
        _asm{
                jmp CodeEnd;
CodeStart:
                nop;
                nop;
                nop;
                nop;
                nop;
CodeEnd:
                mov eax,offset CodeEnd
                        mov end,eax
                       
                        mov eax ,offset CodeStart
                        mov start,eax
        }
       
        *len=end-start;
        data=new BYTE[*len];
        memcpy(data,(void*)(start),*len);
       
        return data;
}
//add some codes..
/*在程序中添加一段代码,代码为Code2Data2(DWORD *len)中的codestart,codeend之间的内容,最后还添加了一条跳转指令,跳转到原来的程序入口*/
void CAddCode_MFCDlg::OnBTNOpenFile()
{
        // TODO: Add your control notification handler code here
        CFile f;
        IMAGE_DOS_HEADER *DosHdr;
        IMAGE_NT_HEADERS *NtHdr;
        IMAGE_SECTION_HEADER *SecHdr;
        CString fname;
        int SecCodeIndex=100;
        char *dossig="MZ",*pesig="PE\0\0\0";
        DWORD datalen;
        LPBYTE data=::Code2Data2(&datalen);
       
        char myjmp[5]={(char)0xe9};DWORD* jmpaddr=(DWORD*)(myjmp+1);//跳转指令
        LPBYTE buf;
        DWORD len;
       
        CFileDialog dlg(TRUE,NULL,NULL,0,"exe files (*.exe)|*.exe||",this);//打开文件对话框
        if(dlg.DoModal()!=IDOK)
        {
                AddLine("you press cancel");return;
        }
        fname=dlg.GetPathName();
        AddLine("open file "+fname+" ok");
       
        char szf1[200],szf2[200];
        char sa[200],sb[200],sc[200],sd[200];
        sprintf(szf1,"%s",(LPCTSTR)fname);
        ::_splitpath(szf1,sa,sb,sc,sd);
        sprintf(szf2,"%s%s%s_2%s",sa,sb,sc,sd);
       
        if(!f.Open(szf1,0))
        {
                AddLine("open for r error");return;
        }
        len=f.GetLength();
        buf=new BYTE[len];//分配内存
        f.ReadHuge(buf,len);//读入数据
        f.Close();
        CString s;
        s.Format("Copy Data To Buf,Filelen=%d",len);
        AddLine(s);
        //检查文件格式
        DosHdr=(PIMAGE_DOS_HEADER)buf;
        if(DosHdr->e_magic!=*(WORD*)dossig)//"MZ"标志
        {
                AddLine("dossig error");return;
        }
       
        NtHdr=(PIMAGE_NT_HEADERS)(buf+DosHdr->e_lfanew);
        if(NtHdr->Signature!=*(DWORD*)pesig)//"PE标志"
        {
                AddLine("pesig error");return;
        }
        AddLine("Checking file format ...ok");
       
        SecHdr=(PIMAGE_SECTION_HEADER)(NtHdr+1);//定位到段表
        //查找代码段
        for(int i=0;i<NtHdr->FileHeader.NumberOfSections;i++)
        {
                if(NtHdr->OptionalHeader.BaseOfCode==SecHdr[i].VirtualAddress)
                {
                        CString s;
                        s.Format("found %s sec:%d/%d",SecHdr[i].Name,i,NtHdr->FileHeader.NumberOfSections);
                        SecCodeIndex=i;
                        AddLine(s);break;
                }
        }
       
        DWORD oldOEP=NtHdr->OptionalHeader.AddressOfEntryPoint,
                newOEP=SecHdr[i].VirtualAddress+SecHdr[i].Misc.VirtualSize,//
                newVirtSize=SecHdr[i].Misc.VirtualSize+datalen+5;//
       
        *jmpaddr=oldOEP-(newOEP+datalen+5);//
        DWORD FreeSpace=SecHdr[i].SizeOfRawData-SecHdr[i].Misc.VirtualSize;
       
       
        if(FreeSpace<5+datalen) //检查空间是否足够
        {
                s.Format("freespace %u not enough",FreeSpace);
                AddLine(s);return;
        }else {
                s.Format("freespace %u enough",FreeSpace);
                AddLine(s);
        }
        //复制指令数据
        memcpy(SecHdr[i].PointerToRawData+SecHdr[i].Misc.VirtualSize+buf,data,datalen);//
        memcpy(SecHdr[i].PointerToRawData+SecHdr[i].Misc.VirtualSize+buf+datalen,myjmp,5);//
        DWORD jmpRVA=SecHdr[i].PointerToRawData+SecHdr[i].Misc.VirtualSize+datalen,
                codeRVA=SecHdr[i].PointerToRawData+SecHdr[i].Misc.VirtualSize;
        //修改文件头
        NtHdr->OptionalHeader.AddressOfEntryPoint=newOEP;
        SecHdr[i].Misc.VirtualSize=newVirtSize;
        SecHdr[i].Characteristics|=0xC0000000|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
        memcpy(SecHdr[i].Name,".code",8);
        AddLine("Copy data and jmp codes to buffer.");
        AddLine("Modify Prog's OEP and sec's VA,Flags,Name.");
       
        if(!f.Open(szf2,CFile::modeCreate|CFile::modeWrite))
        {
                AddLine("open for w error");return;
        }
        f.WriteHuge(buf,len);//写入新文件
        f.Close();
        s.Format("Write to file %s ok.",szf2);
        AddLine(s);
        delete []buf;
       
}
//测试Code2Data2的代码
void CAddCode_MFCDlg::OnButton1()
{
        unsigned char * p=0;
        DWORD len;
        CString s;
       
        p=Code2Data2(&len);
        s.Format("DataLen:%d\r\n",len);
        for(DWORD i=0;i<len;i++)
        {
                char ss[10];
                sprintf(ss,"%.2X ",p[i]);
                s=s+ss;
        }
        AddLine(s);
       
        delete []p;
}
//在文本框中添加1行数据
void CAddCode_MFCDlg::AddLine(char *s)
{
        UpdateData(TRUE);
        m_Info=m_Info+s+"\r\n";
        UpdateData(false);
}

void CAddCode_MFCDlg::AddLine(CString s)
{
        UpdateData(TRUE);
        m_Info=m_Info+s+"\r\n";
        UpdateData(false);
}
//对齐
DWORD Align(DWORD a,DWORD b)
{
        if(a%b)
        {
                a=a+b-a%b;
        }
        return a;
}
//给文件添加一个段
void CAddCode_MFCDlg::OnBtnAddSection()
{
        // 新段的大小Rsize和VSize
        DWORD SecRSize=0x1000,SecVSize=0x500;
        BYTE SecName[8]=".test";
        DWORD newLen;
        CFile f;
        IMAGE_DOS_HEADER *DosHdr;
        IMAGE_NT_HEADERS *NtHdr;
        IMAGE_SECTION_HEADER *SecHdr,*SecLast,*SecNew;
        CString fname;
        int SecCodeIndex=100;
        char *dossig="MZ",*pesig="PE\0\0\0";
        DWORD datalen;
        LPBYTE data=::Code2Data2(&datalen);
        CString s;
        LPBYTE buf;
        DWORD len;
       
        AddLine("---------starting----------------");
        CFileDialog dlg(TRUE,NULL,NULL,0,"exe files (*.exe)|*.exe||",this);//打开文件
        if(dlg.DoModal()!=IDOK)
        {
                AddLine("you press cancel");return;
        }
        fname=dlg.GetPathName();
        AddLine("open file "+fname+" ok");
       
        char szf1[200],szf2[200];
        char sa[200],sb[200],sc[200],sd[200];
        sprintf(szf1,"%s",(LPCTSTR)fname);
        ::_splitpath(szf1,sa,sb,sc,sd);
        sprintf(szf2,"%s%s%s_2%s",sa,sb,sc,sd);
       
        if(!f.Open(szf1,0))
        {
                AddLine("open for r error");return;
        }
        len=f.GetLength();
        newLen=len+SecRSize;//change
        buf=new BYTE[newLen];///分配内存
        f.ReadHuge(buf,len);
        f.Close();
        s.Format("Copy Data To Buf,Filelen=%d",len);
        AddLine(s);
       
        DosHdr=(PIMAGE_DOS_HEADER)buf;
        if(DosHdr->e_magic!=*(WORD*)dossig)//检查格式
        {
                AddLine("dossig error");return;
        }
       
        NtHdr=(PIMAGE_NT_HEADERS)(buf+DosHdr->e_lfanew);
        if(NtHdr->Signature!=*(DWORD*)pesig)
        {
                AddLine("pesig error");return;
        }
        AddLine("Checking file format ...ok");
       
        SecHdr=(PIMAGE_SECTION_HEADER)(NtHdr+1);
        SecLast=SecHdr+NtHdr->FileHeader.NumberOfSections-1;
        SecNew=SecLast+1;
        //添加一个段
        NtHdr->FileHeader.NumberOfSections++;
        memcpy(SecNew,SecLast,sizeof(IMAGE_SECTION_HEADER));
        SecNew->PointerToRawData+=SecLast->SizeOfRawData;
        SecNew->SizeOfRawData=Align(SecRSize,NtHdr->OptionalHeader.FileAlignment);
        NtHdr->OptionalHeader.SizeOfImage+=Align(SecRSize,NtHdr->OptionalHeader.SectionAlignment);
        NtHdr->OptionalHeader.SizeOfCode+=Align(SecRSize,NtHdr->OptionalHeader.SectionAlignment);
        SecNew->VirtualAddress+=Align(SecLast->Misc.VirtualSize,NtHdr->OptionalHeader.SectionAlignment);
        SecNew->Misc.VirtualSize=SecVSize;
        SecNew->Characteristics=IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
        memcpy(SecNew->Name,SecName,8);
       
        if(!f.Open(szf2,CFile::modeCreate|CFile::modeWrite))
        {
                AddLine("open for w error");return;
        }
        f.WriteHuge(buf,newLen);///写入文件
        f.Close();
        s.Format("Write to file %s ok.",szf2);
        AddLine(s);
        delete []buf;
}
//修改某一个区段的大小
//执行时有错误,不知遗漏了什么或者错误了那里,望指教
void CAddCode_MFCDlg::OnBtnChgSecSize()
{
        //要修改的区段的序号,要添加的大小注意必须对rsizeadd进行对齐
        int secindex=0,rsizeadd=0x2000,vsizeadd=0x1000;
        DWORD newLen;
        CFile f;
        IMAGE_DOS_HEADER *DosHdr;
        IMAGE_NT_HEADERS *NtHdr;
        IMAGE_SECTION_HEADER *SecHdr,*SecThis;
        CString fname;
        int SecCodeIndex=100;
        char *dossig="MZ",*pesig="PE\0\0\0";
        DWORD datalen;
        CString s;
        LPBYTE buf;
        DWORD len;
        int i;
       
        AddLine("---------starting----------------");
        CFileDialog dlg(TRUE,NULL,NULL,0,"exe files (*.exe)|*.exe||",this);
        if(dlg.DoModal()!=IDOK)
        {
                AddLine("you press cancel");return;
        }
        fname=dlg.GetPathName();
        AddLine("open file "+fname+" ok");
       
        char szf1[200],szf2[200];
        char sa[200],sb[200],sc[200],sd[200];
        sprintf(szf1,"%s",(LPCTSTR)fname);
        ::_splitpath(szf1,sa,sb,sc,sd);
        sprintf(szf2,"%s%s%s_2%s",sa,sb,sc,sd);
       
        if(!f.Open(szf1,0))
        {
                AddLine("open for r error");return;
        }
        len=f.GetLength();
        newLen=len+2*rsizeadd;//change,由于尚未对rsizeadd进行对齐,故多分配一部分内存
        buf=new BYTE[newLen];///
        f.ReadHuge(buf,len);//读入数据
        f.Close();
        s.Format("Copy Data To Buf,Filelen=%d",len);
        AddLine(s);
       
        DosHdr=(PIMAGE_DOS_HEADER)buf;//检查格式
        if(DosHdr->e_magic!=*(WORD*)dossig)
        {
                AddLine("dossig error");return;
        }
       
        NtHdr=(PIMAGE_NT_HEADERS)(buf+DosHdr->e_lfanew);
        if(NtHdr->Signature!=*(DWORD*)pesig)
        {
                AddLine("pesig error");return;
        }
        AddLine("Checking file format ...ok");
       
        //secindex=NtHdr->FileHeader.NumberOfSections-1;//test
       
        SecHdr=(PIMAGE_SECTION_HEADER)(NtHdr+1);
        SecThis=SecHdr+secindex;
       
        //Test ..测试原来的各区段数据和新的区段数据是否相同
        AddLine("Old Sec Info..");
        s="";
        for(i=0;i<NtHdr->FileHeader.NumberOfSections;i++)
        { s.Format("%d:",i);
        char c[20];BYTE *psecdata=buf+SecHdr[i].PointerToRawData;
        for(int j=0;j<16;j++)
        {sprintf(c,"%.2X ",psecdata[j]);s+=c;}
        AddLine(s);
        }
        //change all sechdr
        //copy mem 复制数据
        for(i=len-1;i>=SecThis->PointerToRawData;i--)
                buf[i+Align(rsizeadd,NtHdr->OptionalHeader.FileAlignment)]=
                buf[i];
        //memcpy(SecThis->PointerToRawData+buf+rsizeadd,
        // SecThis->PointerToRawData+buf,len-SecThis->PointerToRawData);
        s.Format("copying len-ROffset=%d-%d=%d bytes ",len,
                SecThis->PointerToRawData,len-SecThis->PointerToRawData);
        AddLine(s);
        //修改当前段信息
        SecThis->SizeOfRawData+=Align(rsizeadd,NtHdr->OptionalHeader.FileAlignment);
        SecThis->Misc.VirtualSize+=vsizeadd;
        //修改后面的区段信息
        for(i=secindex;i<NtHdr->FileHeader.NumberOfSections;i++)
        {
                SecHdr[i].PointerToRawData+=rsizeadd;
                //SecHdr[i].Characteristics|=IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
        }
        //修改NtHdr信息 NtHdr->OptionalHeader.SizeOfImage+=Align(rsizeadd,NtHdr->OptionalHeader.SectionAlignment);
        NtHdr->OptionalHeader.SizeOfCode+=Align(rsizeadd,NtHdr->OptionalHeader.SectionAlignment);
       
        //Test ..测试原来的各区段数据和新的区段数据是否相同
        AddLine("New Sec Info..");
        s="";
        for(i=0;i<NtHdr->FileHeader.NumberOfSections;i++)
        { s.Format("%d:",i);
        char c[20];BYTE *psecdata=buf+SecHdr[i].PointerToRawData;
        for(int j=0;j<16;j++)
        {sprintf(c,"%.2X ",psecdata[j]);s+=c;}
        AddLine(s);
        }
       
        if(!f.Open(szf2,CFile::modeCreate|CFile::modeWrite))
        {
                AddLine("open for w error");return;
        }
        f.WriteHuge(buf,len+Align(rsizeadd,NtHdr->OptionalHeader.FileAlignment));///写入文件
        f.Close();
        s.Format("Write to file %s ok.",szf2);
        AddLine(s);
        delete []buf;
}

//试验Load一个程序并运行之,有问题,望指教
void CAddCode_MFCDlg::OnBtnRunApp()
{
        // TODO: Add your control notification handler code here
        CString s;
        LPBYTE p=(LPBYTE)::LoadLibrary("notepad.exe");//装入程序
        int i;
       
        AddLine("---------starting----------------");
        if(!p){
                AddLine("OPen file error.");return;
        }
        AddLine("open file ok.");
       
        PIMAGE_DOS_HEADER DosHdr=(PIMAGE_DOS_HEADER)p;//检查格式,其实没必要
        if(DosHdr->e_magic!=*(WORD*)"MZ\0\0")
        {
                AddLine("dossig error");return;
        }
       
        PIMAGE_NT_HEADERS NtHdr=(PIMAGE_NT_HEADERS)(p+DosHdr->e_lfanew);
        if(NtHdr->Signature!=*(DWORD*)"PE\0\0\0\0")
        {
                AddLine("pesig error");return;
        }
        AddLine("Checking file format ...ok");
       
        DWORD OEP=NtHdr->OptionalHeader.AddressOfEntryPoint+(DWORD)p;//找到OEP
        s.Format("OEP=%X,Base=%X",OEP,NtHdr->OptionalHeader.ImageBase);
        AddLine(s);
       
        LPBYTE pcode=(LPBYTE)OEP;
        s="";
        for(i=0;i<20;i++)
        {
                char c[10];sprintf(c,"%.2X ",pcode[i]);
                s+=c;
        }
        AddLine(s);
       
        LPBYTE p2=(LPBYTE)::VirtualAlloc(0,NtHdr->OptionalHeader.SizeOfImage,MEM_COMMIT,PAGE_READWRITE);//分配内存
        memcpy(p2,p,NtHdr->OptionalHeader.SizeOfImage);//复制数据
        pcode+=p2-p;
        s="";
        for(i=0;i<20;i++)
        {
                char c[10];sprintf(c,"%.2X ",pcode[i]);
                s+=c;
        }
        AddLine(s);
       
        DWORD OEP2=(DWORD)(OEP+p2-p);//新的OEP
        //return;
        _asm{//跳转到OEP,执行时出错,望指教
                mov eax,OEP2;
                jmp eax;
        }
}

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
注意:我想不用用系统提供的api实现loader.
最终目标是想实现自主装载程序(不用loadlibrary),
并运行之(可以在自己的进程空间中,而不是建立新的进程空间)
2005-6-18 09:56
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
怎么没人说话???
2005-6-18 14:26
0
雪    币: 229
活跃值: (168)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
这个问题复杂,没人敢说,我也不敢!
2005-6-30 08:42
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
5
你的思路好像有问题。exe的loader好像没这么简单。别人有现成的代码,你找找
2005-6-30 08:59
0
雪    币: 1223
活跃值: (469)
能力值: (RANK:460 )
在线值:
发帖
回帖
粉丝
6
思路不对

你可以参考一下这个讨论帖:
http://bbs.pediy.com/showthread.php?s=&threadid=9417
2005-6-30 09:51
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
7
没看到你处理Relocations
直接VirtualAlloc得到的页面跟原来的RVA不符合自然出错
2005-7-1 00:54
0
游客
登录 | 注册 方可回帖
返回