Windows x86 下的 静态代码混淆

0x00  前言

静态反汇编之王,毫无疑问就是Ida pro,大大降低了反汇编工作的门槛,尤其是出色的“F5插件”Hex-Rays可以将汇编代码还原成类似于C语言的伪代码,大大提高了可读性。但个人觉得“F5插件”只能作为一项辅助手段,在结合动态调试和静态分析之后,了解了整个函数的流程再利用F5看“C语言”代码才是最佳的手段。而这篇文章就是学习如何手写”花指令“,来干扰ida的静态分析和”F5插件“。

0x01 反汇编引擎

反汇编引擎就是将二进制程序翻译成了汇编的工具。主流的反汇编算法主要是两种:线性扫描反汇编和递归下降反汇编。

线性扫描算法是将一条指令的结束作为另一条指令的开始,从第一个字节开始,以线性模式扫描整个代码段,逐条反汇编每天指令,直到完成整个代码段的分析。主要优点是可以覆盖程序的所有代码段,但是却没有考虑到代码中可能混有的数据,容易出错。

递归下降算法依据程序的控制流,根据一条指令是否被另一条指令引用来决定是否对其进行反汇编。例如遇见条件跳转指令,反汇编器从true或者false两个分支处选择一个进行反汇编,如果是正常的代码,反汇编器优先选择true分支或者false分支,输出的汇编代码并没有任何区别,但是在遇见人工编码的”花指令“后,同一块代码的两个分支经常会产生不同的反汇编结果。当冲突时,反汇编器会优先选择信任的分支,而大多数面向程序控制流的反汇编器会首先选择false分支。

更多的具体关于反汇编引擎的介绍请参考看雪论坛的文章:

《各种开源引擎,反汇编引擎的对比》 :http://bbs.pediy.com/showthread.php?p=1401094#post1401094

0x02  欺骗“F5” Hex-Rays

简单的”push+ret”组合(和jmp一样)根本不能骗过ida ,很轻易的就被f5还原出了”C语言”。而多出来的memset()函数是f5将编译器自动开辟栈的空间的代码还原了。

我们继续变化,将”push+ret”组合换成另一种形式:

结果令人有点失望,还是被f5直接还原了。

那我们继续修改,向下跳转后再向上跳转,ida会不会以为是循环?

好像是成功了,欺骗了ida的f5。但是稍微看一眼汇编代码就很容易看出这个循环跳转

但通过以上的例子可以总结出ida f5插件的一些特性:

(1)对于jmp指令的分析完全没有问题

(2)“push+ret”指令的组合直接当成jmp处理

(3)向下跳转再向上跳转,会认为是循环

(4)对于手动通过寄存器将值置于栈上的分析能力较弱,但简单的还是可以直接分析出。

之前都是在函数内部跳转,也可以改变跳转的方式,做函数间的长跳转。

而点进去saveregs会发现是这样的

很好,看来又成功欺骗了f5插件。但是读汇编代码会发现

双击进入_next,还是被发现了我们的真正的代码。

0x03  针对反汇编引擎

之前都是用跳转指令来迷惑”F5”插件,那可不可以让运行的结果和ida分析的汇编完全不同呢?这里我们就需要插入一些机器码来迷惑反汇编引擎,比如经常会用到在代码中间插入一些数据,让ida无法对数据和代码进行有效的区别,最普通的就是0xE8,因为这是call指令的第一个字节。

当”f5”还原时,弹出对话框,显示无法”Decompilation”。

反汇编的结果显示将0xE8作为call指令的第一个字节解释,然后成为了一个call指令,但是ida已经标注出为红色了,有经验的人一看就知道这块代码是被”加花”了的.

主要这里的xor eax , eax 和jz这两句,这本就是个跳转,为什么不直接写成jmp呢?因为之前说到过的面向控制流的反汇编引擎的策略是遇见jmp直接跳转,0xe8就会就被识别,这里人为的写成“条件跳转”,以此来达到混淆的目的。机器码的插入方法有很多,但一些机器码既可以作为前一条指令的结尾,又可以作为下条指令的开始,比如说刚刚的e8指令,尽量不要用在CPU可以执行的地方,不然很容易让程序崩溃。我们可以来看稍微复杂的指令插入

可以看到ida的分析结果有点令人失望,”f5”之后也没什么用。

我们可以借助更多的机器码达到欺骗ida的目的

反汇编的汇编代码:

这里ida将0x66 0xb8识别为mov指令的前两个字节了,然后导致之后的分析错误。而在0xe8的中间还可以加入大量的其它花指令。

0x04 SEH

SEH 结构化异常处理,这里就不多做介绍了,可以阅读之前的文章Windows x86 SEH 学习,需要说明的是编译器实现的SEH和普通的不一样。

0x05  破坏栈帧分析

Ida试图分析一个函数来确定其栈帧结构,特别是遇到ret/retn就认为到达一个函数结尾,因此很容易伪造栈帧来阻止静态分析。给之前的代码加上一个ret 0xff

Ida f5 的结果,认为有63个参数。

