首页
社区
课程
招聘
[原创]一种函数级变深度循环递归加密的JavaScript代码加密引擎
发表于: 2018-11-10 19:16 13633

[原创]一种函数级变深度循环递归加密的JavaScript代码加密引擎

2018-11-10 19:16
13633

0x00 前言

在与攻击者对抗的历程中,Web前端一直是非常薄弱的一环。浏览器毫无保留地把所有前端代码拉取到本地并执行、所有前端代码均透明可见。现在JS随着小程序和前端的兴起越来越火,收到了各个厂商的重视。如何保护前端JavaScript代码的安全? 最近自己正好在做JS的加密,分享一下自己的方案。

0x01 前期调研

简单列出市面上经常出现的几种保护方案:
1.混淆

混淆工具有很多:YUI Compressor、UglifyJS、Google Closure Compiler,其中商业产品 有jscrambler等

2.加密

有些加密工具很有趣,比如aaencode:

加密前

alert("Hello, JavaScript")

加密后

゚ω゚ノ= /`m´)ノ ~┻━┻//*´∇`*/ ['_']; o=(゚ー゚)=_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚.....

再比如jjencode:

加密前

alert("Hello, JavaScript")

加密后

$=~[];$={___:++$,$$$$:(![]+“”)[$],__$:++$,$_$_:(![]+“”)[$],_$_:++$,$_$$:({}+“”)[$],$$_$:($[$]+“”)[$],_$$:++$,$$$_:(!“”+“”)[$],$__:++$,$_$:++$,$$__:({}+“”)[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+“”)[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+“”)[$.__$])+((!$)+“”)[$._$$]+($.__=$.$_[$.$$_])+($.$=(!“”+“”)[$.__$])+($._=(!“”+“”)[$._$_])+$.$_[$.$_$]+$.__…….

但是他们都无一例外膨胀到令人无法接受的程度,只好放弃。

或是使用base64加密

加密前

