llvm学习(六):说说发现的其他几个项目的 Bug

最近开发参考了几个项目,仔细阅读源码的过程中,看到一些不大理解的地方。本来准备先写点基础知识的,看到hikari的作者在自己的 blog 里列举了其他人的 bug,作为后辈我也列举一下前人的 bug 好了。本文包括一个ollvm的 bug,两个(后来发现很多个)hikari的 bug,有空了给提个issue去,修起来也不难。(不代表 Armariris 没 bug,因为写的太挫了,没忍心看。。。)

一、ollvm在 Flatten 时对 IndirectBranch 缺少处理的bug

原因:ollvm 在 Flatten 时,根据每个 BasicBlock 的 Terminator 的后继个数来进行处理,当后继为2时,就认为是 BranchInst 了,但这时不一定是 BranchInst

代码位置:

测试用的 case:

crashLog:

PS:直接拿这个.c编译的话是不行的,因为正常情况下是不会出现 IndirectBr 的,和其他 Pass 配合起来就会出现 IndirectBrInst,从而造成Crash。

例如随手写的这个 Pass 进行配合,就会造成Crash:

其实这里还会被其他的 Terminator 打挂,例如C++那边的那几个处理异常的 Terminator,也是可能把 Flatten 打挂的,只是我没触发到罢了。

二、Hikari字符串加密时的逻辑bug

原因:Hikari 对rwdata的字符串进行加密时,如果有多处引用,会复制多份 copy,从而导致该字符串被修改后没有写回。当时好像看第一遍时候就觉得有问题,测试时候果然发现有问题。

效果示例:

按理说输出的应该是 2 次 “AlloWorld!”,但因为作者设计的问题,第二次输出错误了。

在main和repeat函数里,都对hello字符串进行了引用,所以存放了2份密文和2份 key ,直接被当成了2个独立的数据进行处理。当时还记得错误的位置来着,现在给忘了,不知道为什么作者会写出这么蠢的 bug。

三、Hikari使用dlopen时不同平台flag 错误的 bug

原因:Hikari 的 FunctionCallObfuscate 引用了dlfcn.h 里定义好的常量,万万没想到,各个平台对这个常量的定义不一样

代码位置

其实乍一眼,看不出这个有什么问题,确实使用了这两个 flag,问题出在,各个平台的这个文件可能不一致。

例如 Android 上的:

例如 Mac 上的:

其他的没统计,反正我在安卓上踩坑了,在小伙伴的提醒下,打开 IDA才发现是这里的问题。

这里应该根据  TargetTriple 的实际情况去配置数值,不能直接用 Mac 上自带的这个。

四、向各位前辈大佬致敬

======2019.3.17更新=========

不是我说,hikari里的 bug 还真不少。。。

五、Hikari 字符串加密的并发 bug

当时是注意到来着,但和使用情景确认过,调用是单线程的,而且调用间隔比较长,所以就没有刻意去解决这个问题。从设计角度上来讲,可以很容易看出这个 bug。

写一下 hikari 的伪代码,例如一段 HelloWorld 的代码。

显然,当多个线程同时进入 func 时,在第一个线程解密到一半的时候,第二个线程发现 isDecrypt 仍然是0,于是也开始解密。预期情况下,数据被解密一遍后是明文,被解密两遍后是乱码,所以并发肯定会出问题的。

在没有锁的情况下,无论如何写,总会出现错误的,无论什么时候去解密和设置标记,没有完美的方案。

最后正确的代码应该是:

六、Hikari 字符串加密的未处理 bug

直接上样例吧,出现在当前 module 使用了其他 module 里的字符串的情况下,会出现非预期。

例如这个字符数组,是两个 module 里的(虽然没有人这么写),执行后,在main.c里会寻找不到 c 这个符号,因为在data里已经将 c 给删掉了,连接时就会报错。

处理方案:额,暂时没想到。。。

七、Hikari字符串加密乱插指令的 bug

设计角度上,Hikari 为每个函数都加了一个flag,在第一次进入该函数时候运行解密代码。问题就出在这里,例如写了一个很简单的函数。

我什么都不写,按理说里面没有字符串,没有必要插指令,但 hikari 还是插进去了。。。。。佛了。。。。。

处理方案:在处理函数时,如果函数里没有用到常量字符串,就跳过该函数。

《llvm学习(六):说说发现的其他几个项目的 Bug》有2个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code