diff --git a/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts b/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts index 412928c20a72f7ce6c44618ab1b818d8138972ab..b101e3e4a4bd25fce39c3404ef685b554db49dfc 100644 --- a/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts +++ b/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts @@ -41,7 +41,8 @@ import { isGlobalScope, isEnumScope, isInterfaceScope, - isObjectLiteralScope + isObjectLiteralScope, + mangledIdentifierNames } from '../../utils/ScopeAnalyzer'; import type { @@ -153,8 +154,8 @@ namespace secharmony { function renameNamesInScope(scope: Scope): void { if (scope.parent) { - scope.parent.mangledNames.forEach((value) => { - scope.mangledNames.add(value); + mangledIdentifierNames.forEach((value) => { + mangledIdentifierNames.add(value); }); scope.parent.importNames.forEach((value) => { @@ -185,7 +186,7 @@ namespace secharmony { let mangled: string = original; // No allow to rename reserved names. if (reservedNames.includes(original) || scope.exportNames.has(def.name) || isSkippedGlobal(openTopLevel, scope)) { - scope.mangledNames.add(mangled); + mangledIdentifierNames.add(mangled); mangledSymbolNames.set(def, mangled); return; } @@ -206,7 +207,7 @@ namespace secharmony { // add new names to name cache nameCache.set(path, mangled); - scope.mangledNames.add(mangled); + mangledIdentifierNames.add(mangled); mangledSymbolNames.set(def, mangled); localCache.set(original, mangled); }); @@ -254,7 +255,7 @@ namespace secharmony { } // the anme has already been generated in the current scope - if (scope.mangledNames.has(mangled)) { + if (mangledIdentifierNames.has(mangled)) { mangled = ''; } } while (mangled === ''); @@ -337,7 +338,7 @@ namespace secharmony { const sym: Symbol | undefined = checker.getSymbolAtLocation(targetNode); if (!sym) { - scope.mangledNames.add((targetNode as Identifier).escapedText.toString()); + mangledIdentifierNames.add((targetNode as Identifier).escapedText.toString()); } }; diff --git a/arkguard/src/utils/OhsUtil.ts b/arkguard/src/utils/OhsUtil.ts index 2588197cf1e76e08057472a0e95051dd11b523ab..f729f7f0263797735e44a87661c62df20a91b406 100644 --- a/arkguard/src/utils/OhsUtil.ts +++ b/arkguard/src/utils/OhsUtil.ts @@ -249,7 +249,7 @@ export function getInterfaceProperties(interfaceNode: InterfaceDeclaration, prop }); } -function isParameterPropertyModifier(modifier: Modifier): boolean { +export function isParameterPropertyModifier(modifier: Modifier): boolean { if (modifier.kind === SyntaxKind.PublicKeyword || modifier.kind === SyntaxKind.PrivateKeyword || modifier.kind === SyntaxKind.ProtectedKeyword || diff --git a/arkguard/src/utils/ScopeAnalyzer.ts b/arkguard/src/utils/ScopeAnalyzer.ts index abb71ec030c5887759faf3f644d82e7b58105a3b..8f6994aa9c72d3f182525ecf7f2c42d58c3cf709 100644 --- a/arkguard/src/utils/ScopeAnalyzer.ts +++ b/arkguard/src/utils/ScopeAnalyzer.ts @@ -40,10 +40,12 @@ import type { ImportSpecifier, InterfaceDeclaration, LabeledStatement, + Modifier, ModuleDeclaration, Node, ObjectBindingPattern, ObjectLiteralExpression, + ParameterDeclaration, SourceFile, Symbol, SymbolTable, @@ -53,7 +55,7 @@ import type { } from 'typescript'; import {NodeUtils} from './NodeUtils'; -import {isViewPUBasedClass} from './OhsUtil'; +import {isParameterPropertyModifier, isViewPUBasedClass} from './OhsUtil'; /** * kind of a scope @@ -103,6 +105,7 @@ namespace secharmony { return scope.kind === ScopeKind.OBJECT_LITERAL; } + export const mangledIdentifierNames: Set = new Set(); /** * Structure of a scope */ @@ -151,8 +154,6 @@ namespace secharmony { exportNames?: Set; - mangledNames?: Set; - /** * add a sub scope to current scope * @@ -228,7 +229,6 @@ namespace secharmony { 'loc': loc, 'importNames': importNames, 'exportNames': exportNames, - 'mangledNames': mangledNames, addChild, addDefinition, addLabel, @@ -622,7 +622,7 @@ namespace secharmony { } /** - * exclude constructor's parameter witch should be treated as property, example: + * exclude constructor's parameter which should be treated as property, example: * constructor(public name){}, name should be treated as property * @param node */ @@ -631,18 +631,20 @@ namespace secharmony { return; } - const visitParam = (param: Node): void => { - if (isIdentifier(param)) { - current.defs.forEach((def) => { - if (def.name === param.text) { - current.defs.delete(def); - current.mangledNames.add(def.name); - } - }); + const visitParam = (param: ParameterDeclaration): void => { + const modifiers = param.modifiers; + if (modifiers && (modifiers.length > 0)) { + const hasParameterPropertyModifier: boolean = modifiers.find(modifier => isParameterPropertyModifier(modifier)) !== undefined; + if (isIdentifier(param.name) && hasParameterPropertyModifier) { + current.defs.forEach((def) => { + if (def.name === param.name.getText()) { + current.defs.delete(def); + mangledIdentifierNames.add(def.name); + } + }); + } } - - forEachChild(param, visitParam); - }; + } node.parameters.forEach((param) => { visitParam(param); diff --git a/arkguard/test/grammar/identifier_validation/constructor_property.ts b/arkguard/test/grammar/identifier_validation/constructor_property.ts new file mode 100644 index 0000000000000000000000000000000000000000..a12585a1e613f0185b17fea160fac451bc362339 --- /dev/null +++ b/arkguard/test/grammar/identifier_validation/constructor_property.ts @@ -0,0 +1,37 @@ +// @target: es2015 +namespace ts { + let friendA: { getX(o: A): number, setX(o: A, v: number): void }; + + + class A { + x: number; + + constructor (v: number) { + this.x = v; + } + + getX () { + return this.x; + } + + obj() { + friendA = { + getX(obj) { return obj.x }, + setX(obj, value) { obj.x = value } + }; + } + }; + + class B { + constructor(public a: A, private x1: number = 1, protected x2: string = '', readonly x3: number = 2) { + const x = friendA.getX(a); // ok + + friendA.setX(a, x + 1); // ok + } + }; + + const a = new A(41); + a.obj(); + const b = new B(a); + a.getX(); +} \ No newline at end of file diff --git a/arkguard/test/grammar/identifier_validation/constructor_variables.ts b/arkguard/test/grammar/identifier_validation/constructor_variables.ts new file mode 100644 index 0000000000000000000000000000000000000000..715c9730cfb33ab96073f29a4cd2acdccfd78e59 --- /dev/null +++ b/arkguard/test/grammar/identifier_validation/constructor_variables.ts @@ -0,0 +1,37 @@ +// @target: es2015 +namespace ts { + let friendA: { getX(o: A): number, setX(o: A, v: number): void }; + + + class A { + x: number; + + constructor (v: number) { + this.x = v; + } + + getX () { + return this.x; + } + + obj() { + friendA = { + getX(obj) { return obj.x }, + setX(obj, value) { obj.x = value } + }; + } + }; + + class B { + constructor(a: A) { + const x = friendA.getX(a); // ok + + friendA.setX(a, x + 1); // ok + } + }; + + const a = new A(41); + a.obj(); + const b = new B(a); + a.getX(); +} \ No newline at end of file diff --git a/arkguard/test/grammar/identifier_validation/obfConfig.json b/arkguard/test/grammar/identifier_validation/obfConfig.json new file mode 100644 index 0000000000000000000000000000000000000000..218f100677b8429f2e0c08151dc3a3847c49b72f --- /dev/null +++ b/arkguard/test/grammar/identifier_validation/obfConfig.json @@ -0,0 +1,18 @@ +{ + "mCompact": false, + "mRemoveComments": false, + "mOutputDir": "../../local", + "mDisableHilog": false, + "mDisableConsole": false, + "mSimplify": false, + "mNameObfuscation": { + "mEnable": true, + "mNameGeneratorType": 1, + "mDictionaryList": [], + "mRenameProperties": false, + "mKeepStringProperty": false + }, + "mEnableSourceMap": false, + "mEnableNameCache": false, + "mTopLevel": false +} \ No newline at end of file diff --git a/arkguard/test/grammar/obfuscation_validation/interface_demo_01-assert.ts b/arkguard/test/grammar/obfuscation_validation/interface_demo_01-assert.ts index ec65d7e88523ea75ee96ef91ee252760a209af66..33d82bb5c2b2c9325ca57cccf00c76f95e6553f3 100644 --- a/arkguard/test/grammar/obfuscation_validation/interface_demo_01-assert.ts +++ b/arkguard/test/grammar/obfuscation_validation/interface_demo_01-assert.ts @@ -29,7 +29,7 @@ export class class01 { classP12 = 3; }; get classP13() { return 1; } - set classP14(a) { } + set classP14(g) { } } export enum enum01 { enumP1,