function a(e){/* ... */console.log(e.title)}a({title:\'buy\'})

加密后

eval(atob("ZnVuY3Rpb24gYShlKXsvKiAuLi4gKi9jb25zb2xlLmxvZyhlLnRpdGxlKX1hKHt0aXRsZTonYnV5J30p"));

使用Packer加密

加密前

function a(e){/* ... */console.log(e.title)}a({title:'buy'})

加密后

eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('3 0(1){4.5(1.2)}0({2:\'6\'})',7,7,'a|e|title|function|console|log|buy'.split('|'),0,{}))

0x02 使用uglifyjs和spidermonkey

上述方案后都有自己的缺陷,无法采用。于是开始尝试想利用现有的浏览器的解析引擎,先试着理解比人的语法树,然后在人家的语法树进行修改。

先从uglify开始,它是github上点赞最多的JS解析引擎。它的安装容易出现各种问题,此时您需要google寻求答案(百度上的不是很全)。

刚开始做这件事时,半就被叫停了,因为据说我们组之前有人用uglify做过,出现了很多建荣祥问题,所以弃用。

于是我转战spidermonkey,他是火狐浏览器(firefox)自带的解析引擎。由C语言写成的。考虑到和现有系统的兼容,以及对指针操作的方便,我们选择C语言开发,而spidermonkey恰好是C语言开发的。

还是首先尝试使用它,使用时发现它的代码风格类似JNI,以下是我之前写的测试用例:

学习spidermonkey的过程大量借助google,官方手册是一个很好地学习途径。贴一个参考链接:

https://wiki.mozilla.org/JavaScript:SpiderMonkey:Parser_API

spidermonkey引擎可帮助我们在C语言的环境下执行JacaScrpt代码,我认为在物联网设备中可以发挥很大的用途。代码使用JNI编写,JNI和普通的C开发区别其实不大,用熟悉了总结出模板以后可以直接用。这段脚本还包含了一些我曾经测试过的痕迹,显示出我曾试图去理解构建语法树的过程和各个参数的含义。 当时我分析了JS的解析和执行过程,它先生成tokenstream,我找出了这个的API,并找出了输入tokenstream,输出语法树的API。然后就开始分析语法树的生成过程。但因为这棵树确实比较复杂,看了两三天都没什么头绪,试图修改别人方案实现自己目的的想法也宣告失败了。

这里只简单记录一下spidermonkey的安装和使用容易忘记的步骤:核心文件在src文件夹下,如果编译以后.o文件在Linux_All_DBG.OBJ里,这个文件夹要配个环境变量。然后,手工移动一下一个头文件

mv /opt/js/src/Linux_All_DBG.OBJ/jsautocfg.h /opt/js/src/

这个方面网上的教程写的很清楚,只需要注意环境变量要配置。具体可参考这篇博客

https://www.cnblogs.com/chenfool/p/3840625.html


0x03 自己学习语法树的过程(学习方法的提升)

走投无路之下,只好自己写语法树了。我买了一本专用于考研的《王道数据结构》,写的比较精炼,推荐给大家。

说起数据结构,由于我本人并不是计算机科班出身,之前并没有接收系统的训练,只能从0开始一点点写起来。我最开始是从顺序表开始的,自己实现了它的插入算法和删除算法。顺序表类似数组,但没有指针域的。写完以后就觉得其实还挺简单的,对于刚入门的初学者难度适中。

接着就开始写二叉树了,通过实现一个简答的二叉树,我了解了数据域,指针域怎么分配,树是如何创建的,记得当时只用了不到一天写完了,很有成就感

如何学习新的知识:原来我是看一点,敲一点代码,理解一点,全部都敲完以后,似乎都懂了,其实印象不深,而且再让你写一遍还写不出来。

这里和大家分享我的导师明姐教我的学习方法,我认为是我自个项目最大的收获:先看一遍,然后自己写,不会的再回头去学。也许刚看完有很多你不会的,但是不要慌张,或者认为自己写不出来,必须全理解了才去做事。遇到不清楚的,自己试着写代码,速度,印象成倍提高,说不定回头看,你写的比教材里的还好。

原来就是看一点敲一点理解一点,太慢了,自从使用新方法后效率成倍增加。感谢我的导师,明姐,这个方法就是她教我的。只要她在安全领域保持5年以上的专注,她以后一定会成为安全圈叱咤风云的人物。希望你一直牛逼下去。乘胜追击写了二叉树的生成,写了二叉树的前序遍历,二叉树的层序遍历,队列的层序遍历,可以说理解了递归思想,和它的使用方法。


0x04 方案介绍

现在开始就是本文的重点了,我们的语法树体现了以下点子和技术:

1、使用兄弟孩子表示法,这个从二叉树衍生出的,我们用了这种结构来构建自己的语法树。

2、  结点回溯技术。如果一个根结点开始,树生长完后怎样回到最开始的根结点呢?通过结点回溯。怎么回溯?生成树的时候在指针域里加一个指向前一结点的指针 CBNODE * parent,不停得往回找,直到找到第一个左结点(长子结点)不为空,然后他的右结点(兄弟结点)。挺自豪的,自己的原创

3、 独创 “前序深度遍历”的概念,可以将指定深度的函数一次性全部拿出来,然后执行加密。

4、 修改语法树的方法:采用了结点替换技术,稍后讲到

5、  如何把整个funtion全都拎出来加密呢?根据前序遍历 “根,左,右”的顺序, 只要找到funtion,从那个结点开始做一个前序遍历,函数就全都出来了,

6、  如何将文件切按照一定的规律切成字符串。这里面的切割技术也是我们自己的想法。


我们的数据域是这样的:                                      


结点的数据域包含三个元素,id是反映了节点的创建顺序,data[]存储了单个字符串,depth则存储了函数的深度

结点的指针域中,有三个指针,firstchild是当前结点的长子结点,或叫左结点。nextsibling是当前结点的兄弟结点,或叫右结点。最后一个father指针指向上一个结点,即指向生成当前结点的那个节点。有人问为什么需要它,通过它,我们才实现了一个重要的功能:节点回溯。


如何生成树:

孩子兄弟表示法,是树型数据结构在的实际应用中用途最广的一种,

森林(图侵删)

森林转二叉树-孩子兄弟表示法 (图侵删)

首先设置一个CBNode型节点的指针,这个指针可以指向整棵树里当前我们试图操作的节点,它的作用类似于数组里的下标索引。 通过更新这个CBNode型指针的地址,始终让它指向当前结点。这样就可以:读取当前结点里的数据,或从当前结点的左节点或右结点开始开辟新内存空间,树得以延伸,生长。
语法树的生成规则:每次遇到{就将当前结点给长子结点开辟内存空间,在里面的数据域里填入数据{。每次遇到},就先把}放进当前结点的右结点里,然后通过节点回溯技术回到函数开始的地方。

结点的回溯。按照我们的设想,当一个function运行到最后时,需要回到这个function开始的地方,继续从他的孩子结点(右结点)进一步的延伸和生长。但是怎么回到原来开始的地方呢?我提出了“结点回溯”的概念:首先我们要在结点的指针域中引入“父指针”的指针,它始终要指向上一个生成它的结点。在生成语法树时就要完成这个操作。当我们遇到“}”符号时,我们就要通过这个父指针所形成的的单向链表,递归的往回追溯,直到回到这个function开始的地方。我没往回追溯一个结点,要看他的左结点是不是不为空,右结点是不是为空,因为往往function开头的节点,它的左节点一定不为空,二它的右结点一定为空。然而我们还得小心,当函数的深度增加后,你会发现满足上述条件的节点不止一个,如何避免和其他function的“}”去匹配,只匹配到本属于他的那个}就很重要。我们的回溯算法很好地解决了这个问题,如下图所示


