luau-obfuscator 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +26 -8
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +26 -8
- package/generated/grammers.luau +3431 -5262
- package/generated/tests.luau +1947 -3184
- package/package.json +1 -1
- package/scripts/test.js +1 -3
- package/src/passes/StringsToExpressions.ts +6 -6
- package/src/passes/Vmify.ts +14 -9
- package/src/passes/vmify/compiler.ts +18 -0
package/dist/index.cjs
CHANGED
|
@@ -594,7 +594,7 @@ function splitByteChunks(bytes, min, max) {
|
|
|
594
594
|
return chunks.length > 0 ? chunks : [bytes];
|
|
595
595
|
}
|
|
596
596
|
function stringCharCall(bytes) {
|
|
597
|
-
return call(member(identifier("string"), "char"), bytes.map(
|
|
597
|
+
return call(member(identifier("string"), "char"), bytes.map(vmNumberLiteral));
|
|
598
598
|
}
|
|
599
599
|
function buildConcatChain(chunks) {
|
|
600
600
|
function build(lo, hi) {
|
|
@@ -625,7 +625,7 @@ function buildShuffledTables(chunks) {
|
|
|
625
625
|
for (let slot = 0; slot < n; slot++) {
|
|
626
626
|
order[storageOrder[slot]] = slot + 1;
|
|
627
627
|
}
|
|
628
|
-
const orderFields = order.map((slot) => positionalField(
|
|
628
|
+
const orderFields = order.map((slot) => positionalField(vmNumberLiteral(slot)));
|
|
629
629
|
return {
|
|
630
630
|
storeVar,
|
|
631
631
|
orderVar,
|
|
@@ -644,7 +644,7 @@ function buildForLoopStringExpr(chunks) {
|
|
|
644
644
|
localStatement(accVar, stringLiteral("")),
|
|
645
645
|
numericForStatement(
|
|
646
646
|
iVar,
|
|
647
|
-
|
|
647
|
+
vmNumberLiteral(1),
|
|
648
648
|
unary("#", identifier(orderVar)),
|
|
649
649
|
block([
|
|
650
650
|
assignmentStatement(
|
|
@@ -676,7 +676,7 @@ function buildRecursiveStringExpr(chunks) {
|
|
|
676
676
|
]),
|
|
677
677
|
returnStatement([
|
|
678
678
|
call(identifier(recName), [
|
|
679
|
-
binary("+", identifier(iParam),
|
|
679
|
+
binary("+", identifier(iParam), vmNumberLiteral(1)),
|
|
680
680
|
binary(
|
|
681
681
|
"..",
|
|
682
682
|
identifier(accParam),
|
|
@@ -688,7 +688,7 @@ function buildRecursiveStringExpr(chunks) {
|
|
|
688
688
|
return iife([
|
|
689
689
|
...stmts,
|
|
690
690
|
localFunctionStatement(recName, functionBody([functionParam(iParam), functionParam(accParam)], body)),
|
|
691
|
-
returnStatement([call(identifier(recName), [
|
|
691
|
+
returnStatement([call(identifier(recName), [vmNumberLiteral(1), stringLiteral("")])])
|
|
692
692
|
]);
|
|
693
693
|
}
|
|
694
694
|
function pickControlFlowStrategy() {
|
|
@@ -1783,6 +1783,23 @@ var VmCompiler = class {
|
|
|
1783
1783
|
captured = /* @__PURE__ */ new Set();
|
|
1784
1784
|
protoIdCounter = 0;
|
|
1785
1785
|
declToBinding = /* @__PURE__ */ new Map();
|
|
1786
|
+
/**
|
|
1787
|
+
* 실제로 프로그램이 참조하는 모든 전역 이름(사전 등록된 builtinGlobals +
|
|
1788
|
+
* 스코프 분석이 자동으로 찾아낸, 로컬/파라미터/업밸류로 안 풀리는 나머지 식별자
|
|
1789
|
+
* 전부)을 돌려준다. Vmify.ts가 이 목록으로 브릿지 테이블(globals)을 만든다.
|
|
1790
|
+
*
|
|
1791
|
+
* 예전엔 호출자가 넘긴 builtinGlobals 목록만 브릿지에 넣었는데, 그 목록에
|
|
1792
|
+
* 없는 전역(예: Roblox API나 실행기 전용 전역을 다 못 채운 경우)을 참조하면
|
|
1793
|
+
* 컴파일은 성공하지만 GETGLOBAL이 조용히 nil을 반환해서 "attempt to call a
|
|
1794
|
+
* nil value"로 터진다 — 게다가 원인이 VM 디스패치 쪽 스택에서만 보여서
|
|
1795
|
+
* "opcode 매핑이 깨졌나?" 하고 엉뚱한 곳을 의심하게 만든다. analyzeScopes는
|
|
1796
|
+
* 어차피 로컬/업밸류로 못 푸는 식별자를 전부 global 바인딩으로 잡아두므로,
|
|
1797
|
+
* builtinGlobals에 없던 이름도 여기 globalsByName에는 다 들어있다 —
|
|
1798
|
+
* 하드코딩된 허용목록 대신 이걸 그대로 쓰면 커버리지 문제 자체가 사라진다.
|
|
1799
|
+
*/
|
|
1800
|
+
getUsedGlobalNames() {
|
|
1801
|
+
return Array.from(this.analysis.globalsByName.keys());
|
|
1802
|
+
}
|
|
1786
1803
|
computeCaptured() {
|
|
1787
1804
|
for (const binding of this.analysis.bindings.values()) {
|
|
1788
1805
|
if (binding.kind === "global") continue;
|
|
@@ -3101,14 +3118,15 @@ function markRuntimeNumbersAsStructural(body) {
|
|
|
3101
3118
|
});
|
|
3102
3119
|
}
|
|
3103
3120
|
function runVmify(program, options) {
|
|
3104
|
-
const
|
|
3121
|
+
const builtinGlobals = options.builtinGlobals ?? DEFAULT_BUILTIN_GLOBALS;
|
|
3105
3122
|
const random = options.random ?? Math.random;
|
|
3106
3123
|
const opcodeMap = createOpcodeMap(random);
|
|
3107
3124
|
const names = generateVmNames(random);
|
|
3108
|
-
const compiler = new VmCompiler(program,
|
|
3125
|
+
const compiler = new VmCompiler(program, builtinGlobals, opcodeMap);
|
|
3109
3126
|
const topProto = compiler.compile();
|
|
3127
|
+
const usedGlobalNames = compiler.getUsedGlobalNames();
|
|
3110
3128
|
const globalsTable = table(
|
|
3111
|
-
|
|
3129
|
+
usedGlobalNames.map((name) => namedField(name, identifier(name)))
|
|
3112
3130
|
);
|
|
3113
3131
|
const runtimeSource = buildVmRuntimeSource(names, opcodeMap);
|
|
3114
3132
|
const runtimeProgram = import_luau_parser4.luauparser.parse(runtimeSource);
|
package/dist/index.d.cts
CHANGED
|
@@ -47,12 +47,12 @@ interface EncryptNumbersOptions {
|
|
|
47
47
|
|
|
48
48
|
interface VmifyOptions {
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
50
|
+
* 스코프 분석에 미리 등록해둘 전역 이름 시드 목록. 여기 없는 이름이라도 프로그램에서
|
|
51
|
+
* 실제로 참조되면(로컬/파라미터/업밸류로 안 풀리는 식별자는 전부) 스코프 분석이
|
|
52
|
+
* 자동으로 전역으로 잡아내므로, 브릿지 테이블은 이 옵션이 아니라
|
|
53
|
+
* VmCompiler.getUsedGlobalNames()(실제 사용된 전역 전체)로 만든다 — 옛날엔 이 목록에
|
|
54
|
+
* 없는 이름을 쓰면 컴파일은 되는데 GETGLOBAL이 조용히 nil을 반환해서
|
|
55
|
+
* "attempt to call a nil value"로 터졌었음.
|
|
56
56
|
*/
|
|
57
57
|
builtinGlobals?: readonly string[];
|
|
58
58
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -47,12 +47,12 @@ interface EncryptNumbersOptions {
|
|
|
47
47
|
|
|
48
48
|
interface VmifyOptions {
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
50
|
+
* 스코프 분석에 미리 등록해둘 전역 이름 시드 목록. 여기 없는 이름이라도 프로그램에서
|
|
51
|
+
* 실제로 참조되면(로컬/파라미터/업밸류로 안 풀리는 식별자는 전부) 스코프 분석이
|
|
52
|
+
* 자동으로 전역으로 잡아내므로, 브릿지 테이블은 이 옵션이 아니라
|
|
53
|
+
* VmCompiler.getUsedGlobalNames()(실제 사용된 전역 전체)로 만든다 — 옛날엔 이 목록에
|
|
54
|
+
* 없는 이름을 쓰면 컴파일은 되는데 GETGLOBAL이 조용히 nil을 반환해서
|
|
55
|
+
* "attempt to call a nil value"로 터졌었음.
|
|
56
56
|
*/
|
|
57
57
|
builtinGlobals?: readonly string[];
|
|
58
58
|
/**
|
package/dist/index.js
CHANGED
|
@@ -566,7 +566,7 @@ function splitByteChunks(bytes, min, max) {
|
|
|
566
566
|
return chunks.length > 0 ? chunks : [bytes];
|
|
567
567
|
}
|
|
568
568
|
function stringCharCall(bytes) {
|
|
569
|
-
return call(member(identifier("string"), "char"), bytes.map(
|
|
569
|
+
return call(member(identifier("string"), "char"), bytes.map(vmNumberLiteral));
|
|
570
570
|
}
|
|
571
571
|
function buildConcatChain(chunks) {
|
|
572
572
|
function build(lo, hi) {
|
|
@@ -597,7 +597,7 @@ function buildShuffledTables(chunks) {
|
|
|
597
597
|
for (let slot = 0; slot < n; slot++) {
|
|
598
598
|
order[storageOrder[slot]] = slot + 1;
|
|
599
599
|
}
|
|
600
|
-
const orderFields = order.map((slot) => positionalField(
|
|
600
|
+
const orderFields = order.map((slot) => positionalField(vmNumberLiteral(slot)));
|
|
601
601
|
return {
|
|
602
602
|
storeVar,
|
|
603
603
|
orderVar,
|
|
@@ -616,7 +616,7 @@ function buildForLoopStringExpr(chunks) {
|
|
|
616
616
|
localStatement(accVar, stringLiteral("")),
|
|
617
617
|
numericForStatement(
|
|
618
618
|
iVar,
|
|
619
|
-
|
|
619
|
+
vmNumberLiteral(1),
|
|
620
620
|
unary("#", identifier(orderVar)),
|
|
621
621
|
block([
|
|
622
622
|
assignmentStatement(
|
|
@@ -648,7 +648,7 @@ function buildRecursiveStringExpr(chunks) {
|
|
|
648
648
|
]),
|
|
649
649
|
returnStatement([
|
|
650
650
|
call(identifier(recName), [
|
|
651
|
-
binary("+", identifier(iParam),
|
|
651
|
+
binary("+", identifier(iParam), vmNumberLiteral(1)),
|
|
652
652
|
binary(
|
|
653
653
|
"..",
|
|
654
654
|
identifier(accParam),
|
|
@@ -660,7 +660,7 @@ function buildRecursiveStringExpr(chunks) {
|
|
|
660
660
|
return iife([
|
|
661
661
|
...stmts,
|
|
662
662
|
localFunctionStatement(recName, functionBody([functionParam(iParam), functionParam(accParam)], body)),
|
|
663
|
-
returnStatement([call(identifier(recName), [
|
|
663
|
+
returnStatement([call(identifier(recName), [vmNumberLiteral(1), stringLiteral("")])])
|
|
664
664
|
]);
|
|
665
665
|
}
|
|
666
666
|
function pickControlFlowStrategy() {
|
|
@@ -1755,6 +1755,23 @@ var VmCompiler = class {
|
|
|
1755
1755
|
captured = /* @__PURE__ */ new Set();
|
|
1756
1756
|
protoIdCounter = 0;
|
|
1757
1757
|
declToBinding = /* @__PURE__ */ new Map();
|
|
1758
|
+
/**
|
|
1759
|
+
* 실제로 프로그램이 참조하는 모든 전역 이름(사전 등록된 builtinGlobals +
|
|
1760
|
+
* 스코프 분석이 자동으로 찾아낸, 로컬/파라미터/업밸류로 안 풀리는 나머지 식별자
|
|
1761
|
+
* 전부)을 돌려준다. Vmify.ts가 이 목록으로 브릿지 테이블(globals)을 만든다.
|
|
1762
|
+
*
|
|
1763
|
+
* 예전엔 호출자가 넘긴 builtinGlobals 목록만 브릿지에 넣었는데, 그 목록에
|
|
1764
|
+
* 없는 전역(예: Roblox API나 실행기 전용 전역을 다 못 채운 경우)을 참조하면
|
|
1765
|
+
* 컴파일은 성공하지만 GETGLOBAL이 조용히 nil을 반환해서 "attempt to call a
|
|
1766
|
+
* nil value"로 터진다 — 게다가 원인이 VM 디스패치 쪽 스택에서만 보여서
|
|
1767
|
+
* "opcode 매핑이 깨졌나?" 하고 엉뚱한 곳을 의심하게 만든다. analyzeScopes는
|
|
1768
|
+
* 어차피 로컬/업밸류로 못 푸는 식별자를 전부 global 바인딩으로 잡아두므로,
|
|
1769
|
+
* builtinGlobals에 없던 이름도 여기 globalsByName에는 다 들어있다 —
|
|
1770
|
+
* 하드코딩된 허용목록 대신 이걸 그대로 쓰면 커버리지 문제 자체가 사라진다.
|
|
1771
|
+
*/
|
|
1772
|
+
getUsedGlobalNames() {
|
|
1773
|
+
return Array.from(this.analysis.globalsByName.keys());
|
|
1774
|
+
}
|
|
1758
1775
|
computeCaptured() {
|
|
1759
1776
|
for (const binding of this.analysis.bindings.values()) {
|
|
1760
1777
|
if (binding.kind === "global") continue;
|
|
@@ -3073,14 +3090,15 @@ function markRuntimeNumbersAsStructural(body) {
|
|
|
3073
3090
|
});
|
|
3074
3091
|
}
|
|
3075
3092
|
function runVmify(program, options) {
|
|
3076
|
-
const
|
|
3093
|
+
const builtinGlobals = options.builtinGlobals ?? DEFAULT_BUILTIN_GLOBALS;
|
|
3077
3094
|
const random = options.random ?? Math.random;
|
|
3078
3095
|
const opcodeMap = createOpcodeMap(random);
|
|
3079
3096
|
const names = generateVmNames(random);
|
|
3080
|
-
const compiler = new VmCompiler(program,
|
|
3097
|
+
const compiler = new VmCompiler(program, builtinGlobals, opcodeMap);
|
|
3081
3098
|
const topProto = compiler.compile();
|
|
3099
|
+
const usedGlobalNames = compiler.getUsedGlobalNames();
|
|
3082
3100
|
const globalsTable = table(
|
|
3083
|
-
|
|
3101
|
+
usedGlobalNames.map((name) => namedField(name, identifier(name)))
|
|
3084
3102
|
);
|
|
3085
3103
|
const runtimeSource = buildVmRuntimeSource(names, opcodeMap);
|
|
3086
3104
|
const runtimeProgram = luauparser2.parse(runtimeSource);
|