Skip to content

Incorrect decompilation #8

@bbarwik

Description

@bbarwik

Hey.

I was analyzing https://suiscan.xyz/mainnet/object/0x3d37357bac2e9644920b5c51d403938c32ea76e9ec848b1a526b208e76da1707/contracts and it turned out it is decompiled incorrectly.

In decompiled code you have

        let v4 = 0x2::random::generate_u64_in_range(arg2, 1, 10001 + arg1.house_edge);
        if (v4 > 10000 && false || arg4 == 0 && v4 >= arg6 && v4 <= arg5 || v4 <= arg6 || v4 >= arg5) {
            v1 = v2 + arg3;
        };

while it should be more like this:

  let v5 = if (v4 > 10000) {
      false
  } else {
      if (arg4 == 0) {
          v4 >= arg6 && v4 <= arg5  // Inside bet: win if within range
      } else {
          v4 <= arg6 || v4 >= arg5  // Outside bet: win if outside range
      }
  };
  if (v5) {
      v1 = v2 + arg3;
  };

Bellow are more details (generated by claude code based on my findings):

Incorrect Decompilation of Complex Boolean Expression in Move Bytecode v6

Description

The decompiler incorrectly decompiles a complex boolean expression in the one_game function, resulting in code that appears to have a critical security vulnerability when the
actual bytecode implements the logic correctly.

Environment

  • Move bytecode version: v6
  • Module: 3d37357bac2e9644920b5c51d403938c32ea76e9ec848b1a526b208e76da1707::ufo_range

Expected Behavior

Based on the bytecode analysis, the win condition should be decompiled as:
let v5 = if (v4 > 10000) {
false
} else {
if (arg4 == 0) {
v4 >= arg6 && v4 <= arg5 // Inside bet: win if within range
} else {
v4 <= arg6 || v4 >= arg5 // Outside bet: win if outside range
}
};
if (v5) {
v1 = v2 + arg3;
};

Actual Behavior

The decompiler produced:
if (v4 > 10000 && false || arg4 == 0 && v4 >= arg6 && v4 <= arg5 || v4 <= arg6 || v4 >= arg5) {
v1 = v2 + arg3;
};

This decompiled code creates a logical tautology where (v4 <= arg6 || v4 >= arg5) covers all possible values, making it appear that inside bets (arg4 == 0) always win.

Bytecode Analysis

The relevant bytecode section (simplified):
B22: 137: LdFalse
138: StLoc[13](loc5: bool)
139: Branch(173)
B23: 140: CopyLoc[4](Arg4: u64)
141: LdConst[0](u64: 0)
142: Eq
143: BrFalse(158)
B24: 144-151: // Check if v4 >= arg6 && v4 <= arg5
152: Branch(155)
B28: 158-168: // Check if v4 <= arg6 || v4 >= arg5
B32: 171: MoveLoc[12](loc4: bool)
172: StLoc[13](loc5: bool)
B33: 173: MoveLoc[13](loc5: bool)
174: BrFalse(179)
B34: 175-178: // Set payout if loc5 is true

The bytecode clearly shows:

  1. Different logic paths for arg4 == 0 (inside bet) vs arg4 == 1 (outside bet)
  2. Proper boolean evaluation with intermediate results stored in locals
  3. No tautology - the conditions are correctly scoped

Impact

This decompilation error led to:

  1. False security vulnerability report: The incorrect decompilation made it appear there was a critical exploit allowing guaranteed wins
  2. Misunderstanding of contract behavior: Multiple security analyses were performed based on the incorrect decompiled code
  3. Wasted resources: Time spent analyzing and attempting to exploit a non-existent vulnerability

Reproduction Steps

  1. Decompile the bytecode for function one_game in the specified module
  2. Observe the boolean expression for the win condition around bytecode positions 133-174
  3. Compare with manual bytecode analysis to see the discrepancy

Suggested Fix

The decompiler should:

  1. Better handle nested conditional logic with multiple branches
  2. Preserve the semantic structure of if-else chains rather than flattening to a single boolean expression
  3. Consider the scope of boolean operators when reconstructing complex conditions

Additional Context

This issue was discovered when investigating what appeared to be a critical security vulnerability in a gaming smart contract. The decompiled code suggested that players could
achieve ~99% win rates, but actual testing showed normal loss rates. Manual bytecode analysis revealed the decompiler had incorrectly reconstructed the boolean logic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions