Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Zephyr)
  • No Skin
Collapse
RipperStore Logo
  1. Home
  2. Assets
  3. Gifts / Downloads
  4. Gift: A Open-source Udon Decompiler

Gift: A Open-source Udon Decompiler

Scheduled Pinned Locked Moved Gifts / Downloads
udonudonsharpworldworld encryptworld ripreverseengineerreversedecompiler
1 Posts 1 Posters 1.1k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • paran3xusP
    paran3xusP
    paran3xus
    wrote on last edited by
    #1

    A Open-source Udon Decompiler

    This is a opensource decompiler for Udon bytecode that attempts to reconstruct readable C#-like pseudocode, along with parsing public variables.

    Repo: https://github.com/ParaN3xus/udon-decompiler
    Docs: https://udon-decompiler.paran3x.us/

    Features

    • Core functionialities
      • Decompile Udon bytecode into readable C#-like pseudocode
      • Parse and reconstruct public variables
    • Unity-free decompilation workflow
      After a one-time setup step (extracting Udon module information using Unity), the rest of the process no longer depends on Unity or the VRChat SDK
      Everything can be done with two executables (<10MB total)
    • Some less documented features that are already usable:
      • Udon disassembly output
      • Modifying assembly and patching it back into the original program

    Comparison with existing tools

    There are a few existing open-source attempts at Udon decompilation:

    • https://gitlab.com/lox9973/UdonFlat
    • https://github.com/UdonSharpRE/

    However, both of these projects appear to have been inactive for quite some time.

    I haven’t thoroughly evaluated UdonFlat’s output quality, but judging from its scope and codebase size, it likely does not aim for deeper reconstruction.

    With UdonSharpRE, I’ve personally run into cases where it would completely hang on certain scripts, which might be related to less robust control flow handling. Even in cases where it does produce output, the structure and readability are generally not as strong as what this project is trying to achieve.

    I’ve also had some discussions with authors of other (unreleased) decompilers, and while I can’t make definitive claims, from comparing output fragments it seems this decompiler performs better in certain scenarios.

    Example 1 (Decompiling the FISH! world)

    I will demonstrate the full workflow using the FISH! world:

    1. Assume the decompiler is already installed
    2. Obtain & decrypt world cache (or acquire .vrcw), dump serialized programs & public variables
      68549b16-f319-4bc7-96ff-458a4d39f8ef-image.jpeg
    3. Decompile programs and parse variables
      e5f3c77b-abc1-4a20-8ad1-218f672dd547-image.jpeg

    Output (the __data-dumped directory): [register or login to view this hidden content]

    Example 2 (selected functions from DataServerManager.cs in the Massive Medal Pusher world)

    Comparison of the original asset, disassembly, and decompiled output of selected functions from DataServerManager.cs in the Massive Medal Pusher world

    Original asset

    It’s just a regular Unity asset YAML that contains serializedProgramCompressedBytes. It’s quite uninteresting, so it’s omitted here.
    

    Disassembly

    entry__start: ; @ 0x00000000
      PUSH __const_SystemUInt32_0
      PUSH __gintnl_SystemUInt32_0
      JUMP addr_0x00000138 ; call function_0();
    addr_0x00000018: ; @ 0x00000018
      PUSH __0__MedalTex__ret
      PUSH __lcl_t_SystemString_0
      COPY ; __lcl_t_SystemString_0 = __0__MedalTex__ret;
      PUSH __const_SystemString_0
      PUSH __const_SystemString_1
      PUSH __lcl_t_SystemString_0
      PUSH __const_SystemString_2
      PUSH __lcl_s_SystemString_0
      EXTERN heap_0x0000033F ; __lcl_s_SystemString_0 = System.String.Format(__const_SystemString_0, __const_SystemString_1, __lcl_t_SystemString_0, __const_SystemString_2);
      PUSH __gintnl_SystemUInt32_1
      PUSH __const_SystemString_3
      PUSH __1__intnlparam
      COPY ; __1__intnlparam = __const_SystemString_3;
      JUMP addr_0x00004838 ; call function_11();
    addr_0x00000080: ; @ 0x00000080
      PUSH __0__intnlparam
      PUSH userSecretL
      COPY ; userSecretL = __0__intnlparam;
      PUSH __gintnl_SystemUInt32_2
      PUSH __intnl_VRCSDKBaseVRCPlayerApi_0
      EXTERN heap_0x00000340 ; __intnl_VRCSDKBaseVRCPlayerApi_0 = VRC.SDKBase.Networking.LocalPlayer;
      PUSH __intnl_VRCSDKBaseVRCPlayerApi_0
      PUSH __intnl_SystemString_0
      EXTERN heap_0x00000341 ; __intnl_SystemString_0 = __intnl_VRCSDKBaseVRCPlayerApi_0.displayName;
      PUSH __lcl_s_SystemString_0
      PUSH __0_s__param
      COPY ; __0_s__param = __lcl_s_SystemString_0;
      PUSH __intnl_SystemString_0
      PUSH __0_userId__param
      COPY ; __0_userId__param = __intnl_SystemString_0;
      PUSH userSecretA
      PUSH __0_userSecretA__param
      COPY ; __0_userSecretA__param = userSecretA;
      JUMP addr_0x0000390C ; call function_9();
    addr_0x00000108: ; @ 0x00000108
      PUSH __0_userSecretA__param
      PUSH userSecretA
      COPY ; userSecretA = __0_userSecretA__param;
      PUSH __intnl_returnJump_SystemUInt32_0
      COPY ; __intnl_returnJump_SystemUInt32_0 = __const_SystemUInt32_0;
      JUMP_INDIRECT __intnl_returnJump_SystemUInt32_0
      PUSH __const_SystemUInt32_0
    addr_0x00000138: ; @ 0x00000138
      PUSH medalTex9999
      PUSH __intnl_UnityEngineTransform_0
      EXTERN heap_0x00000342 ; __intnl_UnityEngineTransform_0 = medalTex9999.transform;
      PUSH __intnl_UnityEngineTransform_0
      PUSH __const_SystemType_0
      PUSH __lcl_rend_UnityEngineRenderer_0
      EXTERN heap_0x00000343 ; __lcl_rend_UnityEngineRenderer_0 = __intnl_UnityEngineTransform_0.GetComponent(__const_SystemType_0);
      PUSH __lcl_rend_UnityEngineRenderer_0
      PUSH __intnl_UnityEngineMaterial_0
      EXTERN heap_0x00000344 ; __intnl_UnityEngineMaterial_0 = __lcl_rend_UnityEngineRenderer_0.material;
      PUSH __intnl_UnityEngineMaterial_0
      PUSH __lcl_col_UnityEngineColor_0
      EXTERN heap_0x00000345 ; __lcl_col_UnityEngineColor_0 = __intnl_UnityEngineMaterial_0.color;
      PUSH __lcl_col_UnityEngineColor_0
      PUSH __intnl_SystemSingle_0
      EXTERN heap_0x00000346 ; __intnl_SystemSingle_0 = __lcl_col_UnityEngineColor_0.r;
      PUSH __intnl_SystemSingle_0
      PUSH __const_SystemSingle_0
      PUSH __intnl_SystemSingle_1
      EXTERN heap_0x00000347 ; __intnl_SystemSingle_1 = __intnl_SystemSingle_0 * __const_SystemSingle_0;
      PUSH __intnl_SystemSingle_1
      PUSH __intnl_SystemInt32_0
      EXTERN heap_0x00000348 ; __intnl_SystemInt32_0 = UnityEngine.Mathf.RoundToInt(__intnl_SystemSingle_1);
      PUSH __intnl_SystemInt32_0
      PUSH __const_SystemInt32_0
      PUSH __const_SystemInt32_1
      PUSH __lcl_r_SystemInt32_0
      EXTERN heap_0x00000349 ; __lcl_r_SystemInt32_0 = UnityEngine.Mathf.Clamp(__intnl_SystemInt32_0, __const_SystemInt32_0, __const_SystemInt32_1);
      PUSH __lcl_col_UnityEngineColor_0
      PUSH __intnl_SystemSingle_2
      EXTERN heap_0x0000034A ; __intnl_SystemSingle_2 = __lcl_col_UnityEngineColor_0.g;
      PUSH __intnl_SystemSingle_2
      PUSH __const_SystemSingle_0
      PUSH __intnl_SystemSingle_3
      EXTERN heap_0x00000347 ; __intnl_SystemSingle_3 = __intnl_SystemSingle_2 * __const_SystemSingle_0;
      PUSH __intnl_SystemSingle_3
      PUSH __intnl_SystemInt32_1
      EXTERN heap_0x00000348 ; __intnl_SystemInt32_1 = UnityEngine.Mathf.RoundToInt(__intnl_SystemSingle_3);
      PUSH __intnl_SystemInt32_1
      PUSH __const_SystemInt32_0
      PUSH __const_SystemInt32_1
      PUSH __lcl_g_SystemInt32_0
      EXTERN heap_0x00000349 ; __lcl_g_SystemInt32_0 = UnityEngine.Mathf.Clamp(__intnl_SystemInt32_1, __const_SystemInt32_0, __const_SystemInt32_1);
      PUSH __lcl_col_UnityEngineColor_0
      PUSH __intnl_SystemSingle_4
      EXTERN heap_0x0000034B ; __intnl_SystemSingle_4 = __lcl_col_UnityEngineColor_0.b;
      PUSH __intnl_SystemSingle_4
      PUSH __const_SystemSingle_0
      PUSH __intnl_SystemSingle_5
      EXTERN heap_0x00000347 ; __intnl_SystemSingle_5 = __intnl_SystemSingle_4 * __const_SystemSingle_0;
      PUSH __intnl_SystemSingle_5
      PUSH __intnl_SystemInt32_2
      EXTERN heap_0x00000348 ; __intnl_SystemInt32_2 = UnityEngine.Mathf.RoundToInt(__intnl_SystemSingle_5);
      PUSH __intnl_SystemInt32_2
      PUSH __const_SystemInt32_0
      PUSH __const_SystemInt32_1
      PUSH __lcl_b_SystemInt32_0
      EXTERN heap_0x00000349 ; __lcl_b_SystemInt32_0 = UnityEngine.Mathf.Clamp(__intnl_SystemInt32_2, __const_SystemInt32_0, __const_SystemInt32_1);
      PUSH __const_SystemString_4
      PUSH __lcl_r_SystemInt32_0
      PUSH __lcl_g_SystemInt32_0
      PUSH __lcl_b_SystemInt32_0
      PUSH __0__MedalTex__ret
      EXTERN heap_0x0000033F ; __0__MedalTex__ret = System.String.Format(__const_SystemString_4, __lcl_r_SystemInt32_0, __lcl_g_SystemInt32_0, __lcl_b_SystemInt32_0);
      PUSH __intnl_returnJump_SystemUInt32_0
      COPY
      JUMP_INDIRECT __intnl_returnJump_SystemUInt32_0
      PUSH __intnl_returnJump_SystemUInt32_0
      COPY
      JUMP_INDIRECT __intnl_returnJump_SystemUInt32_0
    

    Decompiled C#-like output (class definition and member variable declarations have been manually omitted)

    public void _start()
    {
        System.String __lcl_t_SystemString_0 = null;
        System.String __lcl_s_SystemString_0 = null;
        System.String __intnl_SystemString_0 = null;
    
        function_0();
        __lcl_t_SystemString_0 = __0__MedalTex__ret;
        __lcl_s_SystemString_0 = System.String.Format("{0}{1}{2}", "GodSh1lbe",
                                                      __lcl_t_SystemString_0, "Shirbe334zako");
        __1__intnlparam = "qWRuTqiyLYJUwwG44DdF537cPEyDPf";
        function_11();
        userSecretL = __0__intnlparam;
        __intnl_SystemString_0 = VRC.SDKBase.Networking.LocalPlayer.displayName;
        __0_s__param = __lcl_s_SystemString_0;
        __0_userId__param = __intnl_SystemString_0;
        __0_userSecretA__param = userSecretA;
        function_9();
        userSecretA = __0_userSecretA__param;
        return;
    }
    
    void function_0()
    {
        UnityEngine.Renderer __lcl_rend_UnityEngineRenderer_0 = null;
        UnityEngine.Color __lcl_col_UnityEngineColor_0 =
            new UnityEngine.Color(0.0f, 0.0f, 0.0f, 0.0f);
        System.Int32 __lcl_r_SystemInt32_0 = 0;
        System.Int32 __lcl_g_SystemInt32_0 = 0;
        System.Int32 __lcl_b_SystemInt32_0 = 0;
    
        __lcl_rend_UnityEngineRenderer_0 = medalTex9999.transform.GetComponent(
            typeof(UnityEngine.Renderer) /* UnityEngine.CoreModule */);
        __lcl_col_UnityEngineColor_0 = __lcl_rend_UnityEngineRenderer_0.material.color;
        __lcl_r_SystemInt32_0 = UnityEngine.Mathf.Clamp(
            UnityEngine.Mathf.RoundToInt(__lcl_col_UnityEngineColor_0.r * 255.0f), 0, 255);
        __lcl_g_SystemInt32_0 = UnityEngine.Mathf.Clamp(
            UnityEngine.Mathf.RoundToInt(__lcl_col_UnityEngineColor_0.g * 255.0f), 0, 255);
        __lcl_b_SystemInt32_0 = UnityEngine.Mathf.Clamp(
            UnityEngine.Mathf.RoundToInt(__lcl_col_UnityEngineColor_0.b * 255.0f), 0, 255);
        __0__MedalTex__ret = System.String.Format("{0:D2}{1:D2}{2:D2}", __lcl_r_SystemInt32_0,
                                                  __lcl_g_SystemInt32_0, __lcl_b_SystemInt32_0);
        return;
    }
    

    Disclaimer / Intended Use

    This project is intended for learning and research, please respect original creators’ rights and follow VRChat's Terms of Service and applicable laws.

    Project status

    This project is still under active development, but it is already usable:

    • Only nightly builds are currently available
    • There are many unfinished todos

    Reporting issues & contributing

    If you encounter bugs or incorrect output, please report them following docs/user-en/reporting-issues

    Contributions are very welcome:

    • bug reports
    • PRs / improvements

    If you want to contribute to this project, check: docs/dev/status and docs/dev/contributing

    1 Reply Last reply
    👍
    5

    Hello! It looks like you're interested in this conversation, but you don't have an account yet.

    Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

    With your input, this post could be even better 💗

    Register Login
    Reply
    • Reply as topic
    Log in to reply
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes


    • Login

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular