最新文章
热门文章
新华字典词典2009注册码序列号破 
使用VC自己动手编写加壳程序(1)— 
黑鹰VIP破解视频教程(好东西) 
使用VC自己动手编写加壳程序(3)— 
使用VC自己动手编写加壳程序(5)— 
使用VC自己动手编写加壳程序(6)— 
使用VC自己动手编写加壳程序(4)— 
使用VC自己动手编写加壳程序(2)— 
天草破解班视频教程 初级中级高级 
ASPack 2.001 -> Alexey Solodov 
当前位置:李露的博客 >> 黑客学堂 >> 浏览文章
使用VC自己动手编写加壳程序(5)——给程序添加一个区段
更新日期:2009年04月01日  来源:本站原创  作者:天漏客   访问次数:次  【字体:

文章标题:使用VC自己动手编写加壳程序(5)——打造自己的壳
主要内容:添加一个新的文件区段,用来存放壳代码,并用8来填充区段。
基本要求:了解VC++6.0基本使用方法;了解PE格式,不熟悉的地方能够通过查阅资料弄懂;
阅读对象:想写壳的新手。高手掠过,本文仅限于写壳入门。
文章类型:原创
文章作者:天漏客 QQ:285252760
完成日期:2009年04月1日
作者主页:www.lilu.name
文章地址:www.lilu.name/Html/heikexuetang/2009-4/3349370008.html
文章说明:允许转载,但最好注明转载出处。

本次内容将添加一个新的区段到原PE文件中,一般加壳程序都会添加一个新的区段用来存放壳代码(这只是一般情况)。然后修改添加区段后的文件的入口点,让程序从添加的壳代码段开始运行。本次内容只添加区段,不修改程序入口点。

添加区段的主要有三个步骤。第一,是修改PE文件头信息。增加一个区段后,要修改NT头中的区段表个数成员,修改可选头的文件镜像大小成员。第二,获取要添加的区段的存放位置和大小,包括文件偏移位置和大小、文件相对虚拟地址和虚拟大小第三,就是将文件写入到文件末尾。

本次源代码:使用VC自己动手编写加壳程序(5)——给程序添加一个区段 [点击浏览该文件:PEPacker(5).rar]

添加区段后的区段表对比图如下:

使用VC自己动手编写加壳程序(5)——给程序添加一个区段

首先添加三个成员函数,如下:

 BOOL MakePacking(HANDLE hFile);  //生成加壳后的文件
 void MakeShell(HANDLE hFile);  //生成壳代码段
 void EditHeader();  //修改文件头信息

 再添加两个成员变量,public型。

 LPVOID lpVirtualShell;   //壳虚拟内存指针
 DWORD SizeOfShell; //壳代码的的大小
 DWORD SizeOfImage;  //文件镜像大小

MakeShell函数功能是生成壳代码数据,先暂时用0填充该数据段。其功能代码如下:

//生成壳代码段
void CPEPackerDlg::MakeShell(HANDLE hFile)
{
 //壳代码段中暂定为用8填充
 SizeOfShell=0x100; //大小暂时定为256字节
 lpVirtualShell=VirtualAlloc(NULL,SizeOfShell,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE);
 memset(lpVirtualShell,8,SizeOfShell);

}

修改PE头,主要是修改区段表个数和镜像大小。

