madder 发表于 2019-4-17 01:43

一个简单的二进制加密壳

本帖最后由 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;
}

dxpwanysys 发表于 2019-4-17 19:10

我来学习交流一下。

jxhh 发表于 2019-4-17 17:28

完全看不懂   纯小白一个{:1_937:}

奇妙 发表于 2019-4-17 02:42

发下可执行文件吧 没有环境的。谢谢!

haidao123 发表于 2019-4-17 05:13

好好学习了

涛之雨 发表于 2019-4-17 06:27

咳咳。所以还是老问题。。。加密后,自然是要解密。。。。
所以想办法在完全解密后脱壳。。。好吧~_~有可能不方便找这个壳的位置而已但是总应该比vmp好办吧2333

cjwff 发表于 2019-4-17 07:14

好好学习了,,谢谢分享。

bachelor66 发表于 2019-4-17 08:29

看不懂,愁啊。。。                                    

大跳企鹅 发表于 2019-4-17 08:35

不得不说,我一直觉得这就是我所需要的东西

Portos 发表于 2019-4-17 10:10

好好学习了

yangzhimin 发表于 2019-4-17 11:19

向大佬学了来了

huzpsb 发表于 2019-4-17 11:35

excuse me?
半成品是什么鬼!
页: [1] 2 3 4 5 6
查看完整版本: 一个简单的二进制加密壳