[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 即可获得。

关注我们

微信公众号:【趣码周

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用 Python 的 bytes 函数将 qt hex 字符串转换为 hex。例如: ``` qt_hex_string = '68656c6c6f' hex_string = bytes.fromhex(qt_hex_string).hex() print(hex_string) # 输出 '68656c6c6f' ``` 也可以使用 Python 的内置函数 int 将 qt hex 字符串转换为十进制整数,再使用 hex 函数将十进制整数转换为 hex 字符串。例如: ``` qt_hex_string = '68656c6c6f' decimal_integer = int(qt_hex_string, 16) hex_string = hex(decimal_integer) print(hex_string) # 输出 '0x68656c6c6f' ``` 希望这些信息对你有帮助。 ### 回答2: Qt,可以使用QString的静态函数`fromUtf8`将hex字符串转换为QString类型的字符串。然后再使用toUtf8函数将QString类型的字符串转换成QByteArray类型的字节数组。最后再使用QByteArray的toHex函数将字节数组转换为hex字符串。 示例代码如下: ```cpp QString hexString = "616263"; QByteArray byteArray = QByteArray::fromHex(hexString.toUtf8()); QString hexResult = byteArray.toHex(); ``` 上述代码,我们将"616263"这个hex字符串转换为字节数组byteArray,然后再将byteArray转换为hex字符串hexResult。最终输出的hexResult为"616263"。 需要注意的是,使用`fromUtf8`函数和`toUtf8`函数可以确保在字符串转换过程不会产生乱码。同时,使用`toHex`函数能够将字节数组转换为hex字符串。如果你需要将一个hex字符串转换为真正的16进制数值,可以使用`toUInt`函数将hex字符串转换为对应的无符号整数。 希望能够帮到你! ### 回答3: 在Qt,将十六进制字符串转换为十六进制数的方法如下: 1. 使用QString的函数 toLatin1() 将十六进制字符串转换为QByteArray。 2. 使用QByteArray的函数 fromHex() 将QByteArray转换为十六进制数。 下面是一个示例代码: ```cpp QString hexString = "7FFA"; // 将十六进制字符串转换为QByteArray QByteArray byteArray = QByteArray::fromHex(hexString.toLatin1()); // 将QByteArray转换为十六进制数 QString hexNumber = byteArray.toHex(); // 输出结果 qDebug() << hexNumber; // 输出 "7FFA" ``` 首先,我们使用 `toLatin1()` 函数将十六进制字符串转换为QByteArray。然后,我们使用 `fromHex()` 函数将QByteArray转换为十六进制数。 最后,我们使用 `toHex()` 函数将QByteArray转换回十六进制字符串,以便进行输出或其他操作。 请注意,使用此方法转换十六进制字符串时,输入的字符串应为有效的十六进制格式。如果字符串包含无效的字符(如字母O、I等),则可能会导致错误的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值