国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

深入學(xué)習(xí) JavaScript 轉(zhuǎn)譯器 Babel ,AST還原混淆代碼

這篇具有很好參考價(jià)值的文章主要介紹了深入學(xué)習(xí) JavaScript 轉(zhuǎn)譯器 Babel ,AST還原混淆代碼。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

介紹

JavaScript 和 Babel 簡介

  1. JavaScript 是一種廣泛應(yīng)用于 Web 開發(fā)的腳本語言,它最初是由網(wǎng)景公司的 Brendan Eich 開發(fā)的。JavaScript 具有易學(xué)易用、靈活、動(dòng)態(tài)等特點(diǎn),它能夠幫助開發(fā)者在 Web 應(yīng)用中實(shí)現(xiàn)豐富的交互和動(dòng)態(tài)效果。

  2. 然而,由于 JavaScript 的語法和特性不斷更新,舊版的瀏覽器和環(huán)境可能無法完全支持新的 JavaScript 特性,這就使得開發(fā)者在編寫 JavaScript 代碼時(shí)需要考慮兼容性問題。為了解決這個(gè)問題,Babel 應(yīng)運(yùn)而生。

  3. Babel 是一個(gè) JavaScript 編譯器,它可以將最新版本的 JavaScript 代碼轉(zhuǎn)換成向下兼容的代碼,以便舊版的瀏覽器和環(huán)境可以運(yùn)行。Babel 的轉(zhuǎn)譯過程是基于 AST(抽象語法樹)的,它可以通過分析 AST 來理解源代碼的結(jié)構(gòu)和含義,然后進(jìn)行相應(yīng)的轉(zhuǎn)換。

  4. Babel 的使用非常靈活,可以通過命令行、Webpack、Rollup 等多種方式來集成到項(xiàng)目中。開發(fā)者可以根據(jù)自己的需求來配置 Babel,選擇需要的插件和預(yù)設(shè),從而實(shí)現(xiàn)對不同版本的 JavaScript 代碼的轉(zhuǎn)譯。同時(shí),Babel 還提供了許多插件和預(yù)設(shè),可以實(shí)現(xiàn)更加復(fù)雜的轉(zhuǎn)譯和擴(kuò)展功能,例如轉(zhuǎn)譯 JSX、ES6 模塊化、裝飾器等。

  5. 總之,Babel 是一個(gè)非常重要的 JavaScript 工具,它可以幫助開發(fā)者更加輕松地編寫和維護(hù)兼容性更好的 JavaScript 代碼,同時(shí)也為 JavaScript 社區(qū)的發(fā)展做出了重要貢獻(xiàn)。

Babel 的歷史和發(fā)展

  1. Babel 誕生于 2014 年,最初的名字是 6to5,它的初衷是為了解決 JavaScript 新特性向下兼容的問題。當(dāng)時(shí),ES6 標(biāo)準(zhǔn)已經(jīng)發(fā)布,但是很多瀏覽器和環(huán)境并不支持 ES6,這就使得開發(fā)者無法充分利用新特性。

  2. 6to5 利用了新的 JavaScript 特性,如箭頭函數(shù)、模板字符串等,將其轉(zhuǎn)換為舊的 ES5 代碼,以便兼容性更廣的瀏覽器和環(huán)境也能夠運(yùn)行。6to5 很快獲得了廣泛的關(guān)注和認(rèn)可,它的開發(fā)者們決定將其更名為 Babel,并將其轉(zhuǎn)變?yōu)橐粋€(gè)更加通用的 JavaScript 編譯器。

  3. 隨著時(shí)間的推移,Babel 逐漸發(fā)展成為一個(gè)功能強(qiáng)大、靈活易用的 JavaScript 工具。除了對新特性的轉(zhuǎn)譯,Babel 還可以處理 TypeScript、Flow、JSX 等不同的 JavaScript 方言。同時(shí),Babel 的插件系統(tǒng)也逐漸完善,開發(fā)者們可以自己編寫插件來定制轉(zhuǎn)譯過程,或者使用現(xiàn)成的插件來實(shí)現(xiàn)更加復(fù)雜的功能。

  4. 2015 年,Babel 正式發(fā)布了 6.0 版本,這個(gè)版本帶來了很多重要的變化,其中最顯著的是支持了 ES6 的新語法和特性,這使得開發(fā)者可以更加方便地使用 ES6 來編寫 JavaScript 代碼。此后,Babel 還不斷更新迭代,推出了支持 ES7、ES8 等新版本的 JavaScript 標(biāo)準(zhǔn)的轉(zhuǎn)譯,并增加了對一些實(shí)驗(yàn)性的 JavaScript 特性的支持。

  5. 目前,Babel 已經(jīng)成為了 JavaScript 社區(qū)中最流行、最重要的工具之一,它對 JavaScript 的發(fā)展和演進(jìn)做出了重要貢獻(xiàn)。

Babel 的優(yōu)勢和應(yīng)用場景

  1. 幫助解決兼容性問題:Babel 可以將最新版本的 JavaScript 代碼轉(zhuǎn)換為向下兼容的代碼,以便舊版的瀏覽器和環(huán)境可以運(yùn)行。這就幫助開發(fā)者解決了兼容性問題,使得開發(fā)者可以更加放心地使用最新的 JavaScript 特性來編寫代碼。

  2. 提高開發(fā)效率:Babel 可以自動(dòng)化地將新版本的 JavaScript 代碼轉(zhuǎn)換為向下兼容的代碼,使得開發(fā)者可以更加專注于編寫高質(zhì)量的代碼,而不需要考慮兼容性問題。這就大大提高了開發(fā)效率。

  3. 支持多種 JavaScript 方言:除了處理標(biāo)準(zhǔn)的 JavaScript 代碼,Babel 還可以處理 TypeScript、Flow、JSX 等不同的 JavaScript 方言。這就使得 Babel 成為了一個(gè)通用的 JavaScript 工具,能夠應(yīng)對各種不同的應(yīng)用場景。

  4. 插件系統(tǒng)功能強(qiáng)大:Babel 的插件系統(tǒng)非常靈活,可以自定義轉(zhuǎn)譯規(guī)則,也可以添加新的語法和特性。這就使得開發(fā)者可以根據(jù)自己的需求來配置 Babel,選擇需要的插件和預(yù)設(shè),實(shí)現(xiàn)對不同版本的 JavaScript 代碼的轉(zhuǎn)譯。

