用ChatGPT逆向工程壓縮后的Js代碼,表現(xiàn)驚艷 精華
互聯(lián)網(wǎng)世界里,每個開發(fā)者都有這么一個瞬間:你遇到一個炫酷的小組件,想知道它是怎么實現(xiàn)的,但源碼卻是最小化的,看起來全是亂碼。這時,你會怎么做?今天,F(xiàn)rank Fiegel要和大家分享一個非常時髦和實用的方法——用ChatGPT來逆向工程被壓縮的JavaScript代碼。
發(fā)現(xiàn)炫酷組件
在某個閑暇的夜晚,我無意間瀏覽到了一個網(wǎng)站,發(fā)現(xiàn)了一個非常有趣的組件(https://reactive.network/hackathon)。它展示了一個以ASCII藝術形式呈現(xiàn)的動態(tài)動畫,著實是令人眼前一亮。
動態(tài)效果
出于好奇,我決定深入研究它的實現(xiàn)。但當我打開源碼時,發(fā)現(xiàn)這些代碼被壓縮和最小化了,看起來十分費解。
const { floor: ra, abs: KE, min: QE } = Math,
O5 = ["reactive.network REACTIVE.NETWORK", "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,^`'. .:a–‘a(chǎn)–’a–“a–?"],
G7 = Date.now() % 3 ? O5[1] : O5[0],
V5 = G7.length,
JE = { fps: 60 };
function eT(e, t, n, r) {
const i = t.time * 8e-5,
s = QE(t.cols, t.rows),
o = t.metrics.aspect * 0.2,
l = { x: ((4 * (e.x - t.cols / 6.25)) / s) * o, y: (5 * (e.y - t.rows / 4)) / s },
u = ra(KE(YE(l) - i) * V5 + (ra(e.x / 1) % 2) * 2) % V5;
return G7[u];
}
const tT = () => {
const e = j.useRef(null),
[t, n] = j.useState({ height: null, width: null });
return (
j.useEffect(() => {
function r() {
n({ height: window.innerHeight, width: window.innerWidth });
}
if (typeof window < "u") return n({ height: window.innerHeight, width: window.innerWidth }), window.addEventListener("resize", r), () => window.removeEventListener("resize", r);
}, []),
j.useEffect(() => {
const r = e.current;
if (!r) return;
const i = 12,
s = ra(t.width / i) * 1.6,
o = ra(t.height / i),
l = { aspect: s / o },
u = setInterval(() => {
let c = "";
for (let d = 0; d < o; d++) {
for (let f = 0; f < s; f++) c += eT({ x: f, y: d }, { cols: s, rows: o, metrics: l, time: Date.now() });
c += `
`;
}
r.textContent = c;
}, 1e3 / JE.fps);
return () => clearInterval(u);
}, [t]),
a.jsx("div", { style: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }, children: a.jsx("div", { ref: e, style: { width: "100%", height: "100%", whiteSpace: "pre", overflow: "hidden" } }) })
);
};
function nT(e) {
return Math.cos(e.x * e.x - e.y * e.y);
}
const { floor: ia, abs: rT, min: iT } = Math,
D5 = ["reactive.network REACTIVE.NETWORK", "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,^`'. .:a–‘a(chǎn)–’a–“a–?"],
X7 = Date.now() % 3 ? D5[1] : D5[0],
F5 = X7.length,
sT = { fps: 60 };
function oT(e, t, n, r) {
const i = t.time * 8e-5,
s = iT(t.cols, t.rows),
o = t.metrics.aspect * 0.2,
l = { x: ((4 * (e.x - t.cols / 6.25)) / s) * o, y: (5 * (e.y - t.rows / 4)) / s },
u = ia(rT(nT(l) - i) * F5 + (ia(e.x / 1) % 2) * 2) % F5;
return X7[u];
}
const aT = () => {
const e = j.useRef(null),
[t, n] = j.useState({ height: null, width: null });
return (
j.useEffect(() => {
function r() {
n({ height: window.innerHeight, width: window.innerWidth });
}
if (typeof window < "u") return n({ height: window.innerHeight, width: window.innerWidth }), window.addEventListener("resize", r), () => window.removeEventListener("resize", r);
}, []),
j.useEffect(() => {
const r = e.current;
if (!r) return;
const i = 12,
s = ia(t.width / i) * 1.6,
o = ia(t.height / i),
l = { aspect: s / o },
u = setInterval(() => {
let c = "";
for (let d = 0; d < o; d++) {
for (let f = 0; f < s; f++) c += oT({ x: f, y: d }, { cols: s, rows: o, metrics: l, time: Date.now() });
c += `
`;
}
r.textContent = c;
}, 1e3 / sT.fps);
return () => clearInterval(u);
}, [t]),
a.jsx("div", { style: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }, children: a.jsx("div", { ref: e, style: { width: "100%", height: "100%", whiteSpace: "pre", overflow: "hidden" } }) })
);
},
使用ChatGPT逆向工程
通常情況下,我會耐心地閱讀這些亂成一團的代碼,嘗試理解其實現(xiàn)原理,或者找一個.map文件來還原原本的代碼。然而,這次我想到了一個新奇的辦法:為什么不讓ChatGPT幫我解讀這些代碼呢?
于是,我將以上代碼復制并詢問ChatGPT:“能解釋一下這段代碼嗎?”以下是它的回復:
概覽
代碼定義了幾個函數(shù)和組件,特別是用于React應用的。它主要處理生成一些動態(tài)文本內(nèi)容,可能是ASCII藝術或者使用預定義字符集的某些視覺效果。此外,它還包括事件處理、性能計時和HTML內(nèi)容轉換的實用工具函數(shù)。
核心組件和函數(shù)
- 字符集選擇:
const { floor: ra, abs: KE, min: QE } = Math;
const O5 = ["reactive.network REACTIVE.NETWORK", "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,^`'. .:a–‘a(chǎn)–’a–“a–?"];
const G7 = Date.now() % 3 ? O5[1] : O5[0];
const V5 = G7.length;
這部分代碼引入了一些常用的數(shù)學函數(shù),并定義了兩個字符集。基于當前的時間戳(Date.now() % 3),選擇其中一個字符集使用,并計算其長度。
- 動態(tài)字符選擇函數(shù):
function eT(e, t, n, r) {
const i = t.time * 8e-5;
const s = QE(t.cols, t.rows);
const o = t.metrics.aspect * 0.2;
const l = { x: ((4 * (e.x - t.cols / 6.25)) / s) * o, y: (5 * (e.y - t.rows / 4)) / s };
const u = ra(KE(YE(l) - i) * V5 + (ra(e.x / 1) % 2) * 2) % V5;
return G7[u];
}
eT函數(shù)根據(jù)輸入位置和當前時間生成字符。調(diào)整位置后,基于時間和位置選擇一個字符。
- React組件用于顯示動態(tài)內(nèi)容:
const tT = () => {
const e = j.useRef(null);
const [t, n] = j.useState({ height: null, width: null });
j.useEffect(() => {
function r() {
n({ height: window.innerHeight, width: window.innerWidth });
}
if (typeof window < "u") {
n({ height: window.innerHeight, width: window.innerWidth });
window.addEventListener("resize", r);
return () => window.removeEventListener("resize", r);
}
}, []);
j.useEffect(() => {
const r = e.current;
if (!r) return;
const i = 12;
const s = ra(t.width / i) * 1.6;
const o = ra(t.height / i);
const l = { aspect: s / o };
const u = setInterval(() => {
let c = "";
for (let d = 0; d < o; d++) {
for (let f = 0; f < s; f++) c += eT({ x: f, y: d }, { cols: s, rows: o, metrics: l, time: Date.now() });
c += `
`;
}
r.textContent = c;
}, 1e3 / JE.fps);
return () => clearInterval(u);
}, [t]);
return a.jsx("div", { style: { position: "absolute", top: 0, lef t: 0, width: "100%", height: "100%" }, children: a.jsx("d iv", { ref: e, style: { width: "100%", height: "100%", whiteSpa ce: "pre", overflow: "hidden" } }) });
};
這是一個React組件,設置一個間隔以定期更新div?元素的內(nèi)容。它根據(jù)窗口大小計算列和行數(shù),然后用動態(tài)生成的字符填充div。
將代碼轉換為TypeScript并變得可讀
我進一步要求ChatGPT將其中的代碼轉換為TypeScript,并使其更加可讀。以下是它的回復:
import React, { useEffect, useRef, useState } from 'react';
const selectedCharacterSet =
"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,^`'. .:a–‘a(chǎn)–’a–“a–?";
const characterSetLength = selectedCharacterSet.length;
const calculateCharacter = (
x: number,
y: number,
cols: number,
rows: number,
aspect: number,
time: number,
): string => {
const timeFactor = time * 0.000_08;
const size = Math.min(cols, rows);
const aspectRatio = aspect * 0.2;
const position = {
x: ((4 * (x - cols / 6.25)) / size) * aspectRatio,
y: (5 * (y - rows / 4)) / size,
};
const index =
Math.floor(
Math.abs(
Math.cos(position.x * position.x - position.y * position.y) -
timeFactor,
) *
characterSetLength +
(Math.floor(x) % 2) * 2,
) % characterSetLength;
return selectedCharacterSet[index];
};
type Size = {
height: null | number;
width: null | number;
};
const AsciiArtGenerator: React.FC = () => {
const textRef = useRef<HTMLDivElement>(null);
const [size, setSize] = useState<Size>({ height: null, width: null });
useEffect(() => {
const handleResize = () => {
setSize({ height: window.innerHeight, width: window.innerWidth });
};
// Initial size setting
handleResize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
useEffect(() => {
const element = textRef.current;
if (!element || !size.width || !size.height) return undefined;
const cols = Math.floor(size.width / 12) * 1.6;
const rows = Math.floor(size.height / 12);
const aspectRatio = cols / rows;
const intervalId = setInterval(() => {
let content = '';
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
content += calculateCharacter(
x,
y,
cols,
rows,
aspectRatio,
Date.now(),
);
}
content += '\n';
}
element.textContent = content;
}, 1_000 / 60); // 60 fps
return () => {
clearInterval(intervalId);
};
}, [size]);
return (
<div
ref={textRef}
style={{
height: '100%',
overflow: 'hidden',
whiteSpace: 'pre',
width: '100%',
}}
/>
);
};
export default () => {
return <AsciiArtGenerator />;
};
當我將ChatGPT生成的代碼與原始組件進行比較時,我發(fā)現(xiàn)輸出幾乎是完全一致的。雖然最初我認為LLM在復制代碼時忽略了一些實現(xiàn)細節(jié),但進一步調(diào)查發(fā)現(xiàn),問題很可能是字符編碼錯誤。還原正確字符后,輸出是完全一致的。
筆者嘗試使用當紅辣子雞Cursor來復現(xiàn)這一過程,看看是否能夠完成這一工作。以下是cursor生成的代碼,大家看chatGPT和Cursor Claude 3.5誰更勝一籌:
import React, { useRef, useState, useEffect } from 'react';
const ASCII_CHARS = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,^`'. .:■■□□";
const TEXT = "reactive.network REACTIVE.NETWORK";
const CHAR_SET = Math.random() < 0.67 ? ASCII_CHARS : TEXT;
const CHAR_LENGTH = CHAR_SET.length;
const FPS = 60;
function calculateChar(x, y, cols, rows, aspect, time) {
const scale = Math.min(cols, rows);
const adjustedX = ((4 * (x - cols / 6.25)) / scale) * aspect * 0.2;
const adjustedY = (5 * (y - rows / 4)) / scale;
const value = Math.cos(adjustedX * adjustedX - adjustedY * adjustedY);
const index = Math.floor(Math.abs(value - time * 8e-5) * CHAR_LENGTH + (Math.floor(x) % 2) * 2) % CHAR_LENGTH;
return CHAR_SET[index];
}
const AsciiAnimation = () => {
const containerRef = useRef(null);
const [dimensions, setDimensions] = useState({ height: null, width: null });
useEffect(() => {
const updateDimensions = () => {
setDimensions({ height: window.innerHeight, width: window.innerWidth });
};
if (typeof window !== 'undefined') {
updateDimensions();
window.addEventListener('resize', updateDimensions);
return () => window.removeEventListener('resize', updateDimensions);
}
}, []);
useEffect(() => {
const container = containerRef.current;
if (!container) return;
const cellSize = 12;
const cols = Math.floor(dimensions.width / cellSize) * 1.6;
const rows = Math.floor(dimensions.height / cellSize);
const aspect = cols / rows;
const animationInterval = setInterval(() => {
let frame = '';
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
frame += calculateChar(x, y, cols, rows, aspect, Date.now());
}
frame += '\n';
}
container.textContent = frame;
}, 1000 / FPS);
return () => clearInterval(animationInterval);
}, [dimensions]);
return (
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }}>
<div ref={containerRef} style={{ width: '100%', height: '100%', whiteSpace: 'pre', overflow: 'hidden' }} />
</div>
);
};
export default AsciiAnimation;
最后,不得不承認,LLM正變得越來越強大,它不僅能夠進行復雜的代碼解釋,還能幫你逆向實現(xiàn)一些非常實用的功能??梢灶A見未來還會有更多用途被挖掘出來,大家拭目以待。
參考:https://glama.ai/blog/2024-08-29-reverse-engineering-minified-code-using-openai
本文轉載自 ??AI工程化??,作者: ully
