最近学习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日开班!