3

For educational purpose I've created a simple python based evm bytecode disassembler (see github::ethereum-dasm) that attempts to resolve static jumps (JUMP,JUMPI instructions) in order to make the disassembly more readable. The disassembler is working fine, however I'm very surprised that some static jumps do not seem to land anywhere near a JUMPDEST even though thats required by the ethereum vm (as outlined in the ethereum yellowpaper)

A static jump looks as follows:

PUSH <iteral>
JUMP[I]

Here's an excerpt of a contract taken from the ethereum chain (etherchain/contracts/postcats):

Solidity code:

contract postCats {
  string strCat;

  function set(string x) {
    strCat = x;
  }

  function get() constant returns (string retVal) {
    return strCat;
  }
}

Disassembly:

#> python evmdasm.py -v critical 0x6060604052610209806100126000396000f3606060405260e060020a60003504634ed3885e81146100265780636d4ce63c146100cc575b005b60206004803580820135601f810184900490930260809081016040526060848152610024946024939192918401918190838280828437509496505050505050508060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106101a057805160ff19168380011785555b5061019b9291505b808211156101d0578381556001016100b9565b61012d60006060818152815460a06020601f60026000196101006001871615020190941693909304928301819004028101604052608082815292939190828280156101ff5780601f106101d4576101008083540402835291602001916101ff565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561018d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b505050565b828001600101855582156100b1579182015b828111156100b15782518260005055916020019190600101906101b2565b5090565b820191906000526020600020905b8154815290600101906020018083116101e257829003601f168201915b505050505090509056

 Instr.#    addrs.      mnemonic        operand                xrefs      description
------------------------------------------------------------------------------------------------------------------------------------------------------
[       0] [0x00000000] PUSH1           0x60 ('`')                        # Place 1 byte item on stack.
[       1] [0x00000002] PUSH1           0x40 ('@')                        # Place 1 byte item on stack.
[       2] [0x00000004] MSTORE                                            # Save word to memory.
[       3] [0x00000005] PUSH2           0x0209                            # Place 2-byte item on stack.
[       4] [0x00000008] DUP1                                              # Duplicate 1st stack item.
[       5] [0x00000009] PUSH2           0x0012                            # Place 2-byte item on stack.
[       6] [0x0000000c] PUSH1           0x00                              # Place 1 byte item on stack.
[       7] [0x0000000e] CODECOPY                                          # Copy code running in current environment to memory.
[       8] [0x0000000f] PUSH1           0x00                              # Place 1 byte item on stack.
[       9] [0x00000011] RETURN                                            # Halt execution returning output data.

[      10] [0x00000012] PUSH1           0x60 ('`')                        # Place 1 byte item on stack.
[      11] [0x00000014] PUSH1           0x40 ('@')                        # Place 1 byte item on stack.
[      12] [0x00000016] MSTORE                                            # Save word to memory.
[      13] [0x00000017] PUSH1           0xe0                              # Place 1 byte item on stack.
[      14] [0x00000019] PUSH1           0x02                              # Place 1 byte item on stack.
[      15] [0x0000001b] EXP                                               # Exponential operation.
[      16] [0x0000001c] PUSH1           0x00                              # Place 1 byte item on stack.
[      17] [0x0000001e] CALLDATALOAD                                      # Get input data of current environment.
[      18] [0x0000001f] DIV                                               # Integer division operation.
[      19] [0x00000020] PUSH4           0x4ed3885e                        # Place 4-byte item on stack.
[      20] [0x00000025] DUP2                                              # Duplicate 2nd stack item.
[      21] [0x00000026] EQ                                     JUMPI@0x2a # Equality  comparison            <--- INVALID, not a JUMPDEST
[      22] [0x00000027] PUSH2           0x0026                            # Place 2-byte item on stack.
[      23] [0x0000002a] JUMPI           @0x26                             # Conditionally alter the program counter.

[      24] [0x0000002b] DUP1                                              # Duplicate 1st stack item.
[      25] [0x0000002c] PUSH4           0x6d4ce63c ('mL\xe6<')            # Place 4-byte item on stack.
[      26] [0x00000031] EQ                                                # Equality  comparison
[      27] [0x00000032] PUSH2           0x00cc                            # Place 2-byte item on stack.
[      28] [0x00000035] JUMPI           @0xcc                             # Conditionally alter the program counter.

