[AST插件篇]还原代码中的Unicode与Hex字符串

目录

插件说明

在 JS 逆向中,想要找到某个参数是怎么生成的,一般的套路就是,比如要找的参数是 w,那么我们直接使用 F12 打开 DevTools,然后使用 search 功能来搜索 w,但是往往有时候会一无所获,这是因为混淆的代码中,把字符串字面量都进行了编码,比如 Unicode编码(\u0077)hex编码(\x77),上面的编码例子都表示为 w

本文主要介绍以下三种常见情况:

  • 字符串的 Unicode 编码 \u0031\u0030\u0030\u0038\u0036
  • 字符串的 Hex 编码 \x31\x30\x30\x38\x36
  • 整型的 Hex 编码 0x2766

以上的 \u0031\u0030\u0030\u0038\u0036\x31\x30\x30\x38\x36 都表示字符串 "10086",而 0x2766 则表示的是 整数 10086

注意:文中出现以 A 结尾的即为混淆插件,以 B 结尾的即为还原插件

插件名称

  • UnicodeEscapeSequence
    • UnicodeEscapeSequenceA(混淆) 把字符串进行 Unicode 编码
    • UnicodeEscapeSequenceB(还原) 把 Unicode编码进行解码
  • HexEscapeSequence
    • HexEscapeSequenceA(混淆) 把字符串或整数进行 Hex 编码
    • HexEscapeSequenceB (还原) 把 Hex 编码进行解码

还原前后对比

UnicodeEscapeSequenceA,对正常内容进行 Unicode 编码混淆

Date.prototype.format = function (formatStr) {
    
    
  let str = formatStr;
  let Week = ["\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d"];
  str = str.replace(/yyyy|YYYY/, this.getFullYear());
  str = str.replace(/MM/, this.getMonth() + 1 > 9 ? (this.getMonth() + 1).toString() : "\u0030" + (this.getMonth() + 1));
  str = str.replace(/dd|DD/, this.getDate() + 1 > 9 ? (this.getDate() + 1).toString() : "\u0030" + (this.getDate() + 1));
  return str;
};

console.log(new Date().format("\u0079\u0079\u0079\u0079\u002d\u004d\u004d\u002d\u0064\u0064"));

UnicodeEscapeSequenceB,对 Unicode 混淆过的代码进行还原

Date.prototype.format = function (formatStr) {
    
    
  let str = formatStr;
  let Week = ["日", "一", "二", "三", "四", "五", "六"];
  str = str.replace(/yyyy|YYYY/, this.getFullYear());
  str = str.replace(/MM/, this.getMonth() + 1 > 9 ? (this.getMonth() + 1).toString() : "0" + (this.getMonth() + 1));
  str = str.replace(/dd|DD/, this.getDate() + 1 > 9 ? (this.getDate() + 1).toString() : "0" + (this.getDate() + 1));
  return str;
};

console.log(new Date().format("yyyy-MM-dd"));

HexEscapeSequenceA,对正常内容进行 Hex 编码混淆

Date.prototype.format = function (formatStr) {
    
    
  let str = formatStr;
  let Week = ["\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d"];
  str = str.replace(/yyyy|YYYY/, this.getFullYear());
  str = str.replace(/MM/, this.getMonth() + 0x1 > 0x9 ? (this.getMonth() + 0x1).toString() : "\x30" + (this.getMonth() + 0x1));
  str = str.replace(/dd|DD/, this.getDate() + 0x1 > 0x9 ? (this.getDate() + 0x1).toString() : "\x30" + (this.getDate() + 0x1));
  return str;
};

console.log(new Date().format("\x79\x79\x79\x79\x2d\x4d\x4d\x2d\x64\x64"));

HexEscapeSequenceB,对 Hex 混淆后的代码进行还原

Date.prototype.format = function (formatStr) {
    
    
  let str = formatStr;
  let Week = ["日", "一", "二", "三", "四", "五", "六"];
  str = str.replace(/yyyy|YYYY/, this.getFullYear());
  str = str.replace(/MM/, this.getMonth() + 1 > 9 ? (this.getMonth() + 1).toString() : "0" + (this.getMonth() + 1));
  str = str.replace(/dd|DD/, this.getDate() + 1 > 9 ? (this.getDate() + 1).toString() : "0" + (this.getDate() + 1));
  return str;
};

console.log(new Date().format("yyyy-MM-dd"));

混淆与还原思路

UnicodeEscapeSequence 插件的混淆与还原思路,我们先准备两行代码

var a = "yyyy-MM-dd"
var b = "\u0079\u0079\u0079\u0079\u002d\u004d\u004d\u002d\u0064\u0064"

把上述代码复制到 https://astexplorer.net/ AST 结构解析网站中,观察两个变量的初始化节点,分别如下

发现两个变量的 extra 中的 raw 不同,那么混淆以及还原的思路如下:

  1. 遍历 StringLiteral 节点
  2. 判断当前节点是否包含 extra 属性
    1. 如果是混淆就把编码内容赋值给 extra
    2. 如果要还原直接删除 extra 属性即可(官网手册查询得知,NumericLiteral、StringLiteral类型的extra节点并非必需,这样在将其删除时,不会影响原节点。

HexEscapeSequence 插件原理和 UnicodeEscapeSequence 插件的思路是一模一样的。

插件部分代码

UnicodeEscapeSequenceA.js

function fix(path) {
    
    
  const node = path.node;
  let value = node.value;
  if (node.extra && (/\\[ux]/gi.test(node.extra.raw) === false)) {
    
    
    value = str2unicode(value);
    node.extra.raw = '"' + value + '"';
  }
}

function str2unicode(str) {
    
    
  let unicodeStr = "", tmp;
  for (const val of str) {
    
    
    tmp = val.codePointAt(0).toString(16);
    while (tmp.length < 4) {
    
    
      tmp = '0' + tmp;
    }
    unicodeStr += "\\u" + tmp;
  }
  return unicodeStr;
}

UnicodeEscapeSequenceB.js

function fix(path) {
    
    
  const node = path.node;
  if (node.extra && /\\[ux]/gi.test(node.extra.raw)) {
    
    
    node.extra = undefined;
  }
}

完整代码

关注公众号【趣码周】回复 AST 即可获得。

关注我们

微信公众号:【趣码周

关注公众快速了解最新文章。

猜你喜欢

转载自blog.csdn.net/baoshuowl/article/details/125398736
今日推荐