我们之前还尝试过其他解决方法,比如想过要在做一个临时的结点,专门存贮下潜到下一层开始的那个结点,但是由于函数的深度是未知的,如果只开一个临时节点,将导致我们下潜到第k层时,第k-1层的开头结点会被覆盖,然后就回不去k-2,k-3..层了。除非我已经知道自己下潜到第几层,开辟多个临时节点,每当我深入下一层前就将上一层的入口存进来,但我必须知道我要开辟几个临时结点空间,这会带来临时节点的管理问题。不是不能做,也是一条思路,但是会让程序变复杂,不但开辟和释放变得复杂,而且可能还需要引入类似堆栈或者队列的数据结构,出于时间和空间复杂度的考虑,我就没这么做。


那么下一个问题是,如何确定当前结点是的深度点呢?我提出了前序深度遍历的概念:第一步是先生成语法树嘛,在生成前,就要在结点的数据域添加data->depth,让每一结点都具有它的深度信息。接着 通过设置一个全局变量, 在合适的时候在语法树下潜时自增,语法树上探时自减,同时将这个全局变量赋值给 data->depth,使得每个节点都具有合适的深度。
第二步,整体要做一次前序遍历,将所有特定深度函数开始的结点就是所有以function开头的全都保存在一个CBNode类型的指针所构成的数组内部。由于之前有了深度信息,很方便就能筛选出特定深度的函数结点,并存入一个指针数组内。
第三步,由于我们在学习数的过程中,写过二叉树前序遍历算法,由于前序遍历“根,左,右”的顺序,只要把函数开头节点输入前序遍历,就会发现,整个函数都遍历出来了。得益于前期的训练和积累,我们才发现了这个有趣的现象并加以利用。

节点替换
如果我能把特定深度的某一个函数拎出来,接下来该干什么就不用说了。加密处理后的函数该如何塞回去呢?我们又一次提出了自己的理解:节点替换。这个过程和逆向中JMP到一款空白内存,写下patch代码后,再JMP回原来的代码继续执行的思想理念是一致的。