基于以上優(yōu)勢,Babel 的應(yīng)用場景非常廣泛,下面列舉幾個(gè)典型的應(yīng)用場景:

  1. 在前端開發(fā)中,Babel 可以幫助開發(fā)者更加方便地使用最新的 JavaScript 特性來編寫代碼,同時(shí)保證兼容性。例如,在使用 React 開發(fā) Web 應(yīng)用時(shí),Babel 可以將 JSX 轉(zhuǎn)換為 JavaScript 代碼。

  2. 在 Node.js 開發(fā)中,Babel 可以幫助開發(fā)者使用最新的 JavaScript 特性和方言,例如使用 TypeScript 來編寫 Node.js 應(yīng)用程序。同時(shí),Babel 還可以將 Node.js 應(yīng)用程序打包成支持多種環(huán)境的代碼。

  3. 在開發(fā)工具中,Babel 可以作為編譯器使用,例如將 JavaScript 代碼轉(zhuǎn)換為 ES5 或 ES6 代碼。同時(shí),Babel 還可以作為 Webpack 等構(gòu)建工具的插件,用于處理 JavaScript 代碼的轉(zhuǎn)譯和打包。

Babel 的原理和工作流程

Babel 的原理主要分為三個(gè)步驟:

  1. 解析(Parsing):Babel 首先會(huì)將 JavaScript 代碼解析成抽象語法樹(AST)。這個(gè)過程可以通過使用 Babylon 解析器或者其他支持解析 JavaScript 代碼的解析器來完成。解析的結(jié)果是一個(gè)包含 JavaScript 代碼的 AST。

  2. 轉(zhuǎn)換(Transformation):在轉(zhuǎn)換階段,Babel 將會(huì)遍歷 AST,對 AST 中的節(jié)點(diǎn)進(jìn)行修改或者刪除,并生成新的 AST。這個(gè)過程中,可以使用 Babel 插件來添加新的語法或者修改現(xiàn)有的語法。例如,可以使用 @babel/plugin-transform-arrow-functions 插件將 ES6 的箭頭函數(shù)轉(zhuǎn)換為 ES5 的函數(shù)表達(dá)式。

  3. 生成(Code Generation):在代碼生成階段,Babel 會(huì)將生成的新 AST 轉(zhuǎn)換回 JavaScript 代碼,并輸出到指定的文件中。這個(gè)過程中,Babel 會(huì)根據(jù)需要進(jìn)行縮進(jìn)和格式化,并且會(huì)將新生成的 JavaScript 代碼與原始代碼進(jìn)行比較,以便調(diào)試和測試。

安裝babel模塊

逆向解混淆,主要用到 Babel 的以下幾個(gè)功能包,本文也僅介紹以下幾個(gè)功能包:

  1. 安裝 Babel:運(yùn)行以下命令安裝 Babel 及其相關(guān)模塊:這里安裝了 @babel/core@babel/cli 兩個(gè)模塊,@babel/core 是 Babel 工具鏈的核心模塊,@babel/cli 是 Babel 命令行工具,可以在命令行中直接使用 Babel 進(jìn)行代碼轉(zhuǎn)譯等操作。
npm install @babel/core @babel/cli --save-dev
  1. 安裝 Babel 解析器:Babel 使用解析器將 JavaScript 代碼轉(zhuǎn)換為抽象語法樹(AST),以便進(jìn)行后續(xù)的轉(zhuǎn)換操作。運(yùn)行以下命令安裝 Babel 解析器:
npm install @babel/parser --save-dev
  1. 安裝 Babel 轉(zhuǎn)換器:Babel 使用轉(zhuǎn)換器對 AST 進(jìn)行轉(zhuǎn)換操作,可以添加、刪除、替換、修改節(jié)點(diǎn)等。@babel/traverse 是 Babel 提供的 AST 轉(zhuǎn)換工具,運(yùn)行以下命令進(jìn)行安裝:
npm install @babel/traverse --save-dev
  1. 安裝 Babel 代碼生成器:Babel 將轉(zhuǎn)換后的 AST 重新生成 JavaScript 代碼,以便進(jìn)行后續(xù)的編譯和執(zhí)行。@babel/generator 是 Babel 提供的 AST 代碼生成器,運(yùn)行以下命令進(jìn)行安裝:
npm install @babel/generator --save-dev
  1. 安裝 @babel/types 模塊,可以使用 npm 或 yarn 命令進(jìn)行安裝:
npm install @babel/types
  1. 安裝完成后,可以在項(xiàng)目中使用這些模塊進(jìn)行 JavaScript 代碼的轉(zhuǎn)譯、解析和生成等操作。例如,以下代碼演示了使用 Babel 解析器將一個(gè)字符串解析成 AST,并使用 Babel 代碼生成器將 AST 轉(zhuǎn)換成 JavaScript 代碼:
  2. 需要注意的是,Babel 的使用需要一定的編程經(jīng)驗(yàn)和 AST 知識(shí),因此建議在學(xué)習(xí) Babel 之前先掌握 JavaScript 和 AST 的相關(guān)知識(shí)。
const babelParser = require('@babel/parser');
const babelGenerator = require('@babel/generator').default;

const code = 'const a = 1;';
const ast = babelParser.parse(code);//將代碼解析成ast語法樹
const output = babelGenerator(ast, { /* options */ }, code);
console.log(output.code); // 輸出轉(zhuǎn)換后的代碼:const a = 1;

@babel/parser

解析代碼

@babel/parser 模塊提供了一個(gè)名為parse()的函數(shù),用于將 ECMAScript 代碼解析成 AST。該函數(shù)接受兩個(gè)參數(shù):

  • code:需要解析的代碼,一個(gè)字符串。

  • options:解析選項(xiàng),一個(gè)對象。

例如,以下代碼可以解析一個(gè)簡單的 ECMAScript 代碼片段,并打印出 AST:

const { parse } = require('@babel/parser');

const code = 'const x = 1 + 2;';
const ast = parse(code);
console.log(JSON.stringify(ast, null, 2));

解析選項(xiàng)

@babel/parser 模塊的parse()函數(shù)可以接受一個(gè)選項(xiàng)對象作為第二個(gè)參數(shù),用于指定解析器的行為。常用的選項(xiàng)包括:

  • sourceType:指定代碼的來源類型,可以為 “script” 或 “module”。默認(rèn)為 “script”。

  • plugins:指定解析器使用的插件列表,一個(gè)數(shù)組。默認(rèn)為空數(shù)組。

  • ranges:是否在 AST 節(jié)點(diǎn)中包含節(jié)點(diǎn)位置信息,一個(gè)布爾值。默認(rèn)為 false。

  • locations:是否在 AST 節(jié)點(diǎn)中包含源代碼位置信息,一個(gè)布爾值。默認(rèn)為 false。

  • onComment:指定解析器在解析注釋時(shí)執(zhí)行的回調(diào)函數(shù),一個(gè)函數(shù)。默認(rèn)為 null。

例如,以下代碼可以使用 sourceType 選項(xiàng)將代碼解析為 ES6 模塊:

const { parse } = require('@babel/parser');

