FORENSIAWeb3 forensicsOpen workspace

Counting functions in bytecode

A rough estimate of how many functions an unverified contract exposes, and why it is only a lead.

2 min read · Contract analysis

#Plain languageIn plain terms

When a contract has not published its source, you still want a sense of its size. Is it a simple token with a handful of functions, or something with a hundred entry points?

Forensia gives a rough count by looking for a pattern in the machine code that usually marks a function. It is a quick estimate to guide the next step. It is not a list of functions and it can be wrong in both directions.

#How it worksHow it works

Compiled contracts start with a dispatcher. It compares the first four bytes of an incoming call against each function's four-byte identifier, called a selector. To do that, the code pushes each selector onto the stack using an instruction named PUSH4. Counting PUSH4 instructions with distinct values approximates the number of functions.

#Technical detailThe exact rules

The whole method is one pattern match over the code as hex text.

The method
lowercase(code)
match every  63[0-9a-f]{8}        // 0x63 is PUSH4, then four bytes
count the distinct matches

Only the count is kept. The matched values are not stored and are not looked up in a signature database. The result is the finding finding:selector-surface, class lead, confidence low. The same count is taken for a resolved proxy implementation and kept in the proxy record.

#LimitsWhat it does not tell you

  • There is no disassembly. The match does not know where instructions start, so the byte 63 inside another instruction's data still counts.
  • The match runs over hex characters, not whole bytes, so a 63 formed by the second half of one byte and the first half of the next also counts.
  • The compiler's metadata trailer is not removed before matching.
  • Constants that are not selectors, such as 0xffffffff, are not filtered out.
  • For real function names, rely on verified source metadata. This count is for contracts that have none.