zoukankan      html  css  js  c++  java
  • 用C++实现的壳(扩展版)

    之前我写了篇【用C++实现的壳(基础版)】完成了一个非常单纯的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数据结构如下:

    1. typedef struct _MYIMPORT
    2. {
    3.   DWORD  m_dwIATAddr;      //IAT地址
    4.   DWORD  m_dwModNameRVA;      //模块名偏移
    5.   DWORD  m_dwFunNameRVA;      //函数名偏移
    6.   BOOL  m_bIsOrdinal;      //是否为序号导出函数
    7.   DWORD  m_Ordinal;        //序号
    8. }MYIMPORT, *PMYIMPORT;
    复制代码



    示意图如下:



            经过这样处理后的IAT,在你停在原程序OEP的情况下,用IAT修复工具是很难进行自动修复的,修复失败,也就意味着不能脱壳成功。
            
            如果大家感兴趣可以用这个壳对一个程序进行“IAT加密”,然后忘掉这个导入表数据结构,再脱脱壳感受一下,嘿嘿...
    【机器码绑定】
            这个其实没有什么技术含量,只是在逻辑上很难破解(在你不知道这个程序所绑定的机器码的情况下)。
            原理就是,用机器码1同代码段进行亦或操作,这样加过壳的程序就只能在机器码1的电脑上运行了,而如果在其他机器上运行,Shell部分在对机器码绑定进行解密的时候,获取的机器码同机器码1不同,这样解密出来的代码就是垃圾代码,根本无法运行,这样双击的效果为:
    https://bbs.pediy.com/upload/attach/201601/662999_mjxzo6vzo96zvzx.jpg
            大家在测试的时候,通过我打包的文件中的“查看机器码”查看本机的机器码,然后将这个机器码输入到加壳选项中,所加壳后的程序就只能在你的机器上运行了,如果改动一位,加壳后的程序运行时就会出错。
            我这个获取机器码的代码是从网上找的,但貌似并不是真正的机器码,不过也无所谓,只要能保证每台机器所获取的信息都是不同且唯一的就行,原理一样。
            
    【总结】
            给程序加壳其实就是拖慢破解者的进度,或者从数量上击垮对方,很难有脱不了的壳,除非是经过VM保护的代码才会很难分析。这就是一场加壳者和破解者之间的较量,再简单的壳也会有小菜脱不了,再难的壳也会有大牛能搞定。
            注:测试环境为win7系统,32位和64位都可以,但在xp上不行,原因是Shell部分获取Kernel32.dll基址的时候的代码只适用于win7,xp的话需要删除一句“mov eax, [eax]”。如果你想要兼容xp的话,请从网上自行搜索获取Kernel32.dll基址的其他方法。

  • 相关阅读:
    leetcode 29-> Divide Two Integers without using multiplication, division and mod operator
    ros topic 发布一次可能会接收不到数据
    python中的print()、str()和repr()的区别
    python 部分函数
    uiautomatorviewer错误 unable toconnect to adb
    pyqt 不规则形状窗口显示
    appium 计算器demo
    Spring 3.0 注解注入详解
    Spring Autowire自动装配
    restful 学习地址
  • 原文地址:https://www.cnblogs.com/luckywolfzyy/p/11387794.html
Copyright © 2011-2022 走看看