:loc_0x36
[      29] [0x00000036] JUMPDEST                                          # Mark a valid destination for jumps.  <--- NO JMP REF
[      30] [0x00000037] STOP                                              # Halts execution.

:loc_0x38
[      31] [0x00000038] JUMPDEST                                          # Mark a valid destination for jumps.  <---- NO JMP REF
[      32] [0x00000039] PUSH1           0x20                              # Place 1 byte item on stack.
...
[     130] [0x000000b2] LT                                                # Lesser-than comparison
[     131] [0x000000b3] PUSH2           0x01a0                            # Place 2-byte item on stack.
[     132] [0x000000b6] JUMPI           @0x1a0                            # Conditionally alter the program counter.  <---- VALID
[     133] [0x000000b7] DUP1                                              # Duplicate 1st stack item.
[     134] [0x000000b8] MLOAD                                             # Load word from memory.
[     135] [0x000000b9] PUSH1           0xff                   JUMP@0xdd  # Place 1 byte item on stack.    <---- INVALID, not a JUMPDEST
...

:loc_0xcb
[     150] [0x000000cb] JUMPDEST                                          # Mark a valid destination for jumps.
[     151] [0x000000cc] DUP1                                   JUMPI@0x35 # Duplicate 1st stack item.   <---- INVALID, not a JUMPDEST
[     152] [0x000000cd] DUP3                                              # Duplicate 3rd stack item.
[     153] [0x000000ce] GT                                                # Greater-than comparison
[     154] [0x000000cf] ISZERO                                            # Simple not operator
[     155] [0x000000d0] PUSH2           0x01d0                            # Place 2-byte item on stack.
[     156] [0x000000d3] JUMPI           @0x1d0                            # Conditionally alter the program counter.

[     157] [0x000000d4] DUP4                                              # Duplicate 4th stack item.
[     158] [0x000000d5] DUP2                                              # Duplicate 2nd stack item.
[     159] [0x000000d6] SSTORE                                            # Save word to storage.
[     160] [0x000000d7] PUSH1           0x01                              # Place 1 byte item on stack.
[     161] [0x000000d9] ADD                                               # Addition operation.
[     162] [0x000000da] PUSH2           0x00b9                            # Place 2-byte item on stack.
[     163] [0x000000dd] JUMP            @0xb9                             # Alter the program counter.

...
[     295] [0x00000186] DUP1                                              # Duplicate 1st stack item.
[     296] [0x00000187] DUP3                                              # Duplicate 3rd stack item.
[     297] [0x00000188] SUB                                               # Subtraction operation.
[     298] [0x00000189] DUP1                                              # Duplicate 1st stack item.
[     299] [0x0000018a] MLOAD                                             # Load word from memory.
[     300] [0x0000018b] PUSH1           0x01                              # Place 1 byte item on stack.
[     301] [0x0000018d] DUP4                                  JUMPI@0x185 # Duplicate 4th stack item.   <-- INVALID not a JUMPDEST
[     302] [0x0000018e] PUSH1           0x20                              # Place 1 byte item on stack.
[     303] [0x00000190] SUB                                               # Subtraction operation.
[     304] [0x00000191] PUSH2           0x0100                            # Place 2-byte item on stack.
[     305] [0x00000194] EXP                                               # Exponential operation.
[     306] [0x00000195] SUB                                               # Subtraction operation.
[     307] [0x00000196] NOT                                               # Bitwise NOT operation.
[     308] [0x00000197] AND                                               # Bitwise AND operation.
[     309] [0x00000198] DUP2                                              # Duplicate 2nd stack item.
[     310] [0x00000199] MSTORE                                            # Save word to memory.
[     311] [0x0000019a] PUSH1           0x20                              # Place 1 byte item on stack.
[     312] [0x0000019c] ADD                                               # Addition operation.
[     313] [0x0000019d] SWAP2                                             # Exchange 1st and 3rd stack items.
[     314] [0x0000019e] POP                                               # Remove item from stack.
:loc_0x19f
[     315] [0x0000019f] JUMPDEST                                          # Mark a valid destination for jumps.
[     316] [0x000001a0] POP                                    JUMPI@0xb6 # Remove item from stack.    <-- INVALID not a JUMPDEST
[     317] [0x000001a1] SWAP3                                             # Exchange 1st and 4th stack items.
[     318] [0x000001a2] POP                                               # Remove item from stack.
[     319] [0x000001a3] POP                                               # Remove item from stack.
[     320] [0x000001a4] POP                                               # Remove item from stack.
[     321] [0x000001a5] PUSH1           0x40 ('@')                        # Place 1 byte item on stack.
[     322] [0x000001a7] MLOAD                                             # Load word from memory.
[     323] [0x000001a8] DUP1                                              # Duplicate 1st stack item.
[     324] [0x000001a9] SWAP2                                             # Exchange 1st and 3rd stack items.
[     325] [0x000001aa] SUB                                               # Subtraction operation.
[     326] [0x000001ab] SWAP1                                             # Exchange 1st and 2nd stack items.
[     327] [0x000001ac] RETURN                                            # Halt execution returning output data.

