時(shí)間:2023-07-12 15:24:01 | 來源:網(wǎng)站運(yùn)營
時(shí)間:2023-07-12 15:24:01 來源:網(wǎng)站運(yùn)營
用虛擬機(jī)opcode保護(hù)JS源碼:JS代碼保護(hù),有多種方式,如常規(guī)的JS混淆加密、如bytecode化、又或如虛擬機(jī)化。push apush bpush ccall funpop
這是古老的asm語法,沒錯,js代碼可以轉(zhuǎn)為此種形式,而且,可以更進(jìn)一步,轉(zhuǎn)為opcode,如上述asm代碼,如果將push、pop等字符替換為數(shù)字的操作碼,假設(shè)push為20,call為30,pop為40,形態(tài)可以變成:20,1,20,20,3,30,4,40
如果我們的JS代碼,變成了這樣的數(shù)字,誰能理解它的代碼邏輯和作用嗎?const I = { CONST: 1, ADD: 2, PRINT: 3, HALT: 4, CALL: 5, RETURN: 6, LOAD: 7, JUMP_IF_ZERO: 8, JUMP_IF_NOT_ZERO: 9, SUB: 10, MUL: 11,};
虛擬機(jī)的核心的部分,則是根據(jù)指令進(jìn)行相應(yīng)的堆棧操作,如://循環(huán)執(zhí)行 switch (instruction) { //常量 case I.CONST: { //常量值 const op_value = code[ip++]; //存放到堆棧 stack[++sp] = op_value; console.log("const",stack) break; } case I.ADD: { const op1 = stack[sp--]; const op2 = stack[sp--]; stack[++sp] = op1 + op2; break; } //減法 case I.SUB: { //減數(shù) const op1 = stack[sp--]; //被減數(shù),都放在堆棧里 const op2 = stack[sp--]; //相減的結(jié)果,放到堆棧 stack[++sp] = op2 - op1; break; } case I.PRINT: { const value = stack[sp--]; builtins.print(value); break; } case I.HALT: { return; } //函數(shù)調(diào)用 case I.CALL: { //函數(shù)地址 const op1_address = code[ip++]; //參數(shù)個(gè)數(shù) const op2_numberOfArguments = code[ip++]; console.log(".....",op1_address,op2_numberOfArguments) //參數(shù)個(gè)數(shù)入棧 stack[++sp] = op2_numberOfArguments; //舊棧幀入棧 stack[++sp] = fp; //指令指針 stack[++sp] = ip; //console.log("call",stack);return //獨(dú)立的棧幀,從當(dāng)前堆棧指針處開始 fp = sp; //指令指針變化,開始執(zhí)行call函數(shù) ip = op1_address; break; } case I.RETURN: { const returnValue = stack[sp--]; sp = fp; ip = stack[sp--]; fp = stack[sp--]; const number_of_arguments = stack[sp--]; sp -= number_of_arguments; stack[++sp] = returnValue; break; } case I.LOAD: { //補(bǔ)償?shù)刂?,ip指向指令地址,通過補(bǔ)償值,獲得函數(shù)調(diào)用前壓入的參數(shù) const op_offset = code[ip++]; const value = stack[fp + op_offset]; //console.log(value);return stack[++sp] = value; break; } case I.JUMP_IF_NOT_ZERO: { const op_address = code[ip++]; const value = stack[sp--]; if (value !== 0) { ip = op_address; } break; } default: throw new Error(`Unknown instruction: ${instruction}.`); }
三、實(shí)例1, 10, 5, 7, 1, 3, 4, 7, -3,1, 1, 10, 9, 17, 1, 1, 6, 7, -3, 7, -3, 1, 1, 10, 5, 7, 1, 11, 6
看起來僅僅是些數(shù)字,先看效果,在虛擬機(jī)中執(zhí)行:function factorial(n) { if (n === 1) { return 1; } return n * factorial(n - 1);}const result = factorial(10);console.log(result);
將上述opcode轉(zhuǎn)換一個(gè)形式,把數(shù)字替換為前面講到過的匯編指令,會得到如下形式的類asm代碼:I.CONST, 10, I.CALL, /* factorial */ 7, 1, I.PRINT, I.HALT, I.LOAD, // factorial start,7指向的即是這里 -3, I.CONST, 1, I.SUB, I.JUMP_IF_NOT_ZERO, 17, I.CONST, 1, I.RETURN, /* n */ I.LOAD, -3, /* factorial(n - 1) */ I.LOAD, -3, I.CONST, 1, I.SUB, I.CALL, /* factorial */ 7, 1, I.MUL, I.RETURN, // factorial end
對照J(rèn)S源碼、虛擬機(jī)代碼,仔細(xì)閱讀,方能理解此段匯編代碼的含意,相應(yīng)的,也就可以理解opcode。1, 10, 5, 7, 1, 3, 4, 7, -3,1, 1, 10, 9, 17, 1, 1, 6, 7, -3, 7, -3, 1, 1, 10, 5, 7, 1, 11, 6
僅是一行,如果是大段大段的,或是夾雜在混淆加密保護(hù)過的JS代碼中,酸爽。關(guān)鍵詞:保護(hù),虛擬
客戶&案例
營銷資訊
關(guān)于我們
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。