最近学习了壳,自己手动编写了简单的壳,功能比较简单,现在简单整理成笔记,供大家参考。个人能力有限,如有谬误,请不吝赐教,万分感谢。
参考资料:《黑客免杀攻防》,看雪论坛等
简介
“壳”是一种现实比较常见的东西,比如:花生壳、瓜子壳等等。这些壳主要是用来保护其自身的果实的,要想吃到这些果实,我们就需要将其剥掉。在我们的软件行业也存在这样类似的东西,这种东西我们也称之为“壳”,我们自身的软件就类似于花生仁,而“壳”用来保护我们自身的软件,避免被其他人窥探。
壳根据作用,一般分为两种:压缩壳、加密壳。无论哪种他们的原理大致是相同的。我们给自身软件加壳后就会产生新的软件,新的软件是由壳和原软件组成,在执行的时候,先执行壳,由壳对原程序进行解密并还原到内存中去,接着执行原来的程序。如下图:
当我们将带壳的程序运行后,壳就会加载自己的API函数,然后对已知的加密区进行解密,对压缩进行解压,并按照PE结构将其释放到正确的内存位置上,并进行重定位,然后跳转到原程序的入口点(OEP),运行原程序。如图:
搭建环境
开发环境
Win7x64 旗舰版
vs2013
010Edit6.03
OD1.1(吾爱破解版)
PEid0.94
LordPE
说明:
我们想程序的界面与逻辑进行分开,这样可以使两者互不干扰。
创建三个项目
a、创建一个名称为PackBase的mfc项目,用于界面操作
b、创建一个名称为Pack_Base的dll项目,编写加壳逻辑
c、创建一个名称为Stub的dll项目,编写壳的信息
a、创建一个名称为Pack Base的mfc项目
界面如下:
先给EditControl的"Read Only"属性设置为"True",并为其定义两个变量,一个是CString类型的m_pathStr,一个是CEditor类型的m_pathEdit。
然后实现拖拽效果,将该对话框中的Accept Files属性设置为True,然后按Ctrl + Shift +X,添加 WM_DROPFILES消息。
在OnDropFiles中添加如下代码:
void CPackBaseDlg::OnDropFiles(HDROP hDropInfo) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CDialogEx::OnDropFiles(hDropInfo); CDialogEx::OnDropFiles(hDropInfo); //拖动单个文件的时候 WCHAR wcStr[MAX_PATH]; DragQueryFile(hDropInfo, 0, wcStr, MAX_PATH);//获得拖曳的文件的文件名 m_pathEdit.SetWindowText(wcStr); //将路基添加到文本编辑框中 DragFinish(hDropInfo); //拖放结束后,释放内存 UpdateData(TRUE); //将界面上的信息保存到变量中 MessageBox(m_pathStr, m_pathStr, 0); //测试是否成功 }
再次给“浏览”按钮事件处理添加浏览文件并获取文件路径代码,如下:
void CPackBaseDlg::OnBnClickedButton1() { UpdateData(TRUE); //设置要浏览文件的类型 static TCHAR BASED_CODE szFilter[] = _T("可执行文件 (*.exe)|*.exe|") _T("DLL文件 (*.dll)|*.dll|") _T("All Files (*.*)|*.*||"); CFileDialog fileDlg(TRUE, _T("exe"), _T(""), OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, szFilter); if (fileDlg.DoModal() == IDOK) { //将获取的路径信息赋给变量 m_pathStr = fileDlg.GetPathName(); } //更新控件显示信息 UpdateData(FALSE); }
在“加壳”按钮的添加如下代码用于测试:
void CPackBaseDlg::OnBnClickedButton2() { MessageBox(m_pathStr, m_pathStr, 0); }
运行程序测试成功,如图:
b、创建一个名称为Pack_Dll的加壳dll程序
在该工程中的Pack_Dll.h文件中定义一个导出方法Pack用于加壳操作。由于c++存在“名称粉碎机制”,所以要使用 extend "C" 不让改方法“名称粉碎”。如下:
extern "C" PACK_DLL_API BOOL Pack(CString strPath);
我们需要导入CString的头文件,我们为了后面的操作方便,我们将#include <afxwin.h>加入到stdafx.h文件中,由于冲突所以需要去掉文件中"#include <windows.h>"。
在Pack_Dll.cpp文件中对Pack方法进行实现,我们只需要简单的测试下即可。
BOOL Pack(CString strPath) { MessageBox(0, L"Pack", 0, 0); return TRUE; }
为了项目能够正常编译,我们需要去掉用dllmain.cpp文件中的DllMain方法,同时将该项目的“运行库”设置为“多线程调试(/MTD)”,如下图:
接下来实现界面工程和dll的关联,我们在MFC工程的加壳方法中调用刚刚写的Pack方法,修改代码如下:
#include "../Pack_Dll/Pack_Dll.h" #pragma comment(lib,"../Debug/Pack_Dll.lib") void CPackBaseDlg::OnBnClickedButton2() { //MessageBox(m_pathStr, m_pathStr, 0); Pack(m_pathStr); }
通过项目依赖项让两个项目关联,在Pack Base项目上点击右键的“生成依赖项”中“项目依赖项”,在“依赖项”的“依赖于”中选择“Pack_Dll”即可,如下图:
编译运行Pack Base项目,效果如下:
c、创建名称为Stub的dll的项目
在Stub.h的文件中,编写两个按C语言的进行编译的函数fnGetStub和fnSetStub,代码如下:
extern "C" { //获取和设置Stub STUB_API int fnGetStub(void); STUB_API void fnSetStub(int n); } 在Stub.cpp文件中对其进行实现: // 这是导出函数示例。 STUB_API int fnGetStub(void) { return nStub; } STUB_API void fnSetStub(int n) { nStub = n; }
将项目Pack_dll项目和Stub关联起来,在Pack_dll项目上击右键的“生成依赖项”中“项目依赖项”,在“依赖项”的“依赖于”中选择“Stub”即可,此时项目就会形成了:Pack项目依赖于Pack_dll项目,而Pack_dll项目依赖于Stub项目。如下图:
修改Pack_dll项目中的Pack方法,在Pack_dll项目中调用Stub项目中导出的方法,代码如下:
typedef int(*FUNGetStub)(void); typedef void(*FUNSetStub)(int n); BOOL Pack(CString strPath) { HMODULE hMod = LoadLibrary(L"Stub.dll"); FUNSetStub pfnSetStub = (FUNSetStub)GetProcAddress(hMod, "fnSetStub"); pfnSetStub(1); FUNGetStub pfnGetStub = (FUNGetStub)GetProcAddress(hMod, "fnGetStub"); if (pfnGetStub()) { MessageBox(0,L"加壳成功",0,0); } return TRUE; }
此时项目就会形成了:Pack项目依赖于Pack_dll项目,而Pack_dll项目依赖于Stub项目。
运行项目Pack,运行成功如下图,证明我们项目的基础框架调通,我们接下来就可以去编写壳了。
d、修改编译配置
我们将生成的Debug版本的stub.dll加载到LordPE中,发现区段表中的第一个区段为.textbss,如果是这样的话就会影响我们的操作
为了达到第一个区段为.text,我们需要将想Stub设置为Release版本。(选项配置管理器)
然后,我们在使用LoadPE,查看Release版本Stub.dll的区段信息。
为了后面调试方便,我们要将Stub项目的输出目录设置为Debug,这样就会让Stub.dll为Release版本,但是输出到Debug目录中。
参考项目代码: 01Pack Base http://download.csdn.net/detail/obuyiseng/9386931
————————————————
版权声明:本文为CSDN博主「布衣僧」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/oBuYiSeng/article/details/50447540