:loc_0x1ad
[     328] [0x000001ad] JUMPDEST                                          # Mark a valid destination for jumps.
[     329] [0x000001ae] POP                                               # Remove item from stack.
[     330] [0x000001af] POP                                               # Remove item from stack.
[     331] [0x000001b0] POP                                               # Remove item from stack.
[     332] [0x000001b1] JUMP                                              # Alter the program counter.

:loc_0x1b2
[     333] [0x000001b2] JUMPDEST                               JUMP@0x1e1 # Mark a valid destination for jumps.  <-- VALID
[     334] [0x000001b3] DUP3                                              # Duplicate 3rd stack item.
[     335] [0x000001b4] DUP1                                              # Duplicate 1st stack item.
[     336] [0x000001b5] ADD                                               # Addition operation.
[     337] [0x000001b6] PUSH1           0x01                              # Place 1 byte item on stack.
[     338] [0x000001b8] ADD                                               # Addition operation.
[     339] [0x000001b9] DUP6                                              # Duplicate 6th stack item.
[     340] [0x000001ba] SSTORE                                            # Save word to storage.
[     341] [0x000001bb] DUP3                                              # Duplicate 3rd stack item.
[     342] [0x000001bc] ISZERO                                            # Simple not operator
[     343] [0x000001bd] PUSH2           0x00b1                            # Place 2-byte item on stack.
[     344] [0x000001c0] JUMPI           @0xb1                             # Conditionally alter the program counter.

[     345] [0x000001c1] SWAP2                                             # Exchange 1st and 3rd stack items.
[     346] [0x000001c2] DUP3                                              # Duplicate 3rd stack item.
[     347] [0x000001c3] ADD                                               # Addition operation.
:loc_0x1c4
[     348] [0x000001c4] JUMPDEST                                          # Mark a valid destination for jumps.
[     349] [0x000001c5] DUP3                                              # Duplicate 3rd stack item.
[     350] [0x000001c6] DUP2                                              # Duplicate 2nd stack item.
[     351] [0x000001c7] GT                                                # Greater-than comparison
[     352] [0x000001c8] ISZERO                                            # Simple not operator
[     353] [0x000001c9] PUSH2           0x00b1                            # Place 2-byte item on stack.
[     354] [0x000001cc] JUMPI           @0xb1                             # Conditionally alter the program counter.