什么意思呢?对于一个有长子的节点,我们从他的上一节点开始遍历,就能把整个{}里的内容全部遍历出来。这些恰好“可能”是一个完整的函数(或许是一个if语句,但是不是一个function只要判断一下就知道了)。这就为我们加密函数提供了绝佳的条件。因为如果能把这个“根节点”和原来整棵树的联系彻底“斩断”,然后开辟一个新的节点,在新的节点里塞入加密后的内容后,重新和这棵树建立连接,而新节点的内容是整个加密后的内容,就成功完成了节点的“替换”:展示一部分替换过程


有人说:为什么不把旧结点的内容改掉,然后切断它一系列孩子节点的联系呢,这样也替换了啊。我当初的设想是尽可能多的保存原始的节点,只要能完整保存下来,说不定下个版本针对这些被“抛弃”的节点进行优化。

这两种方案,本质上都是是修改语法树的结构来实现加密的。

节点替换后,加密函数节点依然和依附在语法树上,树的完整性得以保留,只要我们从根节点开始前序遍历,就能一次性把所有的文件都展现出来了,接着就能写入文件了。


最后就是字符切割,也就是把整个JS文件按照我们的想法切割成一个一个小的字符串的过程。这部分需要我们写一个简化的此法分析器。
我想,因为ES5里没有引入符号·,就是数字1左边那个按键表示符号,就想用它做切割符号
为了准确切割,不能受正则表达式的干扰,注释干扰,等等。我花了很多时间在这方面,看下代码好了
int readJS(char *path, char *data[]) {
    char *reciever = (char*)malloc(sizeof(char)*1024*1024*200);
    struct stat StatInfo; //当前文件或目录的信息
    if((stat(path,&StatInfo)) ==  -1)
    {
        Mylog_ERROR(__FILE__, __LINE__, "Can't Get File Info !!");
    }
    if(StatInfo.st_size/1024/1024> 1)
    {
        Mylog_ERROR(__FILE__, __LINE__, "Too Large To Parse !!");
        //return 0;
    }
    FILE *pf = fopen(path, "rt");
    if (NULL == pf) {
        Mylog_ERROR(__FILE__, __LINE__, "Read JS file falied!!");
        return 0;
    }

    printf("open js ok\n");

    int length = 0;
    int num = 0;
    char ch='K';//需要初始化
    reciever[0]='/';
    reciever[1]='*';
    reciever[2]='*';
    reciever[3]='/';
    length=4;
    while (ch != EOF)
    {
        ch = fgetc(pf);
        level1:
        if(ch == '\'')
        {
            reciever[length] = ch;
            length += 1;
            eee:
            ch = fgetc(pf);
            while(ch != '\'')
            {
                reciever[length] = ch;
                length += 1;
                ch = fgetc(pf);
            }
            if (reciever[length - 1] == '\\' ) //上个字符是转译字符,当前字符是/
            {
                if(reciever[length - 2]== '\\' && reciever[length - 3] != '\\')
                {
                    goto end1;
                }
                else
                {
                    reciever[length] = ch;
                    length += 1;
                    goto eee;
                }
            }
            end1:
            reciever[length] = ch;
            length += 1;
            continue;
        }
        if(ch == '\"')
        {
            reciever[length] = ch;
            length += 1;
            fff:
            ch = fgetc(pf);
            while(ch != '\"')
            {
                reciever[length] = ch;
                length += 1;
                ch = fgetc(pf);
            }
            if (reciever[length - 1] == '\\' ) //上个字符是转译字符,当前字符是/
            {
                if(reciever[length - 2]== '\\'&& reciever[length - 3] != '\\')
                {
                    goto end2;
                }
                else
                {
                    reciever[length] = ch;
                    length += 1;
                    goto fff;
                }
            }
            end2:
            reciever[length] = ch;
            length += 1;
            continue;
        }
        if (ch == ' ')
        {
            reciever[length] = ch;
            length += 1;
            ch = fgetc(pf);
            while(ch == ' ')
            {
                ch = fgetc(pf);
            }
            goto level1;
        }

        level2:
        if (ch == '{') {
            if(reciever[length-1]=='\a')
            {
                reciever[length] = ch;
                length += 1;
                reciever[length] = '\a';
                length += 1;
                continue;
            }
            reciever[length] = '\a';
            length += 1;
            reciever[length] = ch;
            length += 1;
            reciever[length] = '\a';
            length += 1;
            continue;
        }
        if (ch == '}') {
            if(reciever[length-1]=='\a')
            {
                reciever[length] = ch;
                length += 1;
                reciever[length] = '\a';
                length += 1;
                continue;
            }
            reciever[length] = '\a';
            length += 1;
            reciever[length] = ch;
            length += 1;
            reciever[length] = '\a';
            length += 1;
            continue;
        }
        if (ch == '\t') //|| ch == '\v' || ch == '\n'|| ch == '\r'
        {
            reciever[length] = ' ';
            length += 1;
            continue;
        }
//        if (ch == '\n'|| ch == '\r')
//        {
//            int a =1;
//            while (reciever[length - a] == ' ' || reciever[length - a] == '\n'|| reciever[length - a] == '\r'|| reciever[length - a] == '\t'||reciever[length - a] == '\a') { a+=1; }
//            if(reciever[length - a] == '}')
//            {
//                reciever[length] = '\n';
//                length += 1;
//                continue;
//            }
//            reciever[length] = ' ';
//            length += 1;
//            continue;
//        }
        if (ch == '/')
        {
            ch = fgetc(pf);
            int a = 1;
            while (reciever[length - a] == ' ' || reciever[length - a] == '\n'|| reciever[length - a] == '\r') { a+=1; }
            if ((reciever[length - a] == '=' && ch != '/'&& ch != '*') || (reciever[length - a] == '(' && ch != '/'&& ch != '*') || (reciever[length - a] == '&' && ch != '/'&& ch != '*')|| (reciever[length - a] == '|' && ch != '/'&& ch != '*')|| (reciever[length - a] == '!' && ch != '/'&& ch != '*')|| (reciever[length - a] == ':' && ch != '/'&& ch != '*')|| (reciever[length - a] == '[' && ch != '/'&& ch != '*')|| (reciever[length - a] == ',' && ch != '/'&& ch != '*')|| (reciever[length - a] == ';' && ch != '/'&& ch != '*'))
            {
                    reciever[length] = '/';
                    length += 1;
                    ddd:
                    while (ch != '/')
                    {
                        reciever[length] = ch;
                        length += 1;
                        ch = fgetc(pf);
                    }
                    if (reciever[length-1] == '\\' && reciever[length-2] != '\\')
                    {
                        reciever[length] = ch;
                        length += 1;
                        ch = fgetc(pf);
                        goto ddd;
                    }
                    reciever[length] = ch;
                    length += 1;
                    continue;
            }
            if(ch == '*')
            {
                ch = fgetc(pf);
                if(ch =='/')
                {
                    continue;
                }
                else
                {
                    bbb:
                    if (ch == '*')
                    {
                        ch = fgetc(pf);
                        if (ch == '/')
                        {
                            ch = fgetc(pf);
                            if (ch == EOF) { break; }
                            goto level1;
                        } else
                        {
                            goto bbb;
                        }
                    }
                    else
                    {
                        ch = fgetc(pf);
                        goto bbb;
                    }
                }
            }
            if (ch == '=')
            {
                reciever[length] = '/';
                length += 1;
                reciever[length] = ch;
                length += 1;
                continue;
            }
            if(ch == '/')
             {
                aaa:
                ch = fgetc(pf);
                if(ch == '\r' || ch =='\n')
                {
                    ch = fgetc(pf);
                    goto level1;
                }
                else if(ch ==EOF)
                {
                    break;
                }
                {
                    goto aaa;
                }
             }
            reciever[length] = '/';
            length += 1;
            goto level1;
        }

        reciever[length] = ch;
        length += 1;
        continue;
    }
    //从length-1开始需要用0填充,不填充的话length-1是一个?。
//    printf("HHHHHHHHHHHHH%c\n",reciever[length - 1]);
//    printf("HHHHHHHHHHHHH%c\n",reciever[length]);
//    printf("HHHHHHHHHHHHH%c\n",reciever[length + 1]);
    //加一个不影响语义的结束符,防止最后一个结点不存在
    reciever[length - 1] = '/';
    reciever[length] = '*';
    reciever[length + 1] = '*';
    reciever[length + 2] = '/';

    char *tmp = NULL;
    int i;
    for (i = 0; i < strlen(reciever); i++) //i= seqList->length -1 ; i >=index ; i --
    {
        tmp = &reciever[i];
        if (strncmp(tmp, "function", 8) == 0) {

            int a = 1;
            while (reciever[length - a] == ' ' || reciever[length - a] == '\n'|| reciever[length - a] == '\r') { a+=1; }
            if(reciever[length - a] == '(')
            {
                memmove(&reciever[length - a + 1], &reciever[length - a], strlen(&reciever[length - a]));
                reciever[length - a] = '\a';
                i = i-a+2;
                printf("warning:%c",reciever[i]);
                tmp = NULL;
                continue;
            }
//            if(reciever[length - a] == '=')
//            {
//                char *  backwordtoken1 = 0;
//            }
            memmove(&reciever[i + 1], &reciever[i], strlen(&reciever[i]));
            reciever[i] = '\a';
            i += 2;
            tmp = NULL;
            continue;
        }
//        if(reciever[i]== ' ')
//        {
//            while(reciever[i+1] ==' ')
//            {
//                memmove(&reciever[i + 1], &reciever[i+2], strlen(&reciever[i+2]));
//                //int end =;
//                reciever[ i+strlen(&reciever[i+1])]='\0';
//            }
//        }
//        if (reciever[i] == '\n'|| reciever[i] == '\r'|| reciever[i] == '\t' || reciever[i] == '\v')
//        {
//            reciever[length] = ' ';
//            length += 1;
//        }
        tmp = NULL;

    }
    //Mylog_INFO(__FILE__, __LINE__, "Before splite the string is:");
    //Mylog_INFO(__FILE__, __LINE__, reciever);

    char *result;
    result = strtok(reciever, "\a");

    while (result != NULL) {
        data[num] = result;
        result = strtok(NULL, "\a");
        num += 1;
    }
    fclose(pf);

    return num;

}
这部分怎么说呢。。。很坑爹。。能不自己写词法分析的童鞋尽量不自写把

