IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Obfuscator 混淆学习 -> 正文阅读

[移动开发]Obfuscator 混淆学习

?前言

? ? ? ? ? 最近正式工作了,这段时间比较忙,上篇android脱壳机可能要等一段时间,不过看雪已经有人公布android7.1的脱壳机的源码了。之前验证了android8.1的脱壳,感觉android8.1增加了参数解引用的问题,会有一些坑点导致程序会crash。所以暂时先放弃android8.1,过段时间先复现android7.1的脱壳机。然后工作这段时间,有遇到js混淆,打算学习一下。

js混淆比较出名的工具就有Obfuscator,但是Obfuscator缺点在于平坦化做的一般,有些企业会自己做一下平坦化,再用Obfuscator来混淆。所以先学习Obfuscator很有必要性。

js混淆学习前置知识

? ? ? ? 建议先学习了解AST树和解析AST树的框架,可以先看下面的参考链接,补充前置知识。

Obfuscator混淆解析

? ? ? ? ?Obfuscator 在线混淆网站https://obfuscator.io/?底下有介绍相关混淆内容,这里直接看提供例子来解析的代码。

var _0x3ed0 = ['1241023ikpdYM', 'Hello\x20World!', '291190xIUkft', '1251274vQVPdI', '124952hgHyOi', '1983KQSSIW', '247DipWFn', '7354VgseoG', '49680CQWPxl', '1ZTWTUo', '648lISKkF'];

function _0x4ed9(_0x475ec5, _0x372034) {
  return _0x4ed9 = function (_0x3ed0df, _0x4ed9c4) {
    _0x3ed0df = _0x3ed0df - 0x96;
    var _0x5a22f3 = _0x3ed0[_0x3ed0df];
    return _0x5a22f3;
  }, _0x4ed9(_0x475ec5, _0x372034);
}

(function (_0xa942b4, _0x57410c) {
  var _0x4e4980 = _0x4ed9;

  while (!![]) {
    try {
      var _0x1e86fa = parseInt(_0x4e4980(0x9b)) + parseInt(_0x4e4980(0x9e)) + -parseInt(_0x4e4980(0x97)) + -parseInt(_0x4e4980(0x9c)) * -parseInt(_0x4e4980(0xa0)) + -parseInt(_0x4e4980(0x98)) * parseInt(_0x4e4980(0x9d)) + -parseInt(_0x4e4980(0x96)) + parseInt(_0x4e4980(0x99)) * parseInt(_0x4e4980(0x9a));

      if (_0x1e86fa === _0x57410c) break;else _0xa942b4['push'](_0xa942b4['shift']());
    } catch (_0x178fbf) {
      _0xa942b4['push'](_0xa942b4['shift']());
    }
  }
})(_0x3ed0, 0xb3f61);

function hi() {
  var _0x81b55a = _0x4ed9;
  console['log'](_0x81b55a(0x9f));
}

hi();

/*
source code
function hi() {
  console.log("Hello World!");
}
hi();
*/

暂时可以看出Obfuscator有如下特点:

1.大数组变量

2.位移大数组函数

3.自解密函数

由于代码较短,还未看出平坦化,不过不着急,先尝试把这个还原。

解析ast推荐在线网站:?https://astexplorer.net/

通过分析ast和混淆代码的分析,现在去混淆思路:

1.抠出自解密函数和解密函数的name

2.遍历调用函数和初始化赋值操作,获取解密函数的结果并且替代节点

3.修复函数调用方式,比如console['log']修复成console.log

修复办法:

1.使用ast来解析出body,转化成相关代码,获取到解密函数

2.遍历并判断调用解密函数的点,来进行获取最后结果

3.使用ast在线解析网站,对比二者不同,来进行修复

去混淆脚本如下

const fs=require('fs');
const parser=require('@babel/parser');
const traverse=require('@babel/traverse').default;
const types =require('@babel/types');
const generator=require('@babel/generator').default;
const { type } = require('os');
const { exit } = require('process');

var arguments=process.argv;
if(arguments.length<4)
{
  console.log("need input file and output file path");
  exit();
}
const inputFilePath = arguments[2];
const outputFilePath=arguments[3];

const jscode=fs.readFileSync(inputFilePath,
{
    encoding:"utf-8"
});

var globalArrayName;
var globalDecode;
var DecodeFunName;
var globalDecodeList=new Array();


/*

function getVariableName(path)
{
    var node = path.node;
    if(!types.isArrayExpression(node.init))
    {
      return;
    }
    //console.log(node.id.name);
    globalArrayName=node.id.name;
    
}
*/

function parserAst(ast)
{
    globalArrayName=ast.program.body[0].declarations[0].id.name;
    DecodeFunName=ast.program.body[1].id.name;
    globalDecodeList.push(DecodeFunName);
    var runCode=ast.program.body.slice(3,);
    ast.program.body=ast.program.body.slice(0,3);
    globalDecode=generator(ast).code;
    ast.program.body=runCode;
    return ast;
}

function getDecodeList(path) {
    var node=path.node;
    if(!types.isIdentifier(node.id)||!types.isIdentifier(node.init)||node.init.name!=DecodeFunName)
    {
        return;
    }
    globalDecodeList.push(node.id.name);
    path.remove();
}

function funToStr(path)
{
    var node =path.node;
    if (!types.isIdentifier(node.callee)||globalDecodeList.indexOf(node.callee.name)==-1)
    {
                return;
    }
    //console.log(path.toString());
    node.callee.name=DecodeFunName;
    let value = eval(globalDecode+path.toString());
    //console.log(value);
    path.replaceWith(types.valueToNode(value));
    
}

function fixFunCall(path)
{
    var node =path.node;
    if(!types.isIdentifier(node.property))
    {
        return;
    }
    let name =node.property.name;
    path.node.property=types.stringLiteral(name);
    path.node.computed=true;
}

function solveOb(ast)
{
    //eval(globalDecode);

    traverse(ast,{
        VariableDeclarator:getDecodeList,
        CallExpression:funToStr,
        MemberExpression:fixFunCall
      });
      return ast;
}

let ast=parser.parse(jscode);
ast=parserAst(ast);
ast=solveOb(ast);

let code=generator(ast).code;
console.log(code);

总结

? ? ? ? 多在ast在线网站查看相关数据,多加对比。后续会写长的代码来去混淆,使其体现出平坦化,并且让脚本尽量通用化。

参考链接

Js Ast一部曲:高完整度还原某V5的加密

https://bbs.nightteam.cn/thread-417.htm

??

????????

? ?

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:20:36  更:2021-07-27 16:22:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 11:08:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码