[     355] [0x000001cd] DUP3                                              # Duplicate 3rd stack item.
[     356] [0x000001ce] MLOAD                                             # Load word from memory.
[     357] [0x000001cf] DUP3                                              # Duplicate 3rd stack item.
[     358] [0x000001d0] PUSH1           0x00                  JUMPI@0xd3  # Place 1 byte item on stack. <-- INVALID, not a JUMPDEST
[     359] [0x000001d2] POP                                               # Remove item from stack.
[     360] [0x000001d3] SSTORE                                            # Save word to storage. <-- INVALID, not a JUMPDEST
[     361] [0x000001d4] SWAP2                                 JUMPI@0x12b # Exchange 1st and 3rd stack items.
[     362] [0x000001d5] PUSH1           0x20                              # Place 1 byte item on stack.
[     363] [0x000001d7] ADD                                               # Addition operation.
[     364] [0x000001d8] SWAP2                                             # Exchange 1st and 3rd stack items.
[     365] [0x000001d9] SWAP1                                             # Exchange 1st and 2nd stack items.
[     366] [0x000001da] PUSH1           0x01                              # Place 1 byte item on stack.
[     367] [0x000001dc] ADD                                               # Addition operation.
[     368] [0x000001dd] SWAP1                                             # Exchange 1st and 2nd stack items.
[     369] [0x000001de] PUSH2           0x01b2                            # Place 2-byte item on stack.
[     370] [0x000001e1] JUMP            @0x1b2                            # Alter the program counter.

:loc_0x1e2
[     371] [0x000001e2] JUMPDEST                              JUMPI@0x207 # Mark a valid destination for jumps. <--- VALID
[     372] [0x000001e3] POP                                               # Remove item from stack.
[     373] [0x000001e4] SWAP1                                             # Exchange 1st and 2nd stack items.
[     374] [0x000001e5] JUMP                                              # Alter the program counter.

:loc_0x1e6
[     375] [0x000001e6] JUMPDEST                                          # Mark a valid destination for jumps.
[     376] [0x000001e7] DUP3                                              # Duplicate 3rd stack item.
[     377] [0x000001e8] ADD                                               # Addition operation.
[     378] [0x000001e9] SWAP2                                             # Exchange 1st and 3rd stack items.
[     379] [0x000001ea] SWAP1                                             # Exchange 1st and 2nd stack items.
[     380] [0x000001eb] PUSH1           0x00                              # Place 1 byte item on stack.
[     381] [0x000001ed] MSTORE                                            # Save word to memory.
[     382] [0x000001ee] PUSH1           0x20                              # Place 1 byte item on stack.
[     383] [0x000001f0] PUSH1           0x00                              # Place 1 byte item on stack.
[     384] [0x000001f2] SHA3                                              # Compute Keccak-256 hash.
[     385] [0x000001f3] SWAP1                                             # Exchange 1st and 2nd stack items.
:loc_0x1f4
[     386] [0x000001f4] JUMPDEST                                          # Mark a valid destination for jumps.
[     387] [0x000001f5] DUP2                                              # Duplicate 2nd stack item.
[     388] [0x000001f6] SLOAD                                             # Load word from storage.
[     389] [0x000001f7] DUP2                                              # Duplicate 2nd stack item.
[     390] [0x000001f8] MSTORE                                            # Save word to memory.
[     391] [0x000001f9] SWAP1                                             # Exchange 1st and 2nd stack items.
[     392] [0x000001fa] PUSH1           0x01                              # Place 1 byte item on stack.
[     393] [0x000001fc] ADD                                               # Addition operation.
[     394] [0x000001fd] SWAP1                                             # Exchange 1st and 2nd stack items.
[     395] [0x000001fe] PUSH1           0x20                              # Place 1 byte item on stack.
[     396] [0x00000200] ADD                                               # Addition operation.
[     397] [0x00000201] DUP1                                              # Duplicate 1st stack item.
[     398] [0x00000202] DUP4                                              # Duplicate 4th stack item.
[     399] [0x00000203] GT                                                # Greater-than comparison
[     400] [0x00000204] PUSH2           0x01e2                            # Place 2-byte item on stack.
[     401] [0x00000207] JUMPI           @0x1e2                            # Conditionally alter the program counter.

