首页
社区
课程
招聘
[原创][开源]用C++实现的壳(扩展版)
2016-1-1 13:47 45819

[原创][开源]用C++实现的壳(扩展版)

2016-1-1 13:47
45819
        前几天我写了篇【用C++实现的壳(基础版)】http://bbs.pediy.com/showthread.php?t=206804 完成了一个非常纯洁的C++壳基础框架。现在这个【扩展版】的壳在之前的基础上增加了两个功能,一个是IAT加密,在一个就是机器码绑定。并修复了一些bug,静态编译了Shell.dll,使得在Win 7 x86和Win 7 x64位下都可以正常加壳了,如果加壳后的程序无法运行,请取消“IAT加密”选项,原因是我在IAT加密中使用了Hook-API,而Hook以后全当Call来处理了,实际有的程序IAT位置所填写的地址指向的并不全是Call指令,有时候是Mov指令,所以“IAT加密”功能的兼容性不足。
        本来想增加反调试功能,可我实在水平有限,无法干掉StrongOD的反反调试功能,所以就没在拓展版中假如反调试功能,如果大家有什么好的反调试技术可以添加到这个壳子里,我在这就不献丑了...
        拓展版在界面上有了变化,增加了一些可选选项:

   

        下面就分别介绍一下“IAT加密”和“机器码绑定”这两个功能的实现。

【IAT加密】        

        我对IAT进行加密的思路是:
        ①首先定义一个自己的导入表数据结构,在Pack部分加壳的时候,读取被加壳程序的导入表信息并保存到我自己的导入表数据结构中,然后抹去被加壳程序的导入表数据;
        ②在Shell部分对IAT进行解密的时候,直接从我自己定义的导入表数据结构中获取修复IAT所用的信息,当通过这些信息获取到真正的函数地址后,将该地址填入一个new出来的堆空间1内保存,在这个堆空间1内加入一些花指令,最终再调用真正的函数地址。
        如果直接将堆空间1的地址写入IAT,就完成了一个简单的IAT-Hook,但这样操作的话,真正的函数地址和要写入的IAT地址会同时出现,在反汇编中修改代码,直接将函数地址写入IAT地址的话,就会使得IAT-Hook失效,所以我没有直接将堆空间1写入IAT地址。
        ③而是将堆空间1写入了一段又new出来的堆空间2,然后再在别的函数中,将堆空间2的地址写入IAT地址,这就能保证真正的函数地址和IAT地址不同时出现,这样的话,如果脱壳者在不了解我自己定义的导入表数据结构的情况下,是很难修复IAT并成功脱壳的。
        我自己定义的IAT数据结构如下:
typedef struct _MYIMPORT
{
  DWORD  m_dwIATAddr;      //IAT地址
  DWORD  m_dwModNameRVA;      //模块名偏移
  DWORD  m_dwFunNameRVA;      //函数名偏移
  BOOL  m_bIsOrdinal;      //是否为序号导出函数
  DWORD  m_Ordinal;        //序号
}MYIMPORT, *PMYIMPORT;


        示意图如下:
   

        经过这样处理后的IAT,在你停在原程序OEP的情况下,用IAT修复工具是很难进行自动修复的,修复失败,也就意味着不能脱壳成功。
        
        如果大家感兴趣可以用这个壳对一个程序进行“IAT加密”,然后忘掉这个导入表数据结构,再脱脱壳感受一下,嘿嘿...

【机器码绑定】
        这个其实没有什么技术含量,只是在逻辑上很难破解(在你不知道这个程序所绑定的机器码的情况下)。
        原理就是,用机器码1同代码段进行亦或操作,这样加过壳的程序就只能在机器码1的电脑上运行了,而如果在其他机器上运行,Shell部分在对机器码绑定进行解密的时候,获取的机器码同机器码1不同,这样解密出来的代码就是垃圾代码,根本无法运行,这样双击的效果为:
   

        大家在测试的时候,通过我打包的文件中的“查看机器码”查看本机的机器码,然后将这个机器码输入到加壳选项中,所加壳后的程序就只能在你的机器上运行了,如果改动一位,加壳后的程序运行时就会出错。
        我这个获取机器码的代码是从网上找的,但貌似并不是真正的机器码,不过也无所谓,只要能保证每台机器所获取的信息都是不同且唯一的就行,原理一样。
        
