New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

A Deep Dive into EOF and Its Impact on Program Analysis | Louis Tsai, Amber Group | ETHTaipei 2025

ETHTaipeiThu, Oct 9, 2025, 12:00 AM

A Deep Dive into EOF and Its Impact on Program Analysis | Louis Tsai, Amber Group | ETHTaipei 2025

Transcript

[Music] Um hello everyone welcome to my session today. My topic is a deep dive into EOF and is it impact on program analysis and what is EOF? Uh oh. What is EOF? EOF stands for Ethereum object format.

And in today's session, I will um demonstrate how our tools and EOF facilitate and help with static analyzer in control flow analysis. And before we dive deep into the topic, please let me first introduce myself. My name is Louis from Amber Group. I'm currently the web3 security research intern. In Amber Group, I contribute to MOSRA, a GRA based EVN decompiler developed by our team.

And here is today's agenda. First, we will begin with a brief introduction to Fusaka upgrade and EOF upgrade. Then we will take a look at the current limitations of legacy EVM contracts and the uh Ethereum virtual machine architecture especially the challenges we faced during program analysis. Then I will highlight the key features of Ethereum object format and how and how the EOF help with uh program analysis and uh control flow analysis. Then I will come back to MOSRA and demonstrate how uh we integrate EOF into our tools.

EOF it is not a standalone upgrade. It is part of the Fusaka upgrade. The Fusaka upgrade is the upgrade after the packrups upgrade. Fusaka upgrade introduces significant changes in Ethereum's execution layer especially the Ethereum virtual machine part. If you want to know more details about uh Fusaka upgrades and the Ethereum object format, you could take a look at the following two EIPs.

And what is the current uh what does uh what what problem does EOF try to solve? The first one is the stack to deep issue. Although it is not a problem for the Viper comp compiler, but it is a long-standing issue for the Solidity compiler. When we want to pass data across functions, first we need to pass the data onto the stack and we should we could access it later using swap or dupe operation. But in legacy EV up code, it only supports access up to 16 stack position.

This limited range could be uh easily exceeded for complex functioning and nested logics. However, in EOF EIP 663 is introduced and three new up codes are created. They are swap end, dupe end and exchange allowing uh for the first two up code they are extended version for dupe and swap operation allowing access up to 256 labels deep for the exchange up codes. you could provide an immediate value and specify which two stack position should be swapped. So this uh solve the previous limitation in uh the stack management issue and the other issue is there is code deployment validation issue.

Currently we could deploy undefined or invalid B code on Ethereum network. However, this is impossible after EOF is activate because uh several uh validation rules are introduced in EF. All the by code deploy will be validate during the deployment time and all the immediate value should be proper properly provided as well and learn more validation rule and finally it is the um the legus EVM has a defined structure but in EF a versioning header will be introduced and there will be a welldefined layout for the UFO compatible by code. We have talked a lot about the changes in UF. However, this is not our focus today.

Today we will be concentrated on program analysis part and how EOF help with program analysis. So what do we want when performing the program analysis? When we perform the program analysis, first we want to segment the by code into functions and then uh to segment the B code into functions that is to detect the function boundaries and then we could decode key parameters for example the input arguments or output arguments for list functions. And then we want to know how one function interact with one another. To achieve this goal, we need to detect several patterns.

First, we need to detect the co- patterns and then we need to detect the return pattern. The branch pattern is also important in control flow analysis but uh we will talk it later. We will discuss it later. And in legacy EVM, it only supports dynamic jumps. So it only use jump to represent both co and return pattern.

That makes it difficult for static analyzer to distinguish whether a jump represent the co- pattern or the return pattern. And in Mosa we create an analyzer to distinguish list patterns first. And this is uh how it works. First when we encounter a jump operation we will check its preceding operation. If the preceding operation is a push operation we will classify it as a code.

However, if the preceding operation is pop, swap or jump test, we will classify it as a return. So now we are able to decode the co and return pattern. But that is not enough. We want to further decode the return address and the number of input arguments for this functions. And we built another analyzer for analyzing this data.

For the return address, we first locate the basic blocks that contains the co- pattern. You can see there is a jump with a preceding push. So this is a co- pattern and the return address is usually the program counter after the co- pattern. So this 5C is the return address. And this this program counter is pushed before the code pattern.

