Chainhunters
Reverse engineering van smart contracts is een belangrijk proces voor iedereen die zich bezighoudt met blockchain-technologie, van forensische onderzoekers tot ontwikkelaars die de veiligheid van hun eigen contracten willen waarborgen. In deze blogpost leer je wat smart contracts zijn, waarom je reverse engineering zou toepassen en welke methodes, tools en best practices er bestaan om deze complexe analyse uit te voeren.
Smart contracts vormen de ruggengraat van blockchain-gebaseerde applicaties. Ze automatiseren transacties en leggen afspraken vast zonder de tussenkomst van een derde partij. Met deze automatisering komt echter ook de noodzaak voor veiligheid en transparantie. Eventuele fouten of kwetsbaarheden in smart contracts kunnen direct gevolgen hebben voor de gebruikers en hun middelen.
Lees hier meer over wat Smart Contracts zijn: Wat is een Smart Contract?.
Smart contracts zijn zelfuitvoerende programma’s waarbij de voorwaarden tussen koper en verkoper direct in code zijn geschreven. Deze worden opgeslagen en uitgevoerd op een blockchain-platform (zoals Ethereum), waardoor onafhankelijkheid van traditionele financiële instellingen wordt geboden. Doordat de uitvoering van de code openlijk traceerbaar is, wordt vertrouwen gegarandeerd. Een belangrijk nadeel is echter dat alle functionaliteit (in de meeste gevallen) permanent is zodra het contract is gedeployed.
Zodra je een smart contract uploadt naar een platform zoals Ethereum, wordt de bytecode publiekelijk zichtbaar (bijvoorbeeld op Etherscan). Als de ontwikkelaar de code niet verifieert, is de originele broncode onzichtbaar en moet je vertrouwen op de gecompileerde bytecode. Dit gebrek aan transparantie kan problematisch zijn voor:
Hieronder vind je een voorbeeld van een heel simpel smart contract in Solidity en de bijbehorende bytecode. Bij niet-geverifieerde contracten zie je alleen de bytecode, wat de eerste stap is in het reverse-engineeringproces.
contract SimpleStorage { uint private storedData; function set(uint x) public { storedData = x; } function get() public view returns (uint) { return storedData; } }
608060405234801561001057600080fd5b50610150806100206000396000f3fe
Wanneer je alleen de bytecode hebt, moet je disassembleren en/of decompileren om de werking van deze code te achterhalen.
Het analyseren van de bytecode is vaak de eerste stap:
Ondanks de kracht van geautomatiseerde tools blijft handmatig onderzoek essentieel. Veel kwetsbaarheden zijn logisch of contextueel en kunnen alleen ontdekt worden door een ontwikkelaar of onderzoeker die begrijpt welk gedrag er wordt verwacht.
Een van de meest iconische voorbeelden is het contract achter CryptoKitties. Hieronder vind je enkele links naar de bytecode en gedecompileerde code:
De EVM-opcodes kunnen bijvoorbeeld als volgt starten:
PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x0036 JUMPI
Na decompilatie kan een Solidity-achtig script verschijnen:
function transfer(address _to, uint256 _tokenId) public { require(_to != address(0)); require(ownerOf(_tokenId) == msg.sender); _transfer(msg.sender, _to, _tokenId); }
Hieronder een voorbeeld van hoe je Manticore zou kunnen gebruiken om symbolische tests te draaien:
from manticore.ethereum import ManticoreEVM m = ManticoreEVM() user = m.create_account(balance=1000) contract = m.solidity_create_contract(''' contract CryptoKitties { function transfer(address _to, uint256 _tokenId) public { require(_to != address(0)); // Stel je voor dat er een ownerOf() functie bestaat require(ownerOf(_tokenId) == msg.sender); _transfer(msg.sender, _to, _tokenId); } } ''', owner=user) to_addr = m.make_symbolic_value() token_id = m.make_symbolic_value() contract.transfer(to_addr, token_id) m.finalize()
Wanneer de broncode wel beschikbaar is, blijft een handmatige review onmisbaar om:
Probeer eens de onderstaande bytecode te herleiden naar de oorspronkelijke Solidity-code en test je reverse-engineeringvaardigheden.
0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c806375cd6fe01461002d575b5f80fd5b61003561004b565b60405161004291906100f8565b60405180910390f35b60606040518060400160405280600d81526020017f476f65642067656461616e212100000000000000000000000000000000000000815250905090565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ca82610088565b6100d48185610092565b93506100e48185602086016100a2565b6100ed816100b0565b840191505092915050565b5f6020820190508181035f83015261011081846100c0565b90509291505056fea2646970667358221220e508a7b26b1035deb0de68430764dd686ed8ec2af10b5b70f524b730eaa7cf3564736f6c634300081a0033
Kun je ontdekken wat de functies doen en het verborgen bericht in de code vinden? Tools als disassemblers, decompilers en symbolische executie zijn je beste vrienden bij dit soort uitdagingen.
Reverse engineering van smart contracts is essentieel om:
Een goed begrip van EVM-opcodes, Solidity, tools voor decompilatie en statische analyse, en het toepassen van handmatige audits is cruciaal voor het bouwen aan een veiliger en transparanter blockchain-ecosysteem.