【总结】
        给程序加壳其实就是拖慢破解者的进度,或者从数量上击垮对方,很难有脱不了的壳,除非是经过VM保护的代码才会很难分析。这就是一场加壳者和破解者之间的较量,再简单的壳也会有小菜脱不了,再难的壳也会有大牛能搞定。
        注:测试环境为win7系统,32位和64位都可以,但在xp上不行,原因是Shell部分获取Kernel32.dll基址的时候的代码只适用于win7,xp的话需要删除一句“mov eax, [eax]”。如果你想要兼容xp的话,请从网上自行搜索获取Kernel32.dll基址的其他方法。

        源码下载: CyxvcProtect(扩展版).rar

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (74)
雪    币: 191
活跃值: (818)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
Netfairy 11 2016-1-1 14:23
2
0
感谢分享,之前我也研究过写壳
雪    币: 49
活跃值: (118)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
smurf 2016-1-1 14:49
3
0
支持一下,顶起
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
ID蝴蝶 1 2016-1-1 15:13
4
0
支持一下,顶起。
雪    币: 6026
活跃值: (3940)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
pxhb 2 2016-1-1 17:25
5
0
非常感谢分享
雪    币: 260
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yunshouhu 2016-1-1 17:26
6
0
不错,支持楼主,等放假回来再看看。
雪    币: 6026
活跃值: (3940)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
pxhb 2 2016-1-1 17:34
7
0
方便传个vs2010版本的吗
雪    币: 77
活跃值: (929)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cyxvc 3 2016-1-1 18:00
8
0
我电脑上只有VS2013啊

不过我给你百度了一下如何解决问题

希望能帮到你:
http://blog.csdn.net/civilman/article/details/40109483
雪    币: 294
活跃值: (119)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
zfdyq 1 2016-1-2 00:01
9
0
good job
雪    币: 6026
活跃值: (3940)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
pxhb 2 2016-1-2 10:22
10
0
非常感谢回复
要是以后加入虚拟机引擎就爽了
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 01:00
11
0
感谢分享!挑战一下自己,明天开始研究如何破解
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 03:19
12
0
看了一下你的加密程序,有思路了,嘿嘿代码加密的找到入口点,等你自己解密了之后,就行,至于IAT加密,嘿嘿,也不难啊!可以采用,已知明文破解的办法,就是用VC编写一个静态加载自己DLL的程序,编写之后,用PE编辑工具打开这个文件,打开之后,查看导出表在文件地址,根据对齐值,计算一下加载到内存时的位置,记下这个位置,接着用楼主的程序加壳,加壳之后用OD加载被加壳的程序,拿着刚刚已经计算好的IAT地址加上模块的加载地址,就可以知道IAT地址,然后在IAT地址上下内存断点,在LoadLibraryW GetProcAddress GetModuleHandleW等函数上下执行断点,接着就调试,嘿嘿,看是什么指令写入了IAT,什么位置调用了GetProcAddress  以及加载了什么模块,等加载自己的DLL的时候,就自己手动通过EAT获取自己DLL的函数的地址,然后填入刚刚加壳程序填入的IAT地址,看是否会直接调用你的程序,如果直接调用,而没有经过加壳程序的话,就说明你获取的IAT写入地址正确了,嘿嘿,用这个方法手工恢复吧!要是获取的IAT地址不正确,就继续调试,直到能获取正确的IAT地址为止!
雪    币: 77
活跃值: (929)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cyxvc 3 2016-1-3 10:10
13
0
你这个思路实现了吗? 我获取到真正的函数地址以后,不是直接填到对应的IAT地址的啊。。而是直接填到一块new出来的堆空间中的啊,而这个堆空间中填的地址也不是直接就是函数地址,是一段ShellCode的地址,经过一些花指令以后才会call真正的函数地址。
你dump以后成功修复IAT了? (加壳的时候别忘了选择IAT加密)
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 10:22
14
0
部分实现,通过一个已知的DLL的API,我已经定位到了解码IAT的程序!已经找到了IAT原地址,你即使申请了new的地址,你也必须向原IAT地址填写一个HOOK,不是么?跟踪到后面的结果是,如果没有进行IAT加密的话,会发现惊喜,不过经过测试,加密之后也没事,你同样会发现惊喜!
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 10:25
15
0
没有完全实现的原因,只是因为我跟踪到IAT之后,累了,就先休息了,嘿嘿,等过两天,我有空了,继续挑战,嘿嘿!不过表扬一下,花指令还是不错,不过,不是很强大,花了我多一点事件读取而已
雪    币: 77
活跃值: (929)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cyxvc 3 2016-1-3 10:28
16
0
哇,多谢大牛赐教!

