主頁 > 企業開發 > 反壓縮 js ,我的萬花筒寫輪眼開了,CV 能力大幅提升

反壓縮 js ,我的萬花筒寫輪眼開了,CV 能力大幅提升

2022-03-08 07:47:10 企業開發

前言

因為比較菜,所以經常需要讀一些別人的代碼學習學習,

有原始碼的代碼當然好,但是很多網站不開源,這些網站的 js 又都是打包壓縮過的,學習起來很難受,

所以我做了一個小工具,通過修改抽象語法樹,來處理這些打包壓縮過的 js,增強代碼可讀性,讓我們學習起來更容易,

如果再借助重定向線上 js 到本地 js,或者使用 chrome 自帶的 override 原始碼能力,甚至可以輕松除錯別人的線上代碼,

有了這個工具,我 CV 界大師兄的名號可謂實至名歸,

下面是這個工具的代碼倉庫:boompack,

需求

在此之前,其實面對這些壓縮過的 js 我是不太想做這個工具的,

通常使用 prettier 美化一下,然后慢慢磨就好了,

但是這次我面對的是一個 canvas 相關的 js,壓縮后的核心代碼使用 prettier 格式化之后有 2 萬多行,看到這份代碼之后人都麻了,

這里隨便寫個壓縮代碼示例來舉例:

function f() {
  var a = (c = 33, d = 12), b = 1, g = (e == 2 ? a === 1 && b == 1 || c == 1 && d == 1 && c == 4 : c = 2);
  for (var i; i < 10; i++)if (s < 1) s++
  return a = 2, d == 2, e = !1, e = !0
}

這份代碼其實并不算特別復雜,因為沒有十幾個邏輯運算式和三元運算交雜在一起,

但是這份代碼很典型,因為基本上比較影響閱讀的點都有,

我們簡單列一下:

  • 大量無意義的單字符變數,修改變數名也無法批量替換
  • 序列運算式很多,即大量陳述句以逗號分隔,除錯時只算做一行代碼
  • 多個邏輯運算式混雜不清,需要改為 if 運算式
  • if 或者 for 回圈不加花括號
  • 大量三元運算,需要使用 if 和 else
  • !0 和!1 的表達反人類,需要使用 true 和 false
  • return 陳述句結合序列運算式,實際上只回傳最后一個

這些就是主要的困難,特別是當它們各種互相嵌套,又和十幾個邏輯運算和三元運算交雜在一起,光是拆解出來就得花個十幾分鐘,

如果人力拆解這些代碼,也不是沒有好處,至少你可以化身人肉低端編譯器,反復鞏固 js 基礎,要是碰到一些奇葩公司讓你手寫代碼你就是王者,

但是因為我需要留出時間打游戲的原因,所以還是寫了這么個工具簡化流程,

使用方法

  • 克隆倉庫到本地后
  • yarn install 安裝依賴包
  • 將需要轉換地壓縮代碼,復制粘貼到test/from/index.js這個檔案中
  • 終端運行腳本 yarn start
  • 最侄訓在test/to/這個檔案夾下生成 index.js,也就是我們最后修改后的檔案,

效果

使用工具轉換后的 js 代碼如下:

function func_f() {
  let var_a, var_b, var_g;
  c = 33;
  var_a = d = 12;
  var_b = 1;

  if (e == 2) {
    if (var_a === 1 && var_b == 1) {
      if (var_a === 1) {
        var_g = var_b == 1;
      } else {
        var_g = var_a === 1;
      }
    } else {
      if (c == 1 && d == 1) {
        var_g = c == 4;
      } else {
        if (c == 1) {
          var_g = d == 1;
        } else {
          var_g = c == 1;
        }
      }
    }
  } else {
    var_g = c = 2;
  }

  for (var var_i; var_i < 10; var_i++) {
    if (s < 1) {
      s++
    }
  }
  let result;
  var_a = 2;
  d == 2;
  e = false;
  result = e = true;
  return result;
}

可以看到相對于壓縮后的代碼,我們轉換后的代碼變長了很多,

這份代碼相較于上一份,可讀性大大增強了,

另外我已經使用 jQuery 壓縮后的檔案測驗過了,轉換沒有任何問題,

然而,依然不保證轉換后的代碼一定正確,js 的 hack 玩法太多,只能說用這個轉換肯定可控,

核心玩法:抽象語法樹

想要決議修改這種壓縮 js,需要用到我們的抽象語法樹,

所謂抽象語法樹,實際上就是一種樹形結構來表示編程陳述句,

具體可以百度,這里不解釋太多,總之你可以理解為可以將一串代碼決議成一個樹形結構,這個樹形結構上面每個節點代表一種語法結構,

這里列一個必備網站:https://astexplorer.net/,用來查看 js 被轉換為抽象語法樹后的樣子,

現在前端的基礎庫 babel 系列,就是通過抽象語法樹將 es6 轉換為 es5 的,當然也包括轉換 reacttypescript

因為抽象語法樹和代碼之間是可以相互轉換的,

所以我們的核心思路是將代碼轉換為抽象語法樹,然后在這個樹上做修改,修改完后再轉換為代碼,

