8000 fix: fix with protected string issue - visibility, concat expressions and escape sequences by 1JunHuang · Pull Request #710 · alex8088/electron-vite · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix: fix with protected string issue - visibility, concat expressions and escape sequences #710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the com 8000 munity.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

1JunHuang
Copy link
@1JunHuang 1JunHuang commented Feb 5, 2025

Description

Fix String Protection

  • See Strings are not protected when using bytecodePlugin #552, in some editors it's very easy to identify the protected string. Inspired by subframe7536, we can add obfuscation to fix issue and improve the difficulty of cracking while considering performance(I'll illustrate the principles and improvements later).
  • Added support for string concatenation expressions (e.g., "a" + "b") to ensure merged strings are also protected.
  • Added support for escape sequences (e.g., "\n", "\t", ...) to ensure this special characters are also protected.

Additional context

Reproduction

When I was trying to define a CA cert and client cert in string and protect them, I double checked the generated .jsc file, and find it's easy to identify them in VSCode.

Failure Example
String Variable with concatenation expressions(also mentioned in #455):

export const CLIENT_CERT = "-----BEGIN CERTIFICATE-----" + "\n" +
"MIIDkTCCAnmgAwIBAgIUQt726ICGVvNVXHfzwCSwCR4XsB0wDQYJKoZIhvcNAQEL".......`

String Variable with Template Strings:

export const CLIENT_CERT = `-----BEGIN CERTIFICATE-----
MIIDkTCCAnmgAwIBAgIUQt726ICGVvNVXHfzwCSwCR4XsB0wDQYJKoZIhvcNAQEL
BQAwcDELMAkGA1UEBhMCQ04xDzANBgNVBAgMBll1bm5hbjEdMBsGA1UEBwwUU3Rh.......`

String Variable with Escape Sequences:

export const CLIENT_CERT = "-----BEGIN CERTIFICATE-----\nMIIDkTCCAnm......."

String Variable with Ternary Expression, or we can say, any expression:

export const ABC = "ABCD" + (true ? "E" : "F")

Then, it goes with no effect:
WX20250204-231747@2x

Then I try simple string like:

export const RPC_CONNECTION_TEST_PATH = "main:rpc-connection-check";

It works, but seems easy to identify, just like who described in #552.
WX20250205-005918@2x

WHY THIS HAPPENS?
We use String.fromCharCode(...) correct? This is exactly the key issue. The old protection method simply converted the target string into a series of fixed character codes and used String.fromCharCode(...) to restore it at runtime. As a result:

  • The compiler (V8) can easily detect and inline these constants. It may even perform constant folding during compilation, restoring the original string.
  • It would be easy to reverse through static analysis. Numeric constants explicitly exist in the binary and can be directly mapped back through simple mapping.

So when we open many different editors, this part is particularly prominent and eye-catching. Therefore, although the protection process transforms the source code, the generated code pattern is overly simple and fixed. This makes it easy for V8 to recognize and restore the string after compilation - which means, we have find another approach to do at least low level obfuscation.

Secondly, let's talk about why Expressions and Escape Sequences does not work. In my guessing:

  • If a string was constructed using concatenation, template literals, or contained escape sequences, it might not appear in this exact format after compilation, making it impossible to match and replace.
  • V8 perform constant folding or inline optimizations for string concatenation, template literals, and conditional expressions. As a result, the final generated bytecode may contain only the complete string literal, effectively bypassing the old code's protection logic.
  • We don't have a mechanism for parsing complex expressions and relied solely on simple regex-based replacement.

However, based on my experience and existing examples, combined with a developer's mindset, it is still not recommended to use template literals or complex expressions for protected strings. These should be pre-generated in advance.

Inspired by subframe7536, I find this approach works well. Although a fixed offset is applied to each character, the small range of offset values (approximately 1–32) means that the same input always produces the same encrypted result, making it vulnerable to static analysis or pattern-based decryption. To address this, I did a little revise - I introduced a 4-byte random key and combined addition with XOR operations, ensuring that each character's obfuscation result is not solely dependent on the input. For V8/JIT optimization, the new function utilizes an inline IIFE. While this increases the number of computation steps slightly, it has minimal impact on most use cases. The resulting .jsc file size does increase, but this is a trade-off that comes as a necessary side effect of the enhanced protection.

Supported Types of Expression After Modification
Thus I only modify the transform function and add support only for this types of expression, and util now it has been tested well(manually) and performed well.

  • ✅ Normal String, e.g., const str = "abcd";
  • ✅ Concat Expression, e.g., const str = "ab" + "cd";
  • ✅ String with Escape Sequences, e.g., const str = "ab\ncd";
  • ✅ Combined example, e.g., const str = "ab\t" + 'cd' + "\n" + "efg";

Unsupported usage

  • ❌ Conditional Expression, e.g., const ABC = "ABCD" + (condition ? "E" : "F");
  • ❌ Use another variable in concat expression, e.g., const ABC = "ABC" + someString
  • ❌ Template String, e.g.,
const ABC = `localhost:${port}`

These examples would cover most of cases during our development. I strongly recommend the maintainers mention these cases in official documentation to help community users quickly understand supported and unsupported usages. After the modification, it shows like:
image

That's it. Hope electron-vite will become more and more powerful! This is the best framework for electron and vite that I have ever used.


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

@alex8088
Copy link
Owner
alex8088 commented Feb 5, 2025

Thanks! @1JunHuang

This will be a breaking change and I will need some time to discuss and test it. If there are no problems with verification, it will be merged in a future version.

@subframe7536
Copy link

@1JunHuang For unsupported usages, it is more convenient to use babel to transform. Here is my tests https://github.com/subframe7536/electron-incremental-update/blob/master/tests/bytecode.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0