#1 楼
我不会说混淆检测与熵严格相关。当我检测到混淆代码区域时,我通过简单统计比较特定汇编命令的出现概率来做到这一点。例如具有控制流混淆的二进制文件中与跳转相关的命令数将大大增加。
具有不透明谓词的二进制文件中与算术相关的命令数将大大增加。
某些特定代码序列的数量,例如
jmp $+5
或应用这种混淆时,push addr; ret
会大大变大。这些启发式方法通常可以在未打包的代码上很好地工作(但是,可以通过熵测量和段的存在来检测打包的代码与知名的包装工有关或含义不明)。
评论
我用来检测混淆的技巧之一是计算功能数量和基本块数量,然后检查退出基本块以确定“退出指令”是否有意义。
– joxeankoret
15年5月18日在7:32
计数(函数序言的数量+函数序言的数量)/(代码大小)也可能是很好的启发式方法。
– w s
15年5月18日在7:33
一般而言,有许多不同的指标可以相对简单地加以说明。代码与数据大小之间的关系,跳转数,ALU操作数,与代码大小相关的加载/存储操作数-所有这些都可能提供很多信息。在这些指标上使用著名的多维统计三元组(因子,判别式和聚类分析),应能提供良好的检测率。
– w s
15年5月18日在7:39
#2 楼
我认为,总的来说,很难区分混淆的代码和极差或极好的编译器生成的代码。代码生成/优化将生成各种不必要/无效的指令。作为导致难以理解代码的高级优化示例,请考虑Massalin在超级优化器上的工作,以及GCC使用SSE2指令和/或积极的指令调度(例如在gcc -Ofast下)。 switch语句导致各种有趣的代码生成可能性,看起来很像混淆。
混淆的极端情况比较容易检测。但是试图隐身的混淆器将不容易被发现。
评论
我敢肯定,在.NET的情况下,每个混淆软件在生成的二进制文件上都有一些独特的“足迹”。如果浏览二进制文件不是一种选择:)