使用VC自己动手编写加壳程序Word文件下载.docx
《使用VC自己动手编写加壳程序Word文件下载.docx》由会员分享,可在线阅读,更多相关《使用VC自己动手编写加壳程序Word文件下载.docx(34页珍藏版)》请在冰点文库上搜索。
控件类型ID值标题
组框请选择文件IDC_STATIC
组框文件处理信息IDC_STATIC
按钮选择文件IDC_BUTTON_OPENFILE
按钮开始加壳IDC_BUTTON_PACKING
按钮关于本程序IDC_BUTTON_ABOUT
编辑框无IDC_EDIT_FILEPATHNAME
Rich编辑框无IDC_RICHEDIT_PROCINFO
对话框IDD_PEPACKER_DIALOGPEPackerV1.0
设置好的界面如下图所示:
现在按F7编译,CTRL+F5运行一下,发现程序好没有动静。
什么反应也没有,如果
把RichEdit删除掉,再编译,再运行就可以。
这个问题是由于RichEidt没有初始化引起的,微软的说法是要在APP的初始化函数中
加入初始化函数:
AfxInitRichEdit()。
那我们现在加入。
在classview视图中,展开CPEPackerApp类,双击InitInstance()函数,在
AfxEnableControlContainer();
后面添加代码AfxInitRichEdit();
,添加后的函数代码如下:
BOOLCPEPackerApp:
:
InitInstance()
{
AfxInitRichEdit();
//Standardinitialization
//Ifyouarenotusingthesefeaturesandwishtoreducethesize
//ofyourfinalexecutable,youshouldremovefromthefollowing
//thespecificinitializationroutinesyoudonotneed.
此时再F7编译,CTRL+F5运行,就可以看到程序正常运行了。
再修改一下对话框的属性,右键,选择“属性”后,在“样式”标签中,勾选上“最小化框
[N]”,这样对话框就可以最小化了。
当然你还可以选择其它属性。
现在来添加成员变量。
在编辑框上点击右键,选择“建立类向导……”,打开类向导对话框,然后选择“MemberVariables”标签。
注意Project:
里面是否是PEPacker,Classname:
里面是否是CPEPackerDlg,然后在ControlIDs:
里面找到IDC_EDIT_FILEPATHNAME,双击。
或者点击右边的“AddVarible...”按钮,在“AddMemberVarible”对话框中添加成员变量。
变量名为"
m_FilePathName”,Category选择"
Value”,变量类型选择"
CString”,然后确定。
用同样的方法给控件IDC_RICHEDIT_PROCINFO添加成员变量。
变量名为m_RichEditProcInfo,注意category选择Control,变量类型为CRichEditCtrl。
最后确定。
双击“选择文件”按钮,弹出添加程序函数对话框,函数名你为:
OnButtonOpenfile,我们确定即可,使用默认的,当然也可以修改。
此时来到了PEPackerDlg.cpp文件中,界面默认的位置是刚刚添加的函数编辑处。
代码如下:
voidCPEPackerDlg:
OnButtonOpenfile(){
//TODO:
Addyourcontrolnotificationhandlercodehere
}
此时在此函数中添加如下代码:
代码我会作注释。
//设置文件过滤,默认打开哪些文件类型,最后“||”结束。
charszFilter[]="
可执行文件(*.exe)|*.exe|全部文件(*.*)|*.*||"
;
//通过查阅MSDN,了解CFileDialog中构造函数的用法。
//第一个参数为TRUE,表示打开文件对话框;
为FALSE,表示保存对话框。
//其他详细参数说明见后面。
CFileDialog
dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,szFilter,
NULL);
//通过模态对话框显示文件对话框
if(dlg.DoModal()==IDOK)
//获取文件路径
m_FilePathName=dlg.GetPathName();
//设置RICHEDIT内容
//将指针设置到编辑框最后
m_RichEditProcInfo.SetSel(-1,-1);
//替换编辑框最后的内容,实际上就是在最后添加内容。
m_RichEditProcInfo.ReplaceSel("
文件路径:
"
);
m_RichEditProcInfo.ReplaceSel(m_FilePathName);
//用获取的文件路径更新编辑框内容。
UpdateData(FALSE);
添加完成后,本次功能结束。
编译运行即可,运行界面如下:
其中CFileDialog类的详细说明如下:
CFileDialog文件选择对话框的使用:
首先构造一个对象并提供相应的参数,构造函数原型如下:
CFileDialog:
CFileDialog(BOOLbOpenFileDialog,LPCTSTRlpszDefExt=NULL,
LPCTSTRlpszFileName=NULL,DWORDdwFlags=OFN_HIDEREADONLY|O
FN_OVERWRITEPROMPT,LPCTSTRlpszFilter=NULL,CWnd*pParentWnd=N
ULL);
参数意义如下:
bOpenFileDialog为TRUE则显示打开对话框,为FALSE则显示保存对话文件对话框。
lpszDefExt指定默认的文件扩展名。
lpszFileName指定默认的文件名。
dwFlags指明一些特定风格。
lpszFilter是最重要的一个参数,它指明可供选择的文件类型和相应的扩展名。
参数格式如:
ChartFiles(*.xlc)|*.xlc|WorksheetFiles(*.xls)|*.xls|DataFiles(*.xlc;
*.xls)|
*.xlc;
*.xls|AllFiles(*.*)|*.*||"
文件类型说明和扩展名间用|分隔,同种类型文件的扩展名间可以用;
分割,每种文件类型间用|分隔,末尾用||指明。
pParentWnd为父窗口指针。
创建文件对话框可以使用DoModal(),在返回后可以利用下面的函数得到用户选择:
CStringCFileDialog:
GetPathName()得到完整的文件名,包括目录名和扩展名如:
c:
estest1.txt
CStringCFileDialog:
GetFileName()得到完整的文件名,包括扩展名如:
test1.txtCStringCFileDialog:
GetExtName()得到完整的文件扩展名,如:
txtCStringCFileDialog:
GetFileTitle()得到完整的文件名,不包括目录名和扩展名如:
test1
POSITIONCFileDialog:
GetStartPosition()对于选择了多个文件的情况得到第一个文件位置。
GetNextPathName(POSITION&
pos)对于选择了多个文件的情况得到下一个文件位置,并同时返回当前文件名。
但必须已经调用过POSITIONCFileDialog:
GetStartPosition()来得到最初的POSITION变量。
(2)使用内存映射生成文件
打开文件,使用内存映射生成文件。
本次要完成的任务是:
点击“开始加壳”按钮,生成加壳后的文件,当然这是假想加过壳,并没有加壳。
实际上就是将文件改名,复制成另外一个文件,但又不同于复制。
因为是先将文件创建内存映射,然后再通过映射指针写回文件。
本次的界面效果:
首先添加几个和文件名相关的成员变量。
在classview中,双击PEPackerDlg函数,在类的定义中申明成员变量:
public:
CStringm_FilePathNamePacked;
//加壳后的文件名
下面来添加“开始加壳”按钮的函数。
在“开始加壳”按钮上双击,将出现新建函数的提示,确定即可。
也可以点击工具栏上的“查看”菜单,选择“建立类向导”,选中“MessageMaps”标签。
Project:
设置为PEPacker,Classname:
设置为CPEPackerDlg,ObjectIDs选中IDC_BUTTON_PACKING,Messages:
选中BN_CLICKED,然后点击右边的“AddFunction...”按钮,添加函数“OnButtonPacking”即可。
空的函数为:
OnButtonPacking(){
现在在该函数中添加内容。
代码部分我都做了注释,所以我就不多说了。
HANDLEhFile;
//文件句柄
HANDLEhMapping;
//文件映射句柄
LPVOIDlpHeadBase;
//创建映射的头指针
DWORDdwFileSize;
//文件大小
DWORDdwBufferRead;
//实际读取字节
//打开文件
hFile=CreateFile(m_FilePathName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
//如果文件打开失败,就弹出对话框,并返回。
if(hFile==INVALID_HANDLE_VALUE)
MessageBox("
打开文件失败~"
"
错误提示"
MB_OK);
return;
//获取文件大小
dwFileSize=GetFileSize(hFile,NULL);
//设定加壳后的文件名,我采取了一个偷懒的简单方法。
//如果要严格做,需要获取文件路径,扩展名等等。
m_FilePathNamePacked=m_FilePathName.Left(m_FilePathName.GetLength()
-4)+"
_packed.exe"
//创建文件映射。
如果对文件映射不了解,请自行查阅相关资料。
hMapping=CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
//如果创建映射失败,弹出对话框,并关闭文件句柄,然后返回。
if(hMapping==NULL)
创建文件映射失败~"
CloseHandle(hFile);
//关闭创建的文件句柄
//将文件映射对象映射到当前应用程序的地址空间中
lpHeadBase=MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0);
if(lpHeadBase==NULL)
文件映射地址失败~"
CloseHandle(hMapping);
//关闭映射句柄
//关闭文件句柄
//创建加壳后的文件句柄
hFile=CreateFile(m_FilePathNamePacked,GENERIC_READ|GENERIC_WRITE,F
ILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
生成文件失败~"
错误提示~"
//写入文件
if(!
WriteFile(hFile,lpHeadBase,dwFileSize,&
dwBufferRead,NULL))
写入文件失败~"
//卸载文件映射,关闭文件句柄
UnmapViewOfFile(lpHeadBase);
//在编辑框中显示信息
文件加壳完成~\r\n"
创建文件成功~"
成功提示"
针对于上次还要修改的地方:
打开对话框资源,修改RichEdit的属性,勾选“多行”和“自动垂直滚动”,去掉“自动水平滚动”。
在OnButtonOpenfile()函数中,在代码
的后面添加:
\r\n"
(3)检测文件格式
检测文件格式(是否为PE格式的EXE文件)
本次的主要内容为检测文件是否为PE格式,且是否为EXE文件。
DLL等文件也是PE格式,但其加壳的一些数据处理方式不一样,最明显的一个差别就是DLL文件需要重定位。
本系统现在暂时只处理EXE可执行文件。
截图效果:
(在RichEdit中多了个文件格式提示)
首先添加一个成员函数:
IsPe,用来判断文件格式。
如果满足就返回TRUE,否则返回FALSE。
在classview视图中,找到CPEPackerDlg类,在其上面点击右键,选择“AddmemberFunction...”,函数类型为BOOL,函数描述为IsPE(HANDLEhFile),Access为public,然后确定,编辑此函数。
//检测文件是否是PE可执行文件格式
BOOLCPEPackerDlg:
IsPE(HANDLEhFile){
WORDwTemp;
//暂存读取的字节
//实际读取的字节数
DWORDdwOffset;
//PE头偏移位置
DWORDdwOEP;
//程序OEP
//读取MZ标志
SetFilePointer(hFile,0,NULL,FILE_BEGIN);
ReadFile(hFile,&
wTemp,2,&
dwBufferRead,NULL);
//因为二进制目标文件反着顺序存储,所以要反过来判断。
if(wTemp!
='
ZM'
)
returnFALSE;
//读取PE头位置
SetFilePointer(hFile,0x3C,NULL,FILE_BEGIN);
dwOffset,4,&
//读取PE头信息
SetFilePointer(hFile,dwOffset,NULL,FILE_BEGIN);
//判断是否为PE,同样要反着判断。
EP'
//获取文件OEP
SetFilePointer(hFile,dwOffset+0x28,NULL,FILE_BEGIN);
dwOEP,4,&
//如果OEP为0。
dwOEP)
//获取文件特征,判断是exe还是dll文件。
SetFilePointer(hFile,dwOffset+0x16,NULL,FILE_BEGIN);
if(wTemp&
0x2000!
=0)
returnTRUE;
最后在OnButtonPacking函数中,运用此函数。
将此函数添加在打开文件CreateFile和创建映射之间。
如果文件格式正确,就创建映射;
否则,就返回。
添加后的代码为:
…………………………
/////////////////第三次加的内容/////////////////////////////////////////////
//判断文件格式
IsPE(hFile))
错误提示:
文件不是PE格式~\r\n"
文件不是PE可执行文件"
//////////////////////////////////////////////////////////////////////////
……………………………………
(3)通过分配虚拟内存生成文件
给文件分配虚拟内存并载入内存,然后输出加壳后文件。
将PE文件载入内存后再操作有三种方法。
第一是通过文件映射的基址,其内容在第二节中已经应用并实现。
第二是获取获取文件大小,然后分配相应大小的内存。
第三是模拟PE文件的加载机制,根据PE文件的镜像大小分配相应大小的内存,然后将相应的区块载入到对应的虚拟地址空间中。
本次内容将使用第三种方式加载文件到内存。
由于PE文件在运行时,对文件中数据的读取都是通过RVA(相对虚拟地址)进行的,如果采用第一种或者第二种方式加载到内存,那么当读取数据的时候,还需要将RVA转换成Offset(文件偏移),这种转换虽然说不麻烦,但如果需要转换的地方较多,有时也会出错,所以本系统的加壳也将采用第二种方式加入到内存。
载入内存用先通过VirtualAlloc函数分配虚拟内存空间,然后通过ReadFile读入到内存。
根据PE文件的加载机制,PE文件会按照区段进行载入,每个区段的虚拟地址在区段表中都有说明。
最后的效果图。
首先添加两个成员函数:
MemAlloc和MemAllocFree,在classview视图中的CPEPackerDlg类上点击右键,选择“addmemberfunction...”。
函数类型和说明分别如下:
BOOLMemAlloc(HANDLEhFile);
//分配内存
voidMemAllocFree();
//释放内存
然后再添加几个成员变量,在classview视图中的CPEPackerDlg类上点击右键,选择“addmember