So you could you could see a push operation in the same basic blocks. And how do we decode the input argument numbers? The algorithm is we could simply analyze the ST change between the push operation and the code pattern. There will be some additional rule to handle the H case but we will skip the details here. So by analyzing uh this green section here for the state change we could derive the input argument numbers.

However, what could we decode the output argument numbers? To be honest, we we do not know the answer. And this is the simple workflow like uh we mentioned earlier. Here we can see a co- pattern and a return pattern. And there is a push operation that push the return address.

And this purple section is where we decode the input argument numbers. But this is not always straightforward because we could not decode the input argument numbers without executing the bico sequence. But sometimes it it becomes complex like this one. And this is how EOF simplify the control flow analysis or the program analysis. Here we will come back to EOF introduction and show you how it improve program analysis.

This is a simple counter contract and I compile this contract using the legacy EVM compiler and I pass it into Moseras uh into Mosa and here is the display result for Mosas listing view. As you can see in the legacy event contract there's no specific format for the by code and all the contract logics starts at offset zero. However, list is different in Ethereum object format. In EOF everything is organized as a container and in a container there is a header part and a body part. In a header part um in EF it introduce different kind.

We have the type kind, we have the code kind, the container kind and the data kind. And the header stores important meta data for each kind like its size while its actual content the value associated with is logic or data is stored in the body part and this is the visualization of the eof contract layout. First we will have the header part as we described earlier and then we have the body part and at the beginning of the header part we have a magic value to distinguish whether this bode is ef compatible or it is from legacy EVM contract and the value is ef000 and just To clarify, EF here represents executable format, not Ethereum foundation. All right. And there is a following one byte number that represents the version.

And the following section is uh the meta data for each kind. First we have the type kind. The type kind contains important information uh for each code section. However, we will discuss it later. Next, we have the code kind.

Each code section here would represent one function in EOF by code. And after the code kind uh here is the total number of code section and and here is the list of the size for each code section. And then we have the container type. It is interesting that an EO compatible by code itself is a container. But here we could have nested container.

However, it is not a most you could have zero nested container or you could have multiple nested container inside one container. And finally we have the data kind. In EF the code data separation pattern is introduced. The contract logic is stored in the co- section while the data like the constant or immutable values store in smart contract is placed in the data section and there is a terminator that separates the header section and the body section. If you want to visualize the EOF bico layout by your own, you can use this website efo in the website and it will decode uh the meta data in the header section and decode each section for you.

If you are using Foundry as your testing framework, you could add this flag to compile your contract with the EOF compatible compiler and then you can pass the B code generate to list cast code and then the format will display directly in your terminal. you know like the following result. All right, we we have a brief introduction to Ethereum object format but how list changes help with program analysis. Like we have discussed before in program analysis the first goal for us is to decode the function boundary. In eof we have the co-section and each co-section represents one function.

So now we no longer have to decode the function boundary. and lands in EOF a new up code is introduced. It is the co-f up code. The co-fold would represent the co- pattern. So now we have the co- pattern and uh there's also some semantic changes during execution.

Now for each co-section it has its own program counter scope. So the program counter would reset to zero at the beginning of each code section and a new component the return stack is introduced when we perform the co-f operation. These two items are are pushed onto the return stack. It is the first one uh is the co-section index and the next one is the program counter after the co-f operation. They're combined together and pushed onto the return stack.

And what about the return pattern? Another operation return f is introduced. In return f one item will be popped from the return stack and the current as uh it will returns to the co-section uh specify and the program counter that is provide in the previous co operation. And what about those non-returning functions? For non non-returning functions, we have jump f and it is defined in a stab EIP.

For jump f, it will not push any items onto the return stack. That means when it jumps to the target code section, it will not return. And we already have uh the code pattern and the return pattern. Then how do we detect the input argument or the output argument? We have mentioned in UF header there is a type kind.

In the type kind each entry consisting of four bytes. It contains the input arguments number and the output argument numbers as well as an information for the max stick height. So here we could directly read this information from the type section. Do you remember how we decode this value in the legacy EPN contract? It is so complex but now it becomes very easy.