0x05 结语

随着版本的迭代,以后也许会把语法树做的更复杂,让加密/混淆的效果更好。愿天下无贼(其实我是研究逆向技术为主的,希望多点时间研究逆向技术)。

我们的下一步计划是

给语法树增加更多的细节和功能。目前我们实现了对某层function全部加密,下一步我们要给语法树加入花指令。

感觉实现一个功能其实是比较简单的,关键是你有没有自己的想法或者解决问题巧妙的途径。

最后感谢我的导师,也是我的战友明姐,感谢她的指导,前期的顶层设计全部是明姐提出并实现的,我是从创建语法树那个函数开始接手的。虽然不知道你会不会看到这个,只要在安全行业保持专注,凭借出众的能力和优秀的性格和人品,她总有一天成为安全圈叱咤风云的人物。

这棵语法树现在还只是一颗小树苗。但在我们的努力下,它会成为一颗参天大数。全部只是刚刚开始。




[课程]FART 脱壳王!加量不加价!FART作者讲授!

最后于 2019-7-5 18:43 被r0Cat编辑 ,原因:
收藏
免费 2
支持
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  junkboy   +5.00 2018/11/10
最新回复 (12)
雪    币: 2575
活跃值: (487)
能力值: ( LV2,RANK:85 )
在线值:
发帖
回帖
粉丝
2
赞!
写的真不错
2018-11-10 20:15
0
雪    币: 11716
活跃值: (133)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
支持楼主和楼主的明姐
2018-11-10 20:41
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
4
junkboy 支持楼主和楼主的明姐
哇,JB大神又开直升机撒钱来了求包养~~
2018-11-10 20:47
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
5
wyfe 赞! 写的真不错
谢谢前辈
2018-11-10 20:48
0
雪    币: 3712
活跃值: (1386)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
6
赞,楼主可以给个demo嘛
2018-11-11 13:23
0
雪    币: 17
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
2019-1-10 21:22
0
雪    币: 1046
活跃值: (1261)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
8
JS加密我也调研过,jscrambler作为商业产品被各大厂商使用,而google 有一套recaptcha 的js 是完全虚拟机执行的,这套js的加密方法强度高,实现难度也大,针对加密的js场景也有限。 而js混淆实现起来比较简单,而我不推荐自己去写,因为很多细节你根本无法处理到,比如导出函数的排除,变量作用域分析啊,等等细节。。。。我推荐使用 https://github.com/javascript-obfuscator/javascript-obfuscator 这个遍历框架,然后自己继承写个自己的混淆方法即可。 
2019-1-29 14:04
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
9
StriveXjun JS加密我也调研过,jscrambler作为商业产品被各大厂商使用,而google 有一套recaptcha 的js 是完全虚拟机执行的,这套js的加密方法强度高,实现难度也大,针对加密的js场景也有 ...
的确是,js本身有不同的标准(ES5,6),语法也非常灵活,自己写AST可能遇到很多兼容性问题。不过javascript-obfuscator这个哭泣的大脑也不一定合适,一方面大量运用了typescript,对于本来就对js都不是很熟悉的安全研究者,会增加一些学习成本,另一方面是有些关键的代码也被“美化”了,导致初学者不好根据它做继承创新。。所以你觉得在安卓手机上做虚拟机保护可行吗,我很想听听你的想法,另一个是前辈有没有好的js测试用例
2019-1-29 22:00
0
雪    币: 1046
活跃值: (1261)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
10
amzilun 的确是,js本身有不同的标准(ES5,6),语法也非常灵活,自己写AST可能遇到很多兼容性问题。不过javascript-obfuscator这个哭泣的大脑也不一定合适,一方面大量运用了typescr ...
1.ts 完全兼容js语法,你可以在ts写js,所以不存在学习成本,反而你会觉得提高很多效率
2.不管是Android和IOS都可以用RN来写,这些主要的语法就是js,我已经测试过安卓的RN项目。同理只要适配js语法 不管是虚拟机执行和混淆都可行。 目前我的思路是 利用google v8 编译出 v8 bytecode,在用js写一套解释器感觉应该可行,目前我也正学习。
3.研究js加密也没多长时间,也没经过线上的发布,js测试用例这方面我本人经验也不足。前辈不敢当,我也初学的菜鸟,大家互相交流学习经验。
2019-1-30 11:10
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
11
StriveXjun 1.ts 完全兼容js语法,你可以在ts写js,所以不存在学习成本,反而你会觉得提高很多效率 2.不管是Android和IOS都可以用RN来写,这些主要的语法就是js,我已经测试过安卓的RN项目。同 ...
我对这方面真的了解也不多,说实话您的建议也让我大开眼界,我正按您说的在做,
2019-2-13 14:50
0
雪    币: 1700
活跃值: (676)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
老铁研究的怎么样了
2019-9-17 21:40
0
雪    币: 10
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
好东西
2019-10-12 17:17
0
游客
登录 | 注册 方可回帖
返回
//