调试方面我还是太弱啊,回头研究研究你说的这种方法!

感谢感谢!
雪    币: 260
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yunshouhu 2016-1-3 14:32
17
0
1、本人环境为vs2010,附件中的源码存在问题,开始直接编译不通过。
需修改shell.cpp 245行279行添加等号。
2、修改完各种错误后静态编译出来的shell.dll只有38kb,而楼主所给的shell.dll为78kb不知是什么原因。(基本的环境配置我没有修改,只修改编译错误信息。)
3、使用楼主的shell.dll加壳在win7 x64系统可以正常运行,但是使用楼主源码编译出来的exe和dll加壳后运行弹出对话框后运行出错。第二次输出信息为:
runtime error R6009
- not enough space for environment
4、猜想附件中的源码是不是最终版本。
雪    币: 77
活跃值: (929)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cyxvc 3 2016-1-3 15:52
18
0
我用的是VS2013开发的。
我给出的那个78kb的Shell.dll是我在VS2013下静态编译的( 运行库:多线程 MT )Release版。


你试一下你自己编译exe文件配上压缩包里自带的Shell.dll(78kb)看能不能正常加壳。如果能的话就说明是Shell编译的问题。

确定一下你的dll项目是否是Release(之前为了调试方便,我把shell项目Release的生成目录改成了Debug目录),再确定一下Shell项目是不是按照上图中的方式设置。

在我电脑上下载下来源码然后直接编译出来,加壳是没问题的。

看来VS低版本对高版本的兼容性不太好吧,你也可以看看这个迁移方案,希望能够帮到你:
http://blog.csdn.net/civilman/article/details/40109483
上传的附件:
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 17:17
19
0
已经可以破解了,嘿嘿,多谢你的加壳程序了,我已经弄好了,等我整理好了,吃了晚饭,我就上传破解办法以及资料,先上传截图,等我晚上弄好以后,再上传教程,嘿嘿,肚子饿了,晚上才弄
上传的附件:
雪    币: 27
活跃值: (354)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Promisejhy 2016-1-3 17:50
20
0
留个记号,持续关注楼主的更新。
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 18:14
21
0
楼主,你的加密程序,我已经破解好了,但是我现在在考虑是不是要公布做法,来教一教大家呢?等我公布了,我怕楼主又不高兴了!
雪    币: 77
活跃值: (929)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cyxvc 3 2016-1-3 18:32
22
0
啊...暂时没有更新的打算了,我就是提供个框架,整点简单的加密而已,
主要是抛砖引玉哈哈...
雪    币: 77
活跃值: (929)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cyxvc 3 2016-1-3 18:33
23
0
没啥不高兴的,我这壳本来就是供大家学习的,我自己水平也有限,有大牛来指点当然是极好的了!
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 18:38
24
0
楼主犯了一个小错误,导致我可以直接在你的程序中,直接截取你的IAT填写以及复制过程,在这个过程中,可以在堆栈中记录到导出模块已经导出函数名,楼主在申请新的IAT地址前,使用了LoadLibrary和GetModuleHandle,这两个函数调用时,在堆栈上可以看到我们想要的模块,赶紧的,记录下来呗!,使用了GetProAddress,没有清空EAX寄存器的值,而是,将EAX与15151515h进行异或之后填写入局部变量中,然后就申请了新的内存,新内存地址就保存在EAX中,然后以EAX作为返回值,新的内存用来填写ShllCode,而ShllCode中对原函数的回调用的地址就直接写入SHELLCODE,同时把ShllCode地址存在一个变量中,这个变量,后来又被取出,用来填写真正的IAT地址!我只需截取 ShellCode,让ShellCode的地址指向原函数,并且取消对ShellCode的填写操作,然后用OD将对应的代码回填到可执行文件中,并且在你的程序回填IAT HOOK的时候,记录你的IAT地址就行,有了IAT地址,又有正确的模块加载列表,函数列表,以及IAT的函数地址的链表,恢复IAT不好办么?
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 2 2016-1-3 18:49
25
0
楼主,你想破解的话,先准备工具,需要的工具ollydbg
Cheat Engine和VS2010,以及楼主的加壳程序!
楼主,我先编辑资料,写上破解过程,等一下我发上来
游客
登录 | 注册 方可回帖
返回