-
-
[原创]PE分析小工具开发流水账(二)
-
发表于: 2025-12-7 14:15 358
-
最近随便看了一下其他类似工具的处理,我修改了一个程序的MZ头然后把它放到不管是CFF Explorer也好还是PEview也好,感觉都是采用的保守式分析。众所周知,MZ签名在最开头,当MZ签名被修改后,后面就不进行分析了,但是依然还是合法文件,而不是直接报错不是可执行文件不能分析。然后又试了一下改magic字段看看咋样,也是只分析到前面一些字段,后面保守式仅显示十六进制数据。
emmm,之所以想看看其他工具怎么处理,就是因为开发其实也遇到一点问题,就是在极端情况下假设一些关键字段被修改(虽然其实现实中可能没什么意义),但还是要考虑一些奇奇怪怪的情况。下面还是梳理一下最近又遇到的一些问题。
问题一:可选头分析的依赖问题
可选头之所以叫可选头我想就是因为它是分类讨论的,大概有32位、64位还有ROM架构的这个问题。目前我想先不考虑ROM架构,只做一个最小可执行版的。但是加载一个文件时怎么知道选择哪个结构呢,或者说,我在静态分析时怎么知道我要按照哪个结构分析呢。magic字段是最有说服力的,但是也不排除它的错误,归根结底就是,不能因为一个关键字段的修改而放弃后续的分析。但是其实这个架构问题,并不仅仅只是涉及到这一个字段,像是machine值啊,在合法情况下也要和这个东西匹配。所以我想留一个启发式分析的空给这种反推式分析结构。但是当多个字段出现错配时,这种分析方式也无能为力。所以就引发了下一个问题。
问题二:联合检验和反推式验证平衡点
除了在可选头中出现这种联合性检验问题,还有就是节区头的检验问题。一个健壮的解析器大概是不能仅仅依赖于关键字段的,比如NumberOfSections这样的字段。现实的恶意软件中,可能出现跳转执行这样的情况吧,万一后面还有节区咋办。然后我现在想的就是自己检验这个节区是不是节区,但是怎么检验呢,大概是根据里面字段的合法性检验。首先一个问题就是数量,我想的就是每40个字节一读取,然后看看它是不是,但是万一哪个什么奇怪的文件它搞个1000个节区咋搞,虽然它的NumberOfSections可能只写了几个。然后我设定了一个最大值128,如果它真搞1000个那这也解析不了,就报错算了。可现实就是某些壳啊什么的本来就不会改的所有值都合法,比如Name字段啊搞一点奇奇怪怪的值进去。既然知道现实中这个情况,那又怎么保证检验的成功性呢,可能需要置信度来判断吧,这个还在解决中。
问题三:节区属性判断(Characteristic字段处理)问题
关于属性问题,其实作为解析工具重点肯定不是放在像加载器一样搞清楚它到底是什么属性,但是对于某些节区,比如text段不应该有可执行属性还是需要诊断的。除了常见值,Characteristic字段问题就在于它有很多组合,按位计算,出现常见值容易解决,但是非常见值应该怎么处理。就类似于一个莫名其妙的值,可能被解析为可执行,怎么判断呢,这个部分也在设计中。目前想到的是分析以下几个关键属性。
struct section_imformation {
bool mem_execute_ = false; // 内存可执行
bool mem_read_ = false; // 内存可读
bool mem_write_ = false; // 内存可写
bool mem_shared_ = false; // 内存共享
bool cnt_code_ = false; // 包含可执行代码
bool cnt_initialized_data_ = false; // 包含已初始化数据
bool cnt_uninitialized_data_ = false; // 零初始化
……
}
一点个人的歪点子,欢迎讨论交流。