const code = 'export const x = 1;';
const ast = parse(code, { sourceType: 'module' });

在這個(gè)例子中,我們使用 parse() 函數(shù)解析一個(gè) ES6 模塊,將 sourceType 選項(xiàng)指定為 "module"。

@babel/traverse

@babel/traverse 是一個(gè)用于對抽象語法樹(AST)進(jìn)行遞歸遍歷和更新的工具庫,它可以通過訪問和修改 AST 節(jié)點(diǎn)來實(shí)現(xiàn)代碼轉(zhuǎn)換。

下面是一個(gè)簡單的示例代碼,其中包含了使用 @babel/parser 將 JavaScript 代碼解析為 AST,并使用 @babel/traverse 對 AST 進(jìn)行遍歷和更新的過程。

const parser = require('@babel/parser');
const generator= require('@babel/generator').default
const traverse = require('@babel/traverse').default;

// 將 JavaScript 代碼解析為 AST
const ast = parser.parse(`
  const double = x => x * 2;
  const result = double(3);
`);

// 遍歷 AST,并對所有函數(shù)調(diào)用進(jìn)行修改
traverse(ast, {
  CallExpression(path) {
    // 如果當(dāng)前節(jié)點(diǎn)表示一個(gè)函數(shù)調(diào)用
    if (path.node.callee.name === 'double') {
      // 將函數(shù)名修改為 triple
      path.node.callee.name = 'triple';
      // 將函數(shù)調(diào)用的參數(shù)修改為原參數(shù)的兩倍
      path.node.arguments[0] = {
        type: 'NumericLiteral',
        value: path.node.arguments[0].value * 2,
      };
    }
  },
});

// 將修改后的 AST 轉(zhuǎn)換回 JavaScript 代碼
const code =generator(ast).code;

console.log(code);

在這個(gè)示例代碼中,我們首先使用 @babel/parser 將 JavaScript 代碼解析為 AST,然后使用 @babel/traverse 對 AST 進(jìn)行遞歸遍歷,并對所有函數(shù)調(diào)用進(jìn)行修改。具體來說,我們將函數(shù) double 的名稱修改為 triple,并將函數(shù)調(diào)用的參數(shù)修改為原參數(shù)的兩倍。最后,我們使用 @babel/generator 將修改后的 AST 轉(zhuǎn)換回 JavaScript 代碼,并輸出轉(zhuǎn)換后的代碼。




下面這個(gè)示例,它演示了如何使用 @babel/traverse 對 JavaScript 代碼進(jìn)行轉(zhuǎn)換,將 var 關(guān)鍵字替換成 const 關(guān)鍵字。

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;

const code = `
  var a = 1;
  var b = 2;
  var c = a + b;
`;

// 將 JavaScript 代碼解析為 AST
const ast = parser.parse(code);

// 遍歷 AST,并將所有 var 聲明替換成 const 聲明
traverse(ast, {
  VariableDeclaration(path) {
    if (path.node.kind === 'var') {
      path.node.kind = 'const';
    }
  },
});

// 將修改后的 AST 轉(zhuǎn)換回 JavaScript 代碼
const output = generator(ast, {}, code);

console.log(output.code);

在這個(gè)示例中,我們首先將 JavaScript 代碼傳入 @babel/parser,將其解析為 AST。然后我們使用 @babel/traverse 對 AST 進(jìn)行遍歷,遍歷過程中,我們判斷當(dāng)前節(jié)點(diǎn)是否為變量聲明節(jié)點(diǎn),如果是,則將節(jié)點(diǎn)中的 kind 屬性(即變量聲明的關(guān)鍵字)替換成 const。最后,我們使用 @babel/generator 將修改后的 AST 轉(zhuǎn)換回 JavaScript 代碼,并輸出轉(zhuǎn)換后的代碼。

值得注意的是,@babel/traverse 遍歷 AST 時(shí),它會(huì)對每個(gè)節(jié)點(diǎn)調(diào)用與節(jié)點(diǎn)類型對應(yīng)的方法。例如,在這個(gè)示例代碼中,我們使用了 CallExpression 方法,因?yàn)槲覀円獙λ泻瘮?shù)調(diào)用進(jìn)行修改。如果你要對其他類型的節(jié)點(diǎn)進(jìn)行遍歷和修改,可以參考 @babel/traverse 的文檔,查看支持的節(jié)點(diǎn)類型和相應(yīng)的方法名。

path對象

@babel/traverse模塊中,path 對象表示一個(gè)節(jié)點(diǎn)(node)在 AST 樹中的位置,提供了一些屬性和方法,用于訪問節(jié)點(diǎn)的屬性、子節(jié)點(diǎn)、父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)等,并且可以對 AST 樹進(jìn)行修改。下面是 path 對象的一些常用屬性和方法的詳細(xì)說明:

  • path.node
    nodepath 對象上的一個(gè)屬性,表示當(dāng)前節(jié)點(diǎn)的 AST 表示。node 對象包含了當(dāng)前節(jié)點(diǎn)的所有屬性和方法,你可以在鉤子函數(shù)中使用 path.node 訪問和修改節(jié)點(diǎn)的屬性和方法。

  • 例如,如果當(dāng)前節(jié)點(diǎn)是一個(gè)函數(shù)聲明(FunctionDeclaration),那么 path.node.id 就是函數(shù)的名字,path.node.params 就是函數(shù)的參數(shù)列表,path.node.body 就是函數(shù)的主體等。

  • path.parent
    parent path 對象上的一個(gè)屬性,表示當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。你可以使用 path.parent 訪問和修改當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn),也可以使用 path.parentPath 來獲取父路徑對象。

  • path.scope
    scopepath 對象上的一個(gè)屬性,表示當(dāng)前節(jié)點(diǎn)的作用域。作用域?qū)ο蟀水?dāng)前節(jié)點(diǎn)的變量聲明和函數(shù)聲明等信息。你可以使用 path.scope 訪問和修改當(dāng)前節(jié)點(diǎn)的作用域。