應用 recast 去轉換代碼

js 代碼和抽象語法樹的轉換有很多 js 庫可以實作,

比如@babel/parserrecast,還有不少其他的庫,這里我們使用 recast

我對這個研究也不深入,沒怎么了解他們的優缺點,不過當時看到 recast滿足需求就直接用了,

可以在 npmjs 上找到 recast,里面有簡單的介紹檔案:地址,也有倉庫地址,

但是 recast 的檔案不太夠,有的關鍵點還得自己看下具體的示例和原始碼才能弄明白,不過也不難,

這里就不展開了,先上一段我自己寫的簡單代碼:

import { parse, print } from "recast";
import { readFile, writeFile } from "fs";
import path from "path";
import modifyAst from "./utils/modifyAst.js";

const fromPath = path.join("./test/from/index.js");
const toPath = path.join("./test/to/index.js");

readFile(fromPath, { encoding: "utf8" }, (err, sourceCode) => {
    // 通過recast的parse函式轉換為ast語法樹
    const ast = parse(sourceCode);
    modifyAst(ast);
    writeFile(toPath, print(ast).code, () => {
        console.info("搞完");
    });
});

這段代碼的用處是從 from 檔案夾下的檔案獲取 js 代碼后,通過 recastparse 函式轉換為 ast語法樹 ,再通過我自定義的函式 modifyAst 來修改語法樹后,最后使用 recastprint 函式將 ast語法樹 轉換為 js 代碼,

這段內容比較簡單,主要就是借助 recast 將代碼轉成抽象語法樹,再轉回代碼,

具體修改抽象語法樹在 modifyAst 里面:

import addBlock from "./addBlock.js";
import modifyReturn from "./modifyReturn.js";
import modifyUnaryExpression from "./modifyUnaryExpression.js";
// 修改宣告中的運算式
import replaceVarName from "./modifyVariableDeclaration/replaceVarName.js";
import modifyDeclarationInit from "./modifyVariableDeclaration/modifyDeclarationInit.js";

// 修改運算式
import modifyExpressionStatement from "./modifyExpressionStatement/index.js";

/**
* 修改抽象語法樹
*/
const modifyAst = (ast) => {
  modifyUnaryExpression(ast);
  replaceVarName(ast);
  addBlock(ast);
  modifyReturn(ast);
  modifyDeclarationInit(ast);
  modifyExpressionStatement(ast);
};

export default modifyAst;

modifyAst 中,我將不同的陳述句修改按照功能進行了劃分到,寫在了不同的檔案中,

本篇博客也不宜展開過多,我只挑一部分代碼展示:

import { types, visit } from "recast";

const { blockStatement } = types.builders;

/**
* 找到所有的if和for陳述句,給他們增加花括號
* @param {抽象語法樹} ast
*/
const addBlock = (ast) => {
  visit(ast, {
    // 找到所有的if陳述句給他們增加花括號
    visitIfStatement: function (path) {
      if (
        path.node.consequent != null &&
        path.node.consequent.type != "BlockStatement"
      ) {
        path.node.consequent = blockStatement([path.node.consequent]);
      }
      if (
        path.node.alternate != null &&
        path.node.alternate.type != "BlockStatement"
      ) {
        path.node.alternate = blockStatement([path.node.alternate]);
      }
      this.traverse(path);
    },
  });
};

export default addBlock;

上面這部分代碼的作用是遍歷抽象樹中所有的 if 陳述句,給那些沒加花括號的 if 陳述句加上花括號,

實際上就是使用 recastvisit 方法遍歷抽象語法樹,visitIfStatement 這個回呼函式,就是在遍歷到 if 陳述句后執行的函式,

在函式中有兩個 if 陳述句,那就是判斷以及修改的代碼,這個不多講,

需要注意的是,recast 遍歷抽象語法樹時,如果識別到 if 陳述句后,不會繼續遍歷這個 if 陳述句里包裹的 if 陳述句,所以這里使用

this.traverse(path);

這行代碼是用來繼續遍歷當前節點的子節點的,繼續往下找 if 陳述句,

如果你自己判斷出不需要向下遍歷,不能簡單地刪掉這段代碼,需要用這行代碼替換:

return false

回傳 false 表示不再向下遍歷,

另外如果此時想直接使用新陳述句替換當前陳述句,可以直接回傳一個新陳述句,例如:

return literal(true);

總結

總的來說,做完這個小工具算是解放了我大把的時間,

但是它只是我遇到典型壓縮代碼后,針對性進行更改的結果,可能遇到一些其他壓縮后的語法,效果不大好,您也可以針對相應語法自行修改,

當然,如果您有更好的方法和建議,也希望能不吝賜教,

作者:韓子盧
出處:https://www.cnblogs.com/vvjiang/
本博客文章均為作者原創,轉載請注明作者和原文鏈接,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/439177.html

標籤:其他

上一篇:革命性創新,影片殺手锏 @scroll-timeline

下一篇:如何使用jQuery在for回圈中將按鈕值從ejs發送到服務器?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more