[     402] [0x00000208] DUP3                                              # Duplicate 3rd stack item.
[     403] [0x00000209] SWAP1                                             # Exchange 1st and 2nd stack items.
[     404] [0x0000020a] SUB                                               # Subtraction operation.
[     405] [0x0000020b] PUSH1           0x1f                              # Place 1 byte item on stack.
[     406] [0x0000020d] AND                                               # Bitwise AND operation.
[     407] [0x0000020e] DUP3                                              # Duplicate 3rd stack item.
[     408] [0x0000020f] ADD                                               # Addition operation.
[     409] [0x00000210] SWAP2                                             # Exchange 1st and 3rd stack items.
:loc_0x211
[     410] [0x00000211] JUMPDEST                                          # Mark a valid destination for jumps.
[     411] [0x00000212] POP                                               # Remove item from stack.
[     412] [0x00000213] POP                                               # Remove item from stack.
[     413] [0x00000214] POP                                               # Remove item from stack.
[     414] [0x00000215] POP                                               # Remove item from stack.
[     415] [0x00000216] POP                                               # Remove item from stack.
[     416] [0x00000217] SWAP1                                             # Exchange 1st and 2nd stack items.
[     417] [0x00000218] POP                                               # Remove item from stack.
[     418] [0x00000219] SWAP1                                             # Exchange 1st and 2nd stack items.
[     419] [0x0000021a] JUMP                                              # Alter the program counter.

assemble(disassemble(evmcode))== True

There are a few valid jumps that land on a JUMPDEST like 0x000001e1 or 0x00000207 but the great majority either references an invalid target address or does not land on a JUMPDEST. (Note that I've annotated some valid/invalid jumps in the disassembly listing, check for <-- at the end of the line)

For example the jump:

  • JUMPI@0x2a lands on a EQ - which is invalid
  • JUMP@0xdd lands on a PUSH - which is invalid
  • JUMPI@0x35 lands on a DUP - which is invalid
  • JUMPDEST@0x38 seems to be unreachable (even though it might be ref'd by a dynamic jump)
  • JUMPI@0x123 jumps into an instruction - at first sight this must not be invalid and could well be an obfuscation/optimization artifact but disassembling @0x1ff does not yield JUMPDEST but 0x20 which is a SHA3 instruction - therefore invalid

    [     216] [0x00000120] PUSH2           0x01ff                            # Place 2-byte item on stack.
    [     217] [0x00000123] JUMPI           @0x1ff                            # Conditionally alter the program counter.
    ...
    [     395] [0x000001fe] PUSH1           0x20                              # Place 1 byte item on stack.
    [     396] [0x00000200] ADD                                               # Addition operation.
    

There's obviously something wrong with either my assumption about static jumps, the evm bytecode of the contract (saw the same behavior for multiple different contracts in the blockhain) or the way I match jump destinations.

Below is the code that attempts to resolve jump destinations:

self.instruction_at is a map address to instruction
self.xrefs is a map address to set(jump_sources, ...)

def _update_xrefs(self):
     # find all JUMP, JUMPI's
     for loc, instruction in ((l,i) for l,i in self.instruction_at.iteritems() if i.name in ("JUMP","JUMPI")):
         if instruction.previous and instruction.previous.name.startswith("PUSH"):
            instruction.jumpto = int(instruction.previous.operand, 16)
            target_instruction = self.instruction_at.get(instruction.jumpto)
            if target_instruction and target_instruction.name=="JUMPDEST":
                # valid address, valid target
                self.xrefs.setdefault(instruction.jumpto,set([]))
                self.xrefs[instruction.jumpto] = instruction
                target_instruction.xrefs.add(instruction)

Any clue on what's wrong with my xref code and why the majority of static jumps resolve to invalid destinations is well appreciated.

Thanks,

tin

  • 2
    can you give us the original solidity please? I believe the compiler adds invalid jumps to a standard location as a convention for doing "throw" – Ethan Jul 24 '16 at 0:11
  • Hi @Ethan, added the original solidity, ref to contract on ethchain, bytecode, excerpt of disassembly with annotation (watch for <--, scroll to the right). – tintin Jul 24 '16 at 22:59
3

The first 0x12 bytes (instructions 0 to 9) should be ignored - these are the constructor used to deploy the code and do not form part of the final deployed code. If you subtract 0x12 from all of your bytecode addresses you should find that everything works out.

E.g. JUMPi 0x26 at instruction 23 will point to instruction 31 (currently at 0x38) after deployment, which is indeed a JUMPDEST.

  • absolutely correct. I used the contract creation code instead of the actual contract bytecode back then. thanks! – tintin Jul 7 '18 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.