- path.get(key)
get() 是 path 對象上的一個(gè)方法,用于獲取當(dāng)前節(jié)點(diǎn)的指定子節(jié)點(diǎn)。你可以使用 path.get(key) 訪問當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn),其中 key 可以是一個(gè)屬性名、一個(gè)下標(biāo)或者一個(gè)函數(shù)。

  • 例如,如果當(dāng)前節(jié)點(diǎn)是一個(gè)函數(shù)調(diào)用(CallExpression),那么 path.get('callee') 就是獲取函數(shù)名節(jié)點(diǎn),path.get('arguments')[0] 就是獲取第一個(gè)參數(shù)節(jié)點(diǎn)。

  • path.traverse(visitor)
    traverse() path 對象上的一個(gè)方法,用于遍歷當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn),并調(diào)用鉤子函數(shù)處理子節(jié)點(diǎn)。你可以使用 path.traverse(visitor) 遍歷當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn),其中 visitor 是一個(gè)對象,包含了 enter 和 exit 兩個(gè)鉤子函數(shù)。

  • 例如,如果當(dāng)前節(jié)點(diǎn)是一個(gè)if語句(IfStatement),那么可以使用 path.get('consequent').traverse(visitor) 遍歷 if 語句的主體部分,并且在遍歷每個(gè)子節(jié)點(diǎn)時(shí)調(diào)用 enter exit 鉤子函數(shù)。

  • path.replaceWith(newNode)
    replaceWith() 是 path 對象上的一個(gè)方法,用于替換當(dāng)前節(jié)點(diǎn)。你可以使用 path.replaceWith(newNode) 來替換當(dāng)前節(jié)點(diǎn),其中 newNode 是一個(gè)新的節(jié)點(diǎn)。

  • 例如,如果當(dāng)前節(jié)點(diǎn)是一個(gè)變量聲明(VariableDeclaration),可以使用 path.replaceWith(t.expressionStatement(t.stringLiteral('new code'))) 替換當(dāng)前節(jié)點(diǎn)為一個(gè)新的表達(dá)式語句。

- path.remove()
remove() 是 path 對象上的一個(gè)方法,用于刪除當(dāng)前節(jié)點(diǎn)。你可以使用 path.remove() 刪除當(dāng)前

scope屬性

在Babel中,@babel/traverse模塊的path對象提供了一個(gè)scope屬性,代表當(dāng)前路徑節(jié)點(diǎn)的作用域。在遍歷語法樹時(shí),可以使用scope屬性來判斷當(dāng)前節(jié)點(diǎn)是否處于某個(gè)特定的作用域內(nèi),以及在這個(gè)作用域內(nèi)聲明的變量和函數(shù)。

scope對象包含一些屬性和方法,用于表示當(dāng)前節(jié)點(diǎn)的作用域信息,比如:

  • block:當(dāng)前節(jié)點(diǎn)所在的塊級作用域
  • path:當(dāng)前節(jié)點(diǎn)對應(yīng)的路徑
  • bindings:當(dāng)前作用域內(nèi)所有綁定(變量或函數(shù))的信息
    其中,bindings屬性是一個(gè)對象,它的鍵是所有在當(dāng)前作用域中定義的變量或函數(shù)名,值是綁定對象,代表這些變量或函數(shù)的定義信息,比如它們的類型、聲明的位置等。

bindings對象的值也是一個(gè)對象,包含了以下屬性:

  • kind:變量或函數(shù)的類型,可以是var、let、const、function等
  • path:該變量或函數(shù)的定義路徑
  • constantViolations:使用該變量或函數(shù)的非常量路徑
  • referencePaths:使用該變量或函數(shù)的所有路徑
  • referenced:是否被引用過
  • references:引用的路徑數(shù)量
    例如,下面的示例代碼演示了如何使用scope對象查找當(dāng)前作用域中所有的變量和函數(shù):
const babel = require('@babel/core');
const traverse = require('@babel/traverse').default;

const code = `
  const a = 1;
  function foo() {
    const b = 2;
    console.log(a, b);
  }
  foo();
`;

const ast = babel.parse(code);
traverse(ast, {
  enter(path) {
    const bindings = path.scope.bindings;
    console.log('Node:', path.node.type, 'Bindings:', Object.keys(bindings));
  }
});

在這個(gè)例子中,我們首先使用@babel/core模塊的parse方法將源代碼解析為AST。然后使用traverse方法遍歷AST,在遍歷每個(gè)節(jié)點(diǎn)時(shí)打印出它的類型和作用域信息。

在這個(gè)例子中,我們可以看到,在作用域中定義了a變量和foo函數(shù),它們都被存儲(chǔ)在bindings對象中,我們可以通過遍歷bindings對象來獲取這些變量和函數(shù)的信息。

bindings對象

每個(gè) scope 對象都有一個(gè)名為 bindings 的屬性,它是一個(gè)包含當(dāng)前作用域中所有綁定的對象。在 JavaScript 中,綁定指的是標(biāo)識(shí)符(Identifier)和值(Value)之間的關(guān)系。bindings 對象提供了一種獲取在當(dāng)前作用域中綁定的標(biāo)識(shí)符和它們的值的方式。

bindings 對象是一個(gè)包含鍵值對的對象,其中鍵是標(biāo)識(shí)符名稱,值是描述綁定的對象。描述綁定的對象包含有關(guān)綁定的信息,例如綁定所在的節(jié)點(diǎn)、綁定的類型(變量、函數(shù)等)以及綁定的范圍。此外,描述綁定的對象還提供了許多有用的方法,例如獲取綁定的類型、獲取綁定的值等。

以下是一個(gè)示例代碼,展示如何使用 bindings 對象獲取當(dāng)前作用域中的所有綁定:

const babel = require('@babel/core');
const t = require('@babel/types');
const traverse = require('@babel/traverse').default;

const code = `
  const foo = 1;
  function bar() {}
  console.log(foo + bar());
`;

const ast = babel.parseSync(code);

traverse(ast, {
  Program(path) {
    const { bindings } = path.scope;

    for (const name in bindings) {
      if (bindings.hasOwnProperty(name)) {
        console.log(`Binding: ${name}`);
        console.log(`Binding type: ${bindings[name].kind}`);
        console.log(`Binding value: ${bindings[name].path.node}`);
      }
    }
  },
});

在這個(gè)示例中,我們遍歷了 AST 并在 Program 節(jié)點(diǎn)上獲取了當(dāng)前作用域的 bindings 對象。然后,我們遍歷了 bindings 對象并打印了每個(gè)綁定的名稱、類型和值。注意,bindings[name].path.node 獲取到的是一個(gè) AST 節(jié)點(diǎn),如果想要獲取到節(jié)點(diǎn)對應(yīng)的值,需要使用 @babel/generator 模塊將其轉(zhuǎn)換為代碼。

const babel = require('@babel/core');
const t = require('@babel/types');
const traverse = require('@babel/traverse').default;

const code = `
  const foo = 1;
  function bar() {
    console.log(foo);
  }
`;

const ast = babel.parseSync(code);

traverse(ast, {
  FunctionDeclaration(path) {
    const { bindings } = path.scope;

    for (const name in bindings) {
      if (bindings.hasOwnProperty(name)) {
        console.log(`Binding: ${name}`);
        console.log(`Binding type: ${bindings[name].kind}`);
        console.log(`Binding value: ${bindings[name].path.node}`);

        // 獲取標(biāo)識(shí)符節(jié)點(diǎn)
        const identifier = bindings[name].identifier;
        console.log(`Identifier: ${identifier.name}`);

        // 獲取綁定的所有引用
        const references = bindings[name].referencePaths;
        for (const reference of references) {
          console.log(`Reference: ${reference.node}`);
        }
      }
    }
  },
});