//修改PE文件头信息,主要是区块个数和镜像大小
void CPEPackerDlg::EditHeader()
{
 DWORD dwNumOfSections; //区块个数
 DWORD dwFileAlign; //文件粒度(文件对齐大小)
 DWORD dwSectionAlign; //块粒度(内存对齐大小)
 DWORD dwAlignLastSection; //最后一个区段按内存对齐后的大小
 LPVOID lpShellSecTab;  //壳区段表指针
 IMAGE_SECTION_HEADER SectionHeaderOfShell; //壳代码段的区块表信息
 
 ///////以下为修改区段表信息功能,主要是增加壳区段表////////////////////////
 //初始化区段表结构
 memset(&SectionHeaderOfShell,0,sizeof(SectionHeaderOfShell));
 //获取对齐大小数据
 dwFileAlign=pOptionalHeader->FileAlignment;
 dwSectionAlign=pOptionalHeader->SectionAlignment;
 //获取区块表个数
 dwNumOfSections=pNtHeader->FileHeader.NumberOfSections;
 //设定壳的区块表信息
 SectionHeaderOfShell.Misc.PhysicalAddress=SizeOfShell; //原始大小
 //在文件中对齐后的大小,除以文件粒度,如果余数为零,就直接使用;否则,就扩充对齐。
 SectionHeaderOfShell.SizeOfRawData=(SizeOfShell%dwFileAlign)?(dwFileAlign*(SizeOfShell/dwFileAlign+1)):SizeOfShell; 
 //区块特征
 SectionHeaderOfShell.Characteristics=IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
 memcpy(&SectionHeaderOfShell.Name,".bugsky",7);  //区块名称
 SectionHeaderOfShell.PointerToRelocations=0; //重定位偏移
 SectionHeaderOfShell.NumberOfRelocations=0;  //重定位表数目
 SectionHeaderOfShell.PointerToLinenumbers=0; //行号表偏移
 SectionHeaderOfShell.NumberOfLinenumbers=0;  //行号表中行号数目
 
 
 //对齐最后一个区段后的块大小,来计算壳区段的虚拟地址。
 if ((pSectionHeader+dwNumOfSections-1)->SizeOfRawData % dwSectionAlign)
 {
  dwAlignLastSection=dwSectionAlign*((pSectionHeader+dwNumOfSections-1)->SizeOfRawData / dwSectionAlign+1);
 }
 else
 {
  dwAlignLastSection=(pSectionHeader+dwNumOfSections-1)->SizeOfRawData;
 }
 //获取最后一个区段的相对虚拟地址和虚拟大小
 SectionHeaderOfShell.VirtualAddress=(pSectionHeader+dwNumOfSections-1)->VirtualAddress+dwAlignLastSection;
 SectionHeaderOfShell.PointerToRawData=(pSectionHeader+dwNumOfSections-1)->PointerToRawData+(pSectionHeader+dwNumOfSections-1)->SizeOfRawData;
 
 //计算壳区段表在PE头中的位置
 lpShellSecTab=(LPVOID)((DWORD)pSectionHeader+sizeof(IMAGE_SECTION_HEADER)*dwNumOfSections);
 //将壳区段信息拷贝到文件头中
 //此方法并不严密,因为没有考虑到PE文件头中是否还有多余的空间,为简化,暂如此操作。
 memcpy(lpShellSecTab,&SectionHeaderOfShell,sizeof(SectionHeaderOfShell));
 
 //////////区段表修改完毕,下面修改PE头/////////////////////////////////////////////
 //区段表个数加1。
 pNtHeader->FileHeader.NumberOfSections++;
 //文件镜像增加
 pOptionalHeader->SizeOfImage=SizeOfImage+((SizeOfShell % dwSectionAlign)?(dwSectionAlign*(SizeOfShell/dwSectionAlign+1)):SizeOfShell);
 

MakePacking函数功能是将各个内存数据输出,合并为加壳后的文件。其代码如下:

//生成加壳后的文件
BOOL CPEPackerDlg::MakePacking(HANDLE hFile)
{
  DWORD dwBufferRead;  //实际读取字节大小
 DWORD dwNumOfSection; //区段的个数

 dwNumOfSection=pNtHeader->FileHeader.NumberOfSections;
 //写入原始文件
 if (!WriteFile(hFile,lpVirtualtAlloc,SizeOfImage,&dwBufferRead,NULL))
 {
  return FALSE;
 }

 //写入壳代码段文件
 if (!WriteFile(hFile,lpVirtualShell,(pSectionHeader+dwNumOfSection-1)->SizeOfRawData,&dwBufferRead,NULL))
 {
  return FALSE;
 }
 return TRUE;

}

修改OnButtonPacking函数,增加函数调用。OnButtonPacking代码如下: 

void CPEPackerDlg::OnButtonPacking()
{
  // TODO: Add your control notification handler code here

 HANDLE hFile; //文件句柄

 //打开文件
 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;
 }
 /////////////////第三次加的内容/////////////////////////////////////////////
 //判断文件格式
 if (!IsPE(hFile))
 {
  m_RichEditProcInfo.ReplaceSel("错误提示:文件不是PE格式!\r\n");
  MessageBox("文件不是PE可执行文件","错误提示!",MB_OK);
  return;
 }
 //////////////////////////////////////////////////////////////////////////
 //////////第四次内容。分配内存,并载入内存////////////////////////////////////////////
 if (!MemAlloc(hFile))
 {
  m_RichEditProcInfo.ReplaceSel("错误提示:文件加载到内存失败!\r\n");
  MessageBox("文件加载到内存失败!","错误提示!",MB_OK);
  return;
 }
 //设定加壳后的文件名,我采取了一个偷懒的简单方法。
 //如果要严格做,需要获取文件路径,扩展名等等。
 m_FilePathNamePacked=m_FilePathName.Left(m_FilePathName.GetLength()-4)+"_packed.exe";
 CloseHandle(hFile);


 //创建加壳后的文件句柄
 hFile=CreateFile(m_FilePathNamePacked,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
  NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
 if (hFile==INVALID_HANDLE_VALUE)
 {
  MessageBox("创建加壳后文件失败!","错误提示!",MB_OK);
  return;
 }

 ////////第五次增加////////////////////////////////////////////////
 //生成壳代码段
 MakeShell(hFile);
 //修改PE文件头
 EditHeader();
 //输出加壳后的文件
 if (!MakePacking(hFile))
 {
  MessageBox("生成文件时失败!","错误提示!",MB_OK);
  return;
 }

 //关闭文件句柄
 CloseHandle(hFile);
 //文件写入完毕后,释放内存
 MemAllocFree();
 //在编辑框中显示信息
 m_RichEditProcInfo.ReplaceSel("文件加壳完成!\r\n");
 
 MessageBox("创建文件成功!","成功提示",MB_OK);

}

修改MemAllocFree函数,增加对壳内存释放功能。

void CPEPackerDlg::MemAllocFree()
{
 //释放分配的虚拟内存
 VirtualFree(lpVirtualtAlloc,0,MEM_DECOMMIT|MEM_RELEASE);
 //释放壳代码段的虚拟内存
 VirtualFree(lpVirtualShell,0,MEM_DECOMMIT|MEM_RELEASE);
}

至此,整个功能完毕!

使用Windows XP系统自带的记事本程序——notepad.exe进行加壳测试。下图是添加区段后两个记事本程序的PE文件头对比图。

使用VC自己动手编写加壳程序(5)——给程序添加一个区段

可以看到,区段个数由6个变成了7个。文件镜像大小有0000DC00变成了0000F000。其它的都一样。

以下是用hex_workshop打开的添加区段后的文件,在最后一个区段的位置时的数据图。

使用VC自己动手编写加壳程序(5)——给程序添加一个区段

从图中可以看出,从DC00开始,数据都是有8组成,说明添加数据成功。

加壳前后的区段表对比图最开始已经放出来了。加壳后的文件多了一个区段“.bugsky”,该区段的偏移和地址都是紧靠文件的最后。

运行加壳后的记事本程序,也成功!

发表评论】【告诉好友】【打印此文】【收藏此文】【关闭窗口
上一篇:使用VC自己动手编写加壳程序(4)——通过分配虚拟内存生成文件 下一篇:使用VC自己动手编写加壳程序(6)——在壳代码中添加MessageBox并运行

Copyright 2006-2012 Powered by LiLu.NAME,李露的博客 All Rights Reserved.
E-Mail:lilu.name#gamil.com(注意是gmail,自己改) QQ:285252760
苏ICP备08016526号