So here is a quick summary in program analysis. We want to detect the function boundary and we also want to detect co- pattern and return pattern. And now the co-section each co-section would represent one function and the co-f and jump f would represent the co- pattern and the return f would represent the return pattern and we all we also mentioned the branch pattern is important as well in control flow analysis in the latest EBN contract we also use dynamic jumps or the branch pattern we use jump I but in EF compatible by code we use list three up codes for list three up codes you should provide an immediate to specify the offset you will jump to so it will be more easier for static anal analyzer to extract the value from the B code and it would help us uh combine this together. It will help us reconstruct a more concise control flow graph and the process will be simplified significantly. And finally, we no longer need the dynamic jumps.

So the following three operations jump, jump I and jump desk is duplicate in EOF. And that is also a good news for um the Ethereum client because they no longer needs to validate the jump test during the runtime. and then we will come back to Mosa and show you how we integrate EOF into our tool. Let me first briefly introduce Musra. Musra it is a Gedra based EVM decompiler.

Gedra is a very popular web to decompiler and you could build extension on top of GDRA. DRA supports multiple architectures for example x86 or ARM or and more architectures but it does not natively support EVM. So however it has some powerful features like the the control flow graph uh reconstruction and like the compiler features. So we built Mosra and supports the 256 bits for the EV compatibility and we also built multiple analyzers to perform program analysis and this is the workflow for program analysis in Mosra. First we will compile the contract into by code or you can fetch it on ether scan or um anywhere else and pass it into our custom loader which perform pre-processing for the content and then the data will be passed to different analyzers.

We have the function analyzers that detect uh different patterns and we have the input arguments analyzers that performed the algorithm that we extract the input arguments number and we also have this disassemble analyzers and uh we define the SL uh definition for each bode. So um this disassemble analyzer will convert the up code to intermediate representation using this definition and help us uh displayed the decompilation window and the decompilation view. And there are also other views that will be provided in Mosa like the control flow graph or the listing view. And this is how we handle the legacy EVM decompilation. But in EOF we no longer need in EOF we don't no longer need this one because we have uh co F the return f and jump f.

And we also do not need this one because we have the type section. And um in in uh for for handle the eof bode we further uh we further defined the slay definition for the new newly added operation like this is co for example we're inspired by the x86 jump jmp operation and this is how we define the co-f up code and after all the works this is the final result for the the function code graph in Mosra. This is impossible for us to reconstruct this concise graph in legacy EBN contract because the program analysis um was very difficult. But with the features in EOF it becomes much more easier and this is a very beautiful control flow analysis graph for in in each function and this is also impossible in legacy EV contract because we need to tackle with different patterns and uh there's no specific layout in uh the bico sequence but With EOF everything becomes more easier and um possible and we could develop if we could develop even more powerful analyzers for uh the B code. So this is uh all my presentation today.

I hope uh everyone uh attending this session learned something about uh Ethereum object format and the program analysis. And if you have any questions, you could uh send your question to list email or contact me on Twitter. And this is our tool. You can try it out um and also contribute to our tool. All right.

Thank you for listening today. Thank you, Louis. Great talk. So, we have two minutes, so probably one question. Any question?

Okay, this gentleman waiting for the mic. Hey, I really like the detailed examples you gave on the slides. Um I was wondering with like the structure we get from EOF if there's any assumptions we can make during execution time for any runtime optimizations. Um that's a good question. So you mean um based on UF uh whether we could uh do some optimization for the by code?

Yeah. Yeah. Um I'm not very sure because uh most of our work focus on the decompilation part of the bico. So I I'm not very sure uh how the ef will facilitate the runtime execution. But uh like we mentioned earlier there is exchange or uh swap in dup end operations.

uh it will significantly help with the stack arrangement in the leg uh in EVM because uh in the past we need to use a lot of pop or swap operation to rearrange the ST element but now we could simply use exchange or we could use swap end just one operation to uh to uh place the uh item on a desired position. Yes, thank thank you for your question. Okay, so no more questions. If you have more questions, you can sorry, you can reach out to Louis directly. So, thank you for the thorough explanation about EO app.

So, thanks again to Louis. Okay. Thank you. Okay. [Music]

Automatic transcript — names and jargon may be misspelled.