在這個(gè)示例中,我們遍歷了 AST 并在FunctionDeclaration節(jié)點(diǎn)上獲取了當(dāng)前作用域的 bindings 對象。然后,我們遍歷了 bindings 對象并打印了每個(gè)綁定的名稱、類型和值。接著,我們使用 bindings[name].identifier 獲取了綁定的標(biāo)識(shí)符節(jié)點(diǎn),并使用 bindings[name].referencePaths 獲取了綁定的所有引用。注意,bindings[name].referencePaths 獲取到的是一個(gè)路徑數(shù)組,每個(gè)路徑都包含一個(gè)引用節(jié)點(diǎn)。

@babel/generator

@babel/generator 是 Babel 中負(fù)責(zé)將 AST 轉(zhuǎn)換回 JavaScript 代碼的模塊。它提供了一個(gè) default 方法,該方法接受一個(gè) AST 作為參數(shù),并返回轉(zhuǎn)換后的 JavaScript 代碼。

下面是一個(gè)簡單的示例,演示了如何使用 @babel/generator 將 AST 轉(zhuǎn)換回 JavaScript 代碼:

const generator = require('@babel/generator').default;

const ast = {
  type: 'Program',
  body: [
    {
      type: 'VariableDeclaration',
      kind: 'const',
      declarations: [
        {
          type: 'VariableDeclarator',
          id: { type: 'Identifier', name: 'x' },
          init: { type: 'NumericLiteral', value: 42 },
        },
      ],
    },
  ],
};

const code = generator(ast, {}, '');

console.log(code.code); // 輸出:const x = 42;

在這個(gè)示例中,我們首先定義了一個(gè) AST,它表示了一段簡單的代碼,其中包含一個(gè) const 聲明語句。然后,我們使用 @babel/generatordefault 方法將 AST 轉(zhuǎn)換回 JavaScript 代碼。由于我們不需要傳遞任何配置項(xiàng),所以第二個(gè)參數(shù)傳入一個(gè)空對象。最后,我們輸出轉(zhuǎn)換后的代碼。

除了 default 方法外,@babel/generator 還提供了一些其他方法,例如 generate 方法,它與 default 方法功能類似,但可以在不同的選項(xiàng)和插件配置下生成代碼。此外,還有 CodeGenerator 類,它可以在多個(gè) AST 轉(zhuǎn)換之間共享狀態(tài),以提高性能。

總之,@babel/generator 是一個(gè)非常有用的模塊,它讓你可以輕松地將 AST 轉(zhuǎn)換回 JavaScript 代碼,為你的代碼轉(zhuǎn)換工作提供了很大的便利。

@babel/types

@babel/types 模塊提供了一組用于操作 AST 的工具,包括 AST 節(jié)點(diǎn)類型的定義節(jié)點(diǎn)創(chuàng)建、節(jié)點(diǎn)判斷等功能。下面簡單介紹一下 @babel/types 模塊中的常用功能。

節(jié)點(diǎn)類型

@babel/types 模塊定義了 ECMAScript 代碼中的各種 AST 節(jié)點(diǎn)類型,例如 IdentifierBinaryExpression、BlockStatement 等。每個(gè)節(jié)點(diǎn)類型都是一個(gè) JavaScript 對象,包含該節(jié)點(diǎn)類型的屬性和方法。例如,Identifier 節(jié)點(diǎn)類型包含以下屬性:

  • type:節(jié)點(diǎn)類型,固定為 “Identifier”。

  • name:標(biāo)識(shí)符的名稱,一個(gè)字符串。

  • start:標(biāo)識(shí)符在源代碼中的起始位置(行號(hào)和列號(hào))。

  • end:標(biāo)識(shí)符在源代碼中的結(jié)束位置(行號(hào)和列號(hào))。

  • loc:標(biāo)識(shí)符在源代碼中的位置信息,包含 start 和 end 兩個(gè)屬性。

在使用 @babel/types 模塊時(shí),我們可以使用節(jié)點(diǎn)類型來創(chuàng)建新的節(jié)點(diǎn)或操作現(xiàn)有的節(jié)點(diǎn)。

節(jié)點(diǎn)創(chuàng)建

@babel/types 模塊提供了一組用于創(chuàng)建 AST 節(jié)點(diǎn)的工具函數(shù),例如 t.identifier(name)、t.binaryExpression(operator, left, right) 等。這些函數(shù)會(huì)返回對應(yīng)的節(jié)點(diǎn)對象,我們可以將它們用于構(gòu)建新的 AST。

例如,以下代碼可以創(chuàng)建一個(gè) VariableDeclaration 節(jié)點(diǎn):

const t        = require("@babel/types");

const variable = t.variableDeclaration(
  'const',
  [t.variableDeclarator(t.identifier('x'), t.numericLiteral(1))]
);

在這個(gè)例子中,我們使用 t.variableDeclaration 函數(shù)創(chuàng)建一個(gè) VariableDeclaration 節(jié)點(diǎn),其中指定了變量聲明的類型為 "const",變量名為 "x",初始值為 1。

節(jié)點(diǎn)判斷

@babel/types 模塊還提供了一組用于判斷 AST 節(jié)點(diǎn)類型的工具函數(shù),例如 t.isIdentifier(node)、t.isBinaryExpression(node) 等。這些函數(shù)會(huì)返回一個(gè)布爾值,用于判斷指定的節(jié)點(diǎn)對象是否屬于某個(gè)節(jié)點(diǎn)類型。

例如,以下代碼可以判斷一個(gè)節(jié)點(diǎn)是否為 CallExpression 類型:

const t    = require("@babel/types");

function isCallExpression(node) {
  return t.isCallExpression(node);
}

在這個(gè)例子中,我們定義了一個(gè)名為 isCallExpression 的函數(shù),它接受一個(gè)節(jié)點(diǎn)對象作為參數(shù),使用 t.isCallExpression 函數(shù)判斷該節(jié)點(diǎn)是否為 CallExpression 類型,并返回對應(yīng)的布爾值。

綜上所述,@babel/types 模塊提供了一組用于操作 AST 的工具函數(shù),可以用于創(chuàng)建、修改和判斷 AST 節(jié)點(diǎn)。我們可以使用它們來實(shí)現(xiàn)對 ECMAScript 代碼的轉(zhuǎn)換、分析和生成。

js代碼常見混淆方式

還原前