还有就是在函数中改变esp的值:比如说这里的"cmp esp,0x1000",后面的"add esp , 0x102"是永远不会执行的,在这里可以改变esp,也可以做其他的很多混淆手段。

最后f5显示栈帧已经被破坏了,是不是很熟悉,和之前在函数中调用pop,eax的结果一样,都显示栈帧已经被破坏了。

0x06 小结

列举了非常基本的几种针对ida 和 f5插件的混淆代码,虽然很基础,但是可以将非常非常多的混淆代码进行叠加,形成庞大的”花指令”,花指令的目的就是增加分析的成本。编写混淆代码最重要的一点就是堆栈平衡。如果对于代码混淆,保护做更进一步学习,可以加入GitHub上的开源项目 WProtect 利用”虚拟机技术”来保护代码。关于汇编的分析,个人还是觉得不能太依靠ida和Hex-Rays插件,要自己先动态走一遍流程,熟悉整个框架以后再借助ida 和"F5"插件来提高效率。

参考资料:

《IDA Pro 权威指南》

《恶意代码分析实战》

《加密与解密》

时间: 2024-10-09 22:42:21

Windows x86 下的 静态代码混淆的相关文章

android 常用第三方包的代码混淆

首先在:project.properties 文件下,启动代码混淆 proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 将这行注释取消. 修改proguard-project.txt 代码混淆文件. //1)注意忽视警告 -ignorewarnings -dontwarn //2)注意的是,使用到反射的类,需要keep -keepattributes Signature-keepa

Python 控制流代码混淆简介,加大别人分析你代码逻辑和流程难度

前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 王平 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http://t.cn/A6Zvjdun 聊下 Python 的代码混淆,对 Python 的代码做混淆感觉是不伦不类,但是对于外包项目交付型的,又有一些需要. 混淆的目的就是加大别人分析你代码逻辑和流程的难度,让代码看上去杂乱,逻辑混乱.但是程序要能正常运行. 一般混淆 对 Python 代

Linux下编译静态MinGW环境,编译windows平台Qt程序(使用MXE)

参考链接: MXE.>大多数程序都是在windows平台下开发的程序.windows 在现实中也是绕不过的一个系统平台,做为受过几年VC,MFC”虐待”的程序员,在做为一个程序员之前是一位Linux重度使用者,受够了MFC之后一直想要找一个框架替换,使用过GTK,wxWidgets,Qt,最后还是Qt用得多一些.我认为程序跨平台应该是一个基本标准,同一份代码不需改动,或者改动极少,放在不同的平台下编译就能使用.不同平台,同样的界面,同样的操作,同样的体验.这里要讲的是我如何在Linux 下开发跨

Windows下使用静态库和动态库

Windows下使用静态库和动态库 (一)环境 Windows 7 32位 Visual Studio 2013 (二)dll和lib简介 在Windows下很好理解这些概念,因为当你需要引入一个动态库(dll)或者一个静态库(lib)时一般的步骤是: 添加头文件 配置头文件目录 配置库的目录 将dll拷贝到可执行文件所在的目录(仅限于动态库) 因此,就很好理解.h文件..dll文件和.lib文件的关系: .h文件是编译时需要的,因为里面有函数或变量声明. .dll文件是生成的动态库,是在程序运

Windows环境下通过Git来管理自己的Android代码

前面已经介绍了在Windows下使用git工具来下载Android的源码,Windows环境下通过Git得到Android源代码,这里记录我使用git工具来管理我自己的代码,git是一种分布式的项目管理工具而CVS及SVN都是集中式的版本控制系统集中式版本控制系统最大的毛病就是必须联网才能工作,分布式版本控制系统根本没有"中央服务器",每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上,分布式和集中式通过以下两张图会清楚点 Window

Android 编程下的代码混淆

什么是代码混淆 Java 是一种跨平台的.解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中.由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名.方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码.为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆. 混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功

windows环境下使用git客户端、github和tortoisegit管理项目代码

一.为什么 为什么不用svn? svn是一个优秀的代码和版本管理工具,使用svn只需要搭建好svn中央仓库,配置本地svn客户端即可,自从google code关闭服务之后,互联网上已经没有非常好的公共svn仓库,如果是公司内部使用,还可以用上公司内网搭建的svn服务器,但个人就没那么方便了. 为什么用git? git和svn同样作为代码和版本管理工具,git的理念更先进,而且公共git仓库github真的好用,众多优秀的开源项目都放在github 什么是git.github.tortoiseg

详谈Android 编程下的代码混淆,点开就看....

源码混淆什么 Java 是一种跨平台的.解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中.由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名.方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码.为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆. 混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也

Android Studio环境下代码混淆+签名打包

Android Studio环境下代码混淆+签名打包 作者 Mr_冯先生 关注 2016.08.21 01:10 字数 1040 阅读 734评论 5喜欢 34 注:本文使用的Android Studio版本是 2.1.2. 做公司项目,需要对项目进行代码混淆+签名打包,然后就各种搜集查看资料,算是小有成果吧.周末无事就想着总结一下以后再用可做参考.如有不对的地方烦请各位大神指导-- 一.代码混淆 android studio进行代码混淆需要在两个地方做配置:1.添加自己的混淆规则到对应Modu