一个简单的二进制加密壳
本帖最后由 madder 于 2019-4-17 12:47 编辑文章开头致敬下海哥,估计很多人也看过滴水三期,这里给那些没看过的人提供一些加密的思路。
套用海哥一句话,二进制加密这个东西,拼的就是对PE文件的理解。
首先先说一下思路,前面一段是进行加壳的程序做的事情,后面的是壳子做的事情。
1.读取要进行加密的PE文件,然后加密,我没用什么高端的加密方式,就是简单的异或。这里可以随便找个数,我用0x12345678这个举例,所以0x12345678也称作密钥。
2.读取壳子文件到内存里,将加密后的数据,写入到壳子文件里面。具体操作是给壳子文件增加一个节(有的人喜欢叫区段),然后把加密后的数据写到这个这个区段里面,最后,最重要的是一定要修改OPheader(可选PE头)里面的SizeOfimage和PEheader里面的SizeOfSection.
增加节的方法还有一些细节后续会补充补充。
3.将填充后的壳子文件写成一个新的文件,这样一个带壳的程序就搞定了 。
现在是壳子要做的事情,上面加密,写入文件都比较简单,壳子要做的就稍微有点复杂,而且稍微哪里写错,调试的时候特别麻烦,我都是OD加VS自带的调试器结合起来看。废话不多说
1.在写壳子的时候,心里要把这个壳子当作一个已经加完壳的程序。不知道这么说会不会懂。。。
2.首先,读取自己进程里面的所有数据,这些数据只是指PE文件里的那些,别把系统的dll读了。。
3.解密,把增加的那一个节对应(这个节你在加密的时候放哪里,就从哪里读)的数据读出来,然后解密,用上面提到的密钥,再进行一次异或,就可以得到原来的数据。加密解密用循环挨个异或就行。
4.以挂起的方式创建一个进程CreateProcess,不会的可以百度,创建这个进程是谁?就是壳子本身,不过是挂起的,系统只给你分配好进程空间,然后就不管了。
5.得到挂起的进程的上下文对象,Context这个结构体。GetThreadContext。
6.卸载掉我们创建的进程里面所有的东西,ZwUnmapViewOfSection用这个函数。
7.在指定的位置分配空间:位置就是源文件(被加壳的文件)的ImageBase 大小就是源文件的SizeOfImage的内存 ,VirtualAllocEx
8.如果在指定位置空间分配成功了,就把源文件拉伸(按照RVA),并贴在刚才创建的进程,指定的位置上。这一步我之前做了很多次,都没成功,然后就没指定位置,但是神奇的是,他刚好在ImageBase那里分配。
9.如果申请空间失败,判断该源程序是否有重定位表,有的话就在任意位置申请空间,然后将PE文件拉伸、复制、修复重定位表。
10.如果第7步申请空间失败,并且还没有重定位表,直接返回,失败。
11.修改外壳程序的Context;
将Context的ImageBase改成src的ImageBase
将Context的OEP改成src的OEP
12.设置Context 并恢复创建的进程的主线程(ResumeThread)
13.终止外壳程序,解壳过程结束。
大概过程就是这些,之中我遇到了挺多的问题,但是时间有点久,一时间想不起来了。就是调试的时候特别麻烦,大家在调试的时候,可以用MessageBox这个函数,在你觉的有问题的地方后面,放个MessageBox,看看会不会执行。
代码里面有详细注释。还有代码写的很难看,请谅解,如果代码运行有问题的话请评论,因为用VC写过一个,然后又用VS改了一下,分不清楚哪个是好的了。。
只放了 加密壳的代码,没有放加密程序的代码,(这是两个程序),这个代码很容易可以实现。壳子本身是运行不起来的,需要自己写一个加壳的程序。
刚才开头还有一些东西要提醒得,写到这里想不起来了,以后想起来会补上。
之前发的那个修复重定位表那块是备注起来了,因为之前修复重定位表的函数没写对,下面的正确的修复重定位的函数源码
DWORD RelocAddr(LPBYTE hModule, LPBYTE BaseAddress,LPBYTE ptr)
{
PDOS_HEADER pDosHeader;
PPE_HEADER pPEHeader;
POP_HEADER pOPHeader;
pDosHeader = (PDOS_HEADER)ptr;
pPEHeader = (PPE_HEADER)(pDosHeader->e_lfanew + (CHAR*)pDosHeader);
pOPHeader = (POP_HEADER)((CHAR*)pPEHeader + 0x18);
PIMAGE_BASE_RELOCATION pImageBaseRelocation;
if( (pOPHeader->DataDirectory+5)->virtualAddress&& (pOPHeader->DataDirectory+5)->size)
{
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)((pOPHeader->DataDirectory+5)->virtualAddress + ptr);
printf("%x",pImageBaseRelocation);
DWORD delta = (DWORD)BaseAddress - (DWORD)hModule;
while(pImageBaseRelocation->SizeOfBlock!=0 &&pImageBaseRelocation->VirtualAddress!=0)
{
PWORD offsetPtr = (PWORD)(pImageBaseRelocation + 1);
for(DWORD i=0;i<pImageBaseRelocation->SizeOfBlock-8;i++)
{
PDWORD codeLoc = (DWORD *)(ptr + pImageBaseRelocation->VirtualAddress + (*offsetPtr & 0x0FFF));
printf("%x -- ",codeLoc);
if(*(offsetPtr+i)/0x1000 == 3)
{
*codeLoc = (DWORD)((int)*codeLoc) + ((int)BaseAddress - (int)hModule);
}
offsetPtr++;
}
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)((char*)pImageBaseRelocation + pImageBaseRelocation->SizeOfBlock);
}
return 1;
}
return 0;
} 我来学习交流一下。 完全看不懂 纯小白一个{:1_937:} 发下可执行文件吧 没有环境的。谢谢! 好好学习了 咳咳。所以还是老问题。。。加密后,自然是要解密。。。。
所以想办法在完全解密后脱壳。。。好吧~_~有可能不方便找这个壳的位置而已但是总应该比vmp好办吧2333 好好学习了,,谢谢分享。 看不懂,愁啊。。。 不得不说,我一直觉得这就是我所需要的东西 好好学习了 向大佬学了来了 excuse me?
半成品是什么鬼!