if (function (_0x48fd11, _0x52974e, _0x388e32) {
    function _0x549dad(_0x3d08e6, _0x563a9f, _0x32d68f, _0x935a1e, _0x2f5432, _0x11c4c1) {
        _0x563a9f = _0x563a9f >> 0x8,
        _0x2f5432 = 'po';
        var _0x868417 = 'shift',
        _0xca0acf = 'push',
        _0x11c4c1 = '?';
        if (_0x563a9f < _0x3d08e6) {
            while (--_0x3d08e6) {
                _0x935a1e = _0x48fd11[_0x868417]();
                if (_0x563a9f === _0x3d08e6 && _0x11c4c1 === '?' && _0x11c4c1['length'] === 0x1) {
                    _0x563a9f = _0x935a1e,
                    _0x32d68f = _0x48fd11[_0x2f5432 + 'p']();
                } else if (_0x563a9f && _0x32d68f['replace'](/[UOMPNTnblILJdPG=]/g, '') === _0x563a9f) {
                    _0x48fd11[_0xca0acf](_0x935a1e);
                }
            }
            _0x48fd11[_0xca0acf](_0x48fd11[_0x868417]());
        }
        return 0xf71c7;
    };
function _0x4f91(_0x162067, _0x2c1c19) {
    _0x162067 = ~~'0x'['concat'](_0x162067['slice'](0x1));
    var _0x1a4d27 = _0x235f[_0x162067];
    if (_0x4f91['MRYmFi'] === undefined) {
        (function () {
            var _0x27f542 = typeof window !== 'undefined' ? window : typeof process === 'object' && typeof require === 'function' && typeof global === 'object' ? global : this;
            var _0x5773e8 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            _0x27f542['atob'] || (_0x27f542['atob'] = function (_0x1405c4) {
                var _0x4321b2 = String(_0x1405c4)['replace'](/=+$/, '');
                for (var _0x6467c8 = 0x0, _0x11d027, _0x40e1d1, _0x4cecb2 = 0x0, _0x2fff1b = ''; _0x40e1d1 = _0x4321b2['charAt'](_0x4cecb2++); ~_0x40e1d1 && (_0x11d027 = _0x6467c8 % 0x4 ? _0x11d027 * 0x40 + _0x40e1d1 : _0x40e1d1, _0x6467c8++ % 0x4) ? _0x2fff1b += String['fromCharCode'](0xff & _0x11d027 >> (-0x2 * _0x6467c8 & 0x6)) : 0x0) {
                    _0x40e1d1 = _0x5773e8['indexOf'](_0x40e1d1);
                }
                return _0x2fff1b;
            });
        }
            ());
        function _0x5734d9(_0x57c809, _0x2c1c19) {
            var _0xef41ee = [],
            _0x110b95 = 0x0,
            _0x244795,
            _0x1bed23 = '',
            _0x4a92ec = '';
            _0x57c809 = atob(_0x57c809);
            for (var _0x2253d1 = 0x0, _0x212cb4 = _0x57c809['length']; _0x2253d1 < _0x212cb4; _0x2253d1++) {
                _0x4a92ec += '%' + ('00' + _0x57c809['charCodeAt'](_0x2253d1)['toString'](0x10))['slice'](-0x2);
            }
            _0x57c809 = decodeURIComponent(_0x4a92ec);
            for (var _0xb19e69 = 0x0; _0xb19e69 < 0x100; _0xb19e69++) {
                _0xef41ee[_0xb19e69] = _0xb19e69;
            }
            for (_0xb19e69 = 0x0; _0xb19e69 < 0x100; _0xb19e69++) {
                _0x110b95 = (_0x110b95 + _0xef41ee[_0xb19e69] + _0x2c1c19['charCodeAt'](_0xb19e69 % _0x2c1c19['length'])) % 0x100;
                _0x244795 = _0xef41ee[_0xb19e69];
                _0xef41ee[_0xb19e69] = _0xef41ee[_0x110b95];
                _0xef41ee[_0x110b95] = _0x244795;
            }
            _0xb19e69 = 0x0;
            _0x110b95 = 0x0;
            for (var _0x19db4a = 0x0; _0x19db4a < _0x57c809['length']; _0x19db4a++) {
                _0xb19e69 = (_0xb19e69 + 0x1) % 0x100;
                _0x110b95 = (_0x110b95 + _0xef41ee[_0xb19e69]) % 0x100;
                _0x244795 = _0xef41ee[_0xb19e69];
                _0xef41ee[_0xb19e69] = _0xef41ee[_0x110b95];
                _0xef41ee[_0x110b95] = _0x244795;
                _0x1bed23 += String['fromCharCode'](_0x57c809['charCodeAt'](_0x19db4a) ^ _0xef41ee[(_0xef41ee[_0xb19e69] + _0xef41ee[_0x110b95]) % 0x100]);
            }
            return _0x1bed23;
        }
        _0x4f91['FommKf'] = _0x5734d9;
        _0x4f91['WVWLXP'] = {};
        _0x4f91['MRYmFi'] = !![];
    }
    var _0x41c863 = _0x4f91['WVWLXP'][_0x162067];
    if (_0x41c863 === undefined) {
        if (_0x4f91['zUDdVD'] === undefined) {
            var _0x7cb49b = function (_0x43d3b2) {
                this['dBIiIv'] = _0x43d3b2;
                this['ZJxFPE'] = [0x1, 0x0, 0x0];
                this['DtEyxk'] = function () {
                    return 'newState';
                };
                this['StAszO'] = '\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';
                this['kCvLOW'] = '[\x27|\x22].+[\x27|\x22];?\x20*}';
            };
            _0x7cb49b['prototype']['MAUJkU'] = function () {
                var _0x1bf2d5 = new RegExp(this['StAszO'] + this['kCvLOW']);
                var _0x2af6bd = _0x1bf2d5['test'](this['DtEyxk']['toString']()) ? --this['ZJxFPE'][0x1] : --this['ZJxFPE'][0x0];
                return this['VQGnUA'](_0x2af6bd);
            };
            _0x7cb49b['prototype']['VQGnUA'] = function (_0x2eb9c4) {
                if (!Boolean(~_0x2eb9c4)) {
                    return _0x2eb9c4;
                }
                return this['YQnufA'](this['dBIiIv']);
            };
            _0x7cb49b['prototype']['YQnufA'] = function (_0x35a98e) {
                for (var _0x49c03f = 0x0, _0x367fd6 = this['ZJxFPE']['length']; _0x49c03f < _0x367fd6; _0x49c03f++) {
                    this['ZJxFPE']['push'](Math['round'](Math['random']()));
                    _0x367fd6 = this['ZJxFPE']['length'];
                }
                return _0x35a98e(this['ZJxFPE'][0x0]);
            };
            new _0x7cb49b(_0x4f91)['MAUJkU']();
            _0x4f91['zUDdVD'] = !![];
        }
        _0x1a4d27 = _0x4f91['FommKf'](_0x1a4d27, _0x2c1c19);
        _0x4f91['WVWLXP'][_0x162067] = _0x1a4d27;
    } else {
        _0x1a4d27 = _0x41c863;
    }
    return _0x1a4d27;
};

還原后

-----------------------------------非全部代碼------------------------------------------------------------------文章來源地址http://www.zghlxwxcb.cn/news/detail-472123.html

function getUrl(code, _0x3379ed, _0x46bf59) {
    var _0x524375 = null;
    var tp = new Date()["getTime"]();
    var key = CryptoJS["enc"]["Utf8"]["parse"](md5(pid + "-" + tp)["substring"](0x0, 0x10));
    var encryptedData = CryptoJS["AES"]["encrypt"](pid + "-" + tp, key, {
        "mode": CryptoJS["mode"]["ECB"],
        "padding": CryptoJS["pad"]["Pkcs7"]
    });
    $["ajax"]("/god/" + pid, {
        "async": _0x3379ed,
        "method": "POST",
        "dataType": "json",
        "data": {
            "t": tp,
            "sg": base64ToHex(encryptedData + ""),
            "verifyCode": code
        },
        "success": function (result) {
            if (result["url"] != null) {
                _0x524375 = dealUrl(result);
                _0x120e92 = _0x524375;
                lines["push"](_0x524375);
                _0x46bf59(result["url"]);
            } else {
                window["dp"]["notice"](result["error"], 0xbb8);
            }
        }
    });
    return _0x524375;
}

還原插件

  • 去除十六進(jìn)制編碼
function decodeHexString(ast) {
  traverse(ast, {
    StringLiteral(path) {
      path.get('extra').remove();
    }
  })

  code = generator(ast).code;
  ast= parser.parse(code);
  return ast;
}
  • 刪除未被引用變量
function removeUnusedVariables(ast){
  const visitor ={
      VariableDeclarator(path) {
          const {id} = path.node;
          const binding = path.scope.getBinding(id.name);

          //如果變量被修改過,則不能進(jìn)行刪除動(dòng)作。
          if (!binding || binding.constantViolations.length > 0) {
              return;
          }
          //長度為0,說明變量沒有被使用過。
          if (binding.referencePaths.length === 0) {
              path.remove();
          }
      },
  }
  traverse(ast,visitor);
  code = generator(ast).code;
  ast= parser.parse(code);
return ast;
}
  • 流程平坦化switch語句
function decodeSwitch(ast){
  for(let i = 0; i < 100; i++){
    traverse(ast, {
        MemberExpression(path) {
            if (t.isStringLiteral(path.node.object) &&
                    t.isStringLiteral(path.node.property, {
                        value: 'split'
                    })) {
                //找到類型為 VariableDeclaration 的父節(jié)點(diǎn)
                let varPath = path.findParent(function (p) {
                        return t.isVariableDeclaration(p);
                    });
                //獲取下一個(gè)同級節(jié)點(diǎn)
                let whilePath = varPath.getSibling(varPath.key + 1);
                //解析整個(gè) switch
                let myArr = [];
                whilePath.node.body.body[0].cases.map(function (p) {
                    myArr[p.test.value] = p.consequent[0];
                });

                let parentPath = whilePath.parent;
                varPath.remove();
                whilePath.remove();
                // path.node.object.value 取到的是 '1|2|4|7|5|3|8|0|6'
                let shufferArr = path.node.object.value.split("|");
                shufferArr.map(function (v) {
                    parentPath.body.push(myArr[v]);
                });
                path.stop();
            }
        }
    });
  }
  code = generator(ast).code;
  ast= parser.parse(code);
  return ast;

}

  • object 還原
function decodeObject(ast){
  const visitor ={
        VariableDeclarator(path) {
            const {id, init} = path.node;

            //特征判斷,對象為空則不處理
            if (!t.isObjectExpression(init) || init.properties.length === 0) return;

            let name = id.name;
            let scope = path.scope;

            for (const property of init.properties) {//遍歷key、value
                let key = property.key.value;
                let value = property.value;

                //一般ob混淆,key長度都是5,也有是3的,自行調(diào)整即可。
                if (key.length !== 5) return;

                //如果是字面量
                if (t.isLiteral(value)) {
                    scope.traverse(scope.block, {
                        //遍歷MemberExpression,找出與key相同的表達(dá)式
                        MemberExpression(_path) {
                            let _node = _path.node;
                            if (!t.isIdentifier(_node.object, {name: name})) return;
                            if (!t.isLiteral(_node.property, {value: key})) return;
                            _path.replaceWith(value);
                        },
                    })
                }
                //如果是函數(shù)表達(dá)式
                else if (t.isFunctionExpression(value)) {
                    let ret_state = value.body.body[0];

                    //特征判斷,如果不是return表達(dá)式
                    if (!t.isReturnStatement(ret_state)) continue;

                    scope.traverse(scope.block, {
                        CallExpression: function (_path) {

                            //遍歷CallExpression
                            let {callee, arguments} = _path.node;
                            if (!t.isMemberExpression(callee)) return;
                            if (!t.isIdentifier(callee.object, {name: name})) return;
                            if (!t.isLiteral(callee.property, {value: key})) return;
                            if (t.isCallExpression(ret_state.argument) && arguments.length > 0) {

                                //構(gòu)造節(jié)點(diǎn)
                                _path.replaceWith(t.CallExpression(arguments[0], arguments.slice(1)));
                            } else if (t.isBinaryExpression(ret_state.argument) && arguments.length === 2) {

                                //構(gòu)造節(jié)點(diǎn)
                                let replace_node = t.BinaryExpression(ret_state.argument.operator, arguments[0], arguments[1]);
                                _path.replaceWith(replace_node);
                            } else if (t.isLogicalExpression(ret_state.argument) && arguments.length === 2) {

                                //構(gòu)造節(jié)點(diǎn)
                                let replace_node = t.LogicalExpression(ret_state.argument.operator, arguments[0], arguments[1]);
                                _path.replaceWith(replace_node);
                            }
                        }
                    })
                }
            }
        },
    }
    traverse(ast,visitor);
    code = generator(ast).code;
  ast= parser.parse(code);
    return ast;
}

到了這里,關(guān)于深入學(xué)習(xí) JavaScript 轉(zhuǎn)譯器 Babel ,AST還原混淆代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Nike登錄的acw_sc__v2參數(shù)逆向詳細(xì)思路分析(非常簡單,建議入手)含AST解混淆代碼

    Nike登錄的acw_sc__v2參數(shù)逆向詳細(xì)思路分析(非常簡單,建議入手)含AST解混淆代碼

    最近周末閑著無事,看了一下Nike的登錄,發(fā)現(xiàn)連環(huán)境都不用補(bǔ)acw_sc__v2這個(gè)參數(shù),分享出來給大家趣味性娛樂一下 打開F12抓包看看登錄 老樣子復(fù)制curl給抓到Postman里面去分析一下 具體的參數(shù)查找就不演示了(就是簡單的刪參數(shù)看看啥需要啥不需要)。 最后可以發(fā)現(xiàn),cookie只

    2024年02月09日
    瀏覽(24)
  • AST混淆與解混淆筆記:逗號(hào)表達(dá)式混淆

    本文主要是作者記筆記為主,溫故而知新,記錄混淆和解混淆的代碼,后期可能會(huì)更新文章細(xì)節(jié) 以以下代碼為例: 首先導(dǎo)入庫 本次就是將return語句增加改為逗號(hào)表達(dá)式,來混淆部分閱讀邏輯 混淆后代碼如下: 還原混淆的代碼如下:

    2024年02月22日
    瀏覽(21)
  • vite下javascript-obfuscator 代碼混淆

    1.Vite混淆處理 項(xiàng)目環(huán)境:Vue3+Vite 1、安裝 或者 在打包時(shí)候還會(huì)報(bào)錯(cuò),需要安裝下面的依賴 2、引入 在vite.config.ts中引入插件,并進(jìn)行設(shè)置 3、配置項(xiàng)解釋 關(guān)于 rollup-plugin-obfuscator 插件的配置選項(xiàng)列表,每個(gè)選項(xiàng)都用于定制代碼混淆和壓縮的方式??梢詤⒖磈avascript-obfuscator 的配

    2024年02月19日
    瀏覽(21)
  • 帶你揭開神秘的javascript AST面紗之AST 基礎(chǔ)與功能

    作者:京東科技 周明亮 在前端里面有一個(gè)很重要的概念,也是最原子化的內(nèi)容,就是 AST ,幾乎所有的框架,都是基于 AST 進(jìn)行改造運(yùn)行,比如:React / Vue /Taro 等等。 多端的運(yùn)行使用,都離不開 AST 這個(gè)概念。 在大家理解相關(guān)原理和背景后,我們可以通過手寫簡單的編譯器,

    2023年04月12日
    瀏覽(23)
  • 代碼混淆與反混淆學(xué)習(xí)-第二彈

    代碼混淆與反混淆學(xué)習(xí)-第二彈

    deflat腳本鏈接:GitHub - cq674350529/deflat: use angr to deobfuscation 這里以代碼混淆與反混淆學(xué)習(xí)-第一彈中的OLLVM 混淆樣本為例進(jìn)行去除?!綥LVM-4.0】 控制流平坦前 控制流平坦后 python deflat.py --file main-bcf --addr 0x401180 deflat.py 成功去除后效果: 去混淆后,效果還算可以,能分析程序流程

    2023年04月09日
    瀏覽(43)
  • JavaScript補(bǔ)環(huán)境及AST實(shí)戰(zhàn)

    JavaScript補(bǔ)環(huán)境及AST實(shí)戰(zhàn)

    強(qiáng)烈推薦,適合爬蟲,js逆向,js逆向小白、爬蟲工程師、反爬工程師等等。 -----AST入門實(shí)戰(zhàn)+零基礎(chǔ)JavaScript補(bǔ)環(huán)境 采取直播 + 錄播形式。每節(jié)課時(shí)長約30-60分鐘,一共大概80集。預(yù)計(jì)3-4個(gè)月更新完畢。專用加密軟件播放,需綁定電腦,支持windows和蘋果系統(tǒng)。 感興趣者,私信本

    2024年02月16日
    瀏覽(16)
  • 黃皮書-線接觸熱彈流潤滑 Fortran+Matlab轉(zhuǎn)譯代碼

    黃皮書-線接觸熱彈流潤滑 Fortran+Matlab轉(zhuǎn)譯代碼

    原Fortran代碼有錯(cuò)誤,進(jìn)行了修改,數(shù)值上差別不大。根據(jù)Fortran代碼轉(zhuǎn)的Matlab,可以完美運(yùn)行,但是因?yàn)榫葐栴}有差異,只能說趨勢是一致的。 ? 需要私我-資源里只是Fortran運(yùn)行結(jié)果 ? ?

    2024年02月16日
    瀏覽(18)
  • 【機(jī)器學(xué)習(xí)】二分類問題中的混淆矩陣、準(zhǔn)確率、召回率等 (Python代碼實(shí)現(xiàn))

    【機(jī)器學(xué)習(xí)】二分類問題中的混淆矩陣、準(zhǔn)確率、召回率等 (Python代碼實(shí)現(xiàn))

    混淆矩陣(Confusion Matrix):將分類問題按照真實(shí)情況與判別情況兩個(gè)維度進(jìn)行歸類的一個(gè)矩陣,如在二分類問題中就是一個(gè)2*2的矩陣: TP(True Positive):表示實(shí)際為真預(yù)測為真 FP(False Positive):表示實(shí)際為假預(yù)測為真 (誤報(bào)) TN(True Negative):表示實(shí)際為假預(yù)測為假 FN(False N

    2024年01月24日
    瀏覽(62)
  • 網(wǎng)頁爬蟲逆向與AST入門系列教程(七、AST的應(yīng)用之代碼轉(zhuǎn)換)

    在前面的文章中,我們已經(jīng)介紹了AST的基本概念,生成方法以及在代碼混淆解析、反爬蟲技術(shù)解析和數(shù)據(jù)提取與分析中的應(yīng)用。在本篇中,我們將繼續(xù)探討AST在網(wǎng)頁爬蟲逆向中的另一個(gè)關(guān)鍵領(lǐng)域:代碼轉(zhuǎn)換。 1. 代碼轉(zhuǎn)換簡介 代碼轉(zhuǎn)換是指通過對代碼進(jìn)行解析、修改和重新生

    2024年02月12日
    瀏覽(25)
  • 機(jī)器學(xué)習(xí)模型優(yōu)劣評價(jià)指標(biāo):混淆矩陣,P-R曲線與平均精確度(附代碼實(shí)現(xiàn))

    機(jī)器學(xué)習(xí)模型優(yōu)劣評價(jià)指標(biāo):混淆矩陣,P-R曲線與平均精確度(附代碼實(shí)現(xiàn))

    文章參考:Mean Average Precision (mAP) Explained | Paperspace Blog 目錄 一. Confusion Metrics混淆矩陣 二.?Precision-Recall Curve, Average precision P-R曲線,平均精確度 三. 舉例與代碼實(shí)現(xiàn) (1)從預(yù)測分?jǐn)?shù)到類別標(biāo)簽(From Prediction Score to Class Label) (2)精確度-召回度曲線(Precision-Recall Curve) (3)平均

    2024年02月05日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包