ionCube逆向工程进展备忘
2021-05-21 18:44:36 Author: mp.weixin.qq.com(查看原文) 阅读量:208 收藏

这是一篇吹牛式的、毫无意义的备忘,不要看,不值得看。

2021-05-21 16:48 scz

在XX期间有同事提出ionCube保护PHP源码比较结实,于是研究了一下。

此番与ionCube不期而遇,作为没有任何PHP基础的C/ASM程序员,确实感受了作者深深的恶意以及随之而来巨大的逆向工程挑战。看了看PHP引擎源码,随便吐个槽,这代码质量真特么烂。用IDA、GDB搞了一下ionCube,再吐个槽,其作者编码风格山寨而奇葩。

在2021.4.23的日记中评论:

分析过敌对组织的某些样本,其使用了许多令人叹为观止的高级对抗技术,很是佩服。敌方程序员应该是受过正规而系统的教育,虽然All In One,但逻辑框架一点不显混乱。对于敌方开发维护,这是很好的现象,以前赞美过这样的对手。但从另一个角度看,对于己方逆向工程,这也是很好的现象,对于敌方可能就是一种遗憾了。

今天说一个反例。最近在逆ionCube Loader,其逻辑框架显出一种迷之混乱,尽管我理顺了它的主体流程。考虑到该代码是用于商业PHP加密的,必然包含反静态分析的处理,但从IDA中看它,仍有大量山寨或者显得业余的代码痕迹,一种编译器想优化都优化不过来的感觉。当然,这有一种可能,开发者在源代码级别有意进行了反逆向工程干挠。或者另一种更小概率的可能,开发者智商太高,想哪写哪、信手填坑式开发,嗯,这样的存在也是有的,比如二十年前的yuange。不确认ionCube Loader的开发人员是水平太高,还是水平太渣,总之,那些外在山寨、业余的代码逻辑客观上给逆向工程带来了障碍。我是该赞美TA们呢,还是喷TA们呢?

无论真相如何,此番真地被挑战到了。2019.10剁完Burp Pro之后说过一句话,有技术追求的人应该去挑战那些崇山峻岭。无须置疑,不期而遇的ionCube就是新的崇山峻岭。

搞了一阵之后,有些看法如下:

(a) ionCube 7.x确实很结实,作者应该与搞逆向工程的搏斗过多年,其实现很变态
(b) ionCube 7.x处理过的some_enc.php不含原始some.php,只有混淆过的opcode
(c) 逆向工程技术路线必须分两步走,第一步还原zend_op_array,第二步反编译
(d) easytoyou网站很NB,PHP源码还原度很高,应该有一个强大的私有PHP反编译器

决定先努力达成第一步,即还原zend_op_array,今天阶段性目标达成。

some.php中含有类、多个函数,某类中某函数如下:

/**
 * func_0 comment
 */

public function func_0 ( $arg )
{
    try
    {
        $mode   = func_1( $arg );
        switch ( $mode )
        {
        /**
         * case 0
         */

        case 0 :
            func_case_0( $mode, $arg );
            break;
        case 1 :
            func_case_1( $mode );
            break;
        default :
            /**
             * default
             */

            func_default( $mode, " (unexpected)\n" );
            throw new Exception"\$mode is invalid" );
        }
    }
    catch ( Exception $e )
    {
        print_r( $e );
        die;
    }
    finally
    {
        echo "Finally\n";
    }
}

写程序还原func_0()对应的zend_op_array并反汇编(不是反编译),效果如下:

/**\n     * func_0 comment\n     */
func_0(arg)
[0] (11) $arg = RECV(,)
[1] (15) = INIT_FCALL_BY_NAME(,"func_1")
[2] (15) = SEND_VAR_EX($arg,)
[3] (15) var_4 = DO_FCALL_BY_NAME(,)
[4] (15) = ASSIGN($mode,var_4)
[5] (21) tmp_6 = CASE($mode,0x0)
[6] (21) = JMPNZ(tmp_6,->10)
[7] (24) tmp_6 = CASE($mode,0x1)
[8] (24) = JMPNZ(tmp_6,->15)
[9] (24) = JMP(->19,)
[10] (22) = INIT_FCALL_BY_NAME(,"func_case_0")
[11] (22) = SEND_VAR_EX($mode,)
[12] (22) = SEND_VAR_EX($arg,)
[13] (22) = DO_FCALL_BY_NAME(,)
[14] (23) = JMP(->27,)
[15] (25) = INIT_FCALL_BY_NAME(,"func_case_1")
[16] (25) = SEND_VAR_EX($mode,)
[17] (25) = DO_FCALL_BY_NAME(,)
[18] (26) = JMP(->27,)
[19] (31) = INIT_FCALL_BY_NAME(,"func_default")
[20] (31) = SEND_VAR_EX($mode,)
[21] (31) = SEND_VAL_EX(" (unexpected)\n",)
[22] (31) = DO_FCALL_BY_NAME(,)
[23] (32) var_10 = NEW("Exception",)
[24] (32) = SEND_VAL_EX("$mode is invalid",)
[25] (32) = DO_FCALL(,)
[26] (32) = THROW(var_10,)
[27] (32) = JMP(->33,)
[28] (35) = CATCH("Exception",$e)
[29] (37) = INIT_FCALL_BY_NAME(,"print_r")
[30] (37) = SEND_VAR_EX($e,)
[31] (37) = DO_FCALL_BY_NAME(,)
[32] (38) = EXIT(,)
[33] (41) tmp_3 = FAST_CALL(->35,)
[34] (41) = JMP(->37,)
[35] (42) = ECHO("Finally\n",)
[36] (42) = FAST_RET(tmp_3,)
[37] (44) = RETURN(<IS_NULL>,)

[n]是opcode索引,(n)是源代码行号。反汇编结果中有两段注释丢了,因为它们未被保存到some_enc.php中。

只要保存了的注释,理论上都能还原出来。但easytoyou还原注释时有BUG,不是所有被保存的注释都能还原出来,于是此处可设计CTF赛题,将flag置于easytoyou未成功还原的注释中,简单、粗暴、可解。

目前还在早期原型阶段,只用两个样本测试,还有很多细节需要处理,只是反汇编成功,第二步反编译器尚未动手。

记录进展备忘于此。


文章来源: http://mp.weixin.qq.com/s?__biz=MzUzMjQyMDE3Ng==&mid=2247484689&idx=1&sn=42cdcb819154be5501ece32e35beb846&chksm=fab2c62ecdc54f387aa9d4e5d8608d80efc8d3267dcbb8e87d20152df2457ee6918da50ef24c#rd
如有侵权请联系:admin#unsafe.sh