<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://consumerrights.wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Vaur</id>
	<title>Consumer Rights Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://consumerrights.wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Vaur"/>
	<link rel="alternate" type="text/html" href="https://consumerrights.wiki/w/Special:Contributions/Vaur"/>
	<updated>2026-04-30T15:45:36Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://consumerrights.wiki/index.php?title=Reverse_engineering_Bambu_Connect&amp;diff=2897</id>
		<title>Reverse engineering Bambu Connect</title>
		<link rel="alternate" type="text/html" href="https://consumerrights.wiki/index.php?title=Reverse_engineering_Bambu_Connect&amp;diff=2897"/>
		<updated>2025-01-19T18:50:36Z</updated>

		<summary type="html">&lt;p&gt;Vaur: fixed misspell in word principles&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bambu Connect is an Electron App with Security through Obscurity principles, hence it is inherently insecure.&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read the main.js for further analysis or extracting the private key stored by Bambu in the app:&lt;br /&gt;
&lt;br /&gt;
# Use the MacOs .dmg file, not the exe. Finding the needed decryption code is easier in the .dmg&lt;br /&gt;
# Extract &#039;&#039;bambu-connect-beta-darwin-arm64-v1.0.4_4bb9cf0.dmg&#039;&#039;&amp;lt;ref&amp;gt;https://public-cdn.bblmw.com/upgrade/bambu-connect/bambu-connect-beta-darwin-arm64-v1.0.4_4bb9cf0.dmg&amp;lt;/ref&amp;gt;, in there you can find the files of the underlying Electron app in &#039;&#039;Bambu Connect (Beta).app/Contents/Resources&#039;&#039; folder&lt;br /&gt;
# The app uses asarmor to prevent easy reading, the key is stored in ./app.asar.unpacked/.vite/build/main.node and can be extracted. Unpacking app.asar without fixing it first will result in an encrypted main.js file and 100 GB of decoy files generated, don&#039;t try it.&lt;br /&gt;
# Load main.node in Ghidra and Auto-Analyze it. Then search for the GetKey function, or press G and go to 0000b67e&amp;lt;ref&amp;gt;https://www.reddit.com/r/OrcaSlicer/comments/1i2t6l8/comment/m7tuf2i/&amp;lt;/ref&amp;gt;&lt;br /&gt;
# Write down the hex key, for this build it&#039;s B0AE6995063C191D2B404637FBC193AE10DAB86A6BC1B1DE67B5AEE6E03018A2&lt;br /&gt;
# Install the npm package asarfix and use it to fix the archive: &amp;lt;code&amp;gt;npx asarfix app.asar -k B0AE6995063C191D2B404637FBC193AE10DAB86A6BC1B1DE67B5AEE6E03018A2 -o fixed.asar&amp;lt;/code&amp;gt;&lt;br /&gt;
# Now you can extract it in cleartext with  &amp;lt;code&amp;gt;npx asar extract fixed.asar src&amp;lt;/code&amp;gt;&lt;br /&gt;
# ./src/.vite/build/main.js is minified, use any JavaScript beautifier to make it better readable. Interesting user code including the private key is at the end of the file.&lt;br /&gt;
&lt;br /&gt;
=== Extracting certs and private key ===&lt;br /&gt;
The private key and certs are further obfuscated, to get cleartext you need to do: Encrypted string from cy() -&amp;gt; ure(string, key) -&amp;gt; RC4 decryption -&amp;gt;  decodeURIComponent() -&amp;gt; final string.&lt;br /&gt;
&lt;br /&gt;
Example Python reimplementation to extract the secrets, easy to run. Copy the content of t from function cy() in main.js and paste it here. After running, you have a private key from Bambu Lab.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import urllib.parse&lt;br /&gt;
&lt;br /&gt;
def cy():&lt;br /&gt;
    t = [&lt;br /&gt;
		# copy from main.js&lt;br /&gt;
	]&lt;br /&gt;
    return t&lt;br /&gt;
&lt;br /&gt;
def ure(t, e):&lt;br /&gt;
    # RC4 implementation&lt;br /&gt;
    r = list(range(256))&lt;br /&gt;
    n = 0&lt;br /&gt;
    s = &amp;quot;&amp;quot;&lt;br /&gt;
    &lt;br /&gt;
    # Key-scheduling algorithm (KSA)&lt;br /&gt;
    for o in range(256):&lt;br /&gt;
        n = (n + r[o] + ord(e[o % len(e)])) % 256&lt;br /&gt;
        r[o], r[n] = r[n], r[o]&lt;br /&gt;
    &lt;br /&gt;
    # Pseudo-random generation algorithm (PRGA)&lt;br /&gt;
    o = n = 0&lt;br /&gt;
    for byte in t:&lt;br /&gt;
        o = (o + 1) % 256&lt;br /&gt;
        n = (n + r[o]) % 256&lt;br /&gt;
        r[o], r[n] = r[n], r[o]&lt;br /&gt;
        k = r[(r[o] + r[n]) % 256]&lt;br /&gt;
        s += chr(byte ^ k)&lt;br /&gt;
    &lt;br /&gt;
    return s&lt;br /&gt;
&lt;br /&gt;
def lt(t, e):&lt;br /&gt;
    r = cy()&lt;br /&gt;
    n = t - 106&lt;br /&gt;
    s = r[n]&lt;br /&gt;
    s = ure(s, e)&lt;br /&gt;
    return urllib.parse.unquote(s)&lt;br /&gt;
&lt;br /&gt;
def extract_certs_and_key():&lt;br /&gt;
    try:&lt;br /&gt;
        result = {}&lt;br /&gt;
        result[&amp;quot;Are&amp;quot;] = lt(106, &amp;quot;1o9B&amp;quot;)&lt;br /&gt;
        result[&amp;quot;fre&amp;quot;] = lt(107, &amp;quot;FT2A&amp;quot;)&lt;br /&gt;
        result[&amp;quot;private_key&amp;quot;] = lt(108, &amp;quot;Tlj0&amp;quot;)&lt;br /&gt;
        result[&amp;quot;cert&amp;quot;] = lt(109, &amp;quot;NPub&amp;quot;)&lt;br /&gt;
        result[&amp;quot;crl&amp;quot;] = lt(110, &amp;quot;x077&amp;quot;)&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        print(f&amp;quot;Error extracting certs/key: {e}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    for key, value in result.items():&lt;br /&gt;
        print(f&amp;quot;{key}:\n{value}\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    extract_certs_and_key()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vaur</name></author>
	</entry>
</feed>