
Train Chiptuning
During the last (almost)5 years I worked with trains. And one question stuck with me the whole damn time. Can you chiptune a train to make it go faster? Of course this isn’t a serious question, but it implies some other questions that are a bit more serious. Like, how hard can it be to hack a train, and if it’s easy, how bad would that be?
Then came the 37C3 and I watched the talk about Breaking “DRM” in Polish Trains. From this moment, I was nerdsniped.
Selectron Systems
One very common automation system used in railway vehicles is Selectron-MAS. Selectron is a Swiss manufacturer of automation systems, over time they more and more specialized in railway vehicle automation systems. As far as I noticed, they supply many railway vehicle manufacturers. A CPU from them was also used in the “Polish Train”.
TCMS
A train consists of many systems, from current converters, doors, lights to toilets and Displays. Other than in a car, which also consist of many systems, which can communicate to one another more independently, in a train those systems are connected to one central Train Communication and Management System. The brain of this system is in most cases one or two CPUs which are running the same software and monitor each other for redundancy. Those CPUs are called VCU (Vehicle Control Unit). There could also be another CPU for the most critical systems, called SCU (Safety Control Unit).
The VCU is connected to most subsystems and also to most of the hardwiring through RIOMs (Remote Input Output Modules). Those RIOMs are connected to the VCU via some bus system, most commonly CANopen or Ethernet. In case of Siemens sometimes also AS-Interface, Profi-Bus or Profi-Net. By the way: Look up AS-Interface, those connectors are freakin cool.
Did someone say Tricore?
There is a specific generation of CPUs from Selectron that uses a specific microcontroller family from Infineon, the Tricore. And do you know where the Tricore family is also very commonly used? In Engine control units (or ECU) of cars! Interestingly, this seems to be the intended application for Tricore microcontrollers.
The thing with ECUs of cars is that there is a community dedicated to reverse-engineering ECU code in order to change engine mappings to gain more power without changing hardware. Because of this, reverse engineering of Tricore code is not that uncommon.
The Tricore microcontroller family is pretty ideal for the application as a VCU in trains, it has a CAN interface, Ethernet Interface, is rated for automotive applications, so for things that move and vibrate and has a nice debugging and monitoring interface. Ideal for PLC-style debugging.
IEC61131 code
The 61131 IEC standard was defined in 1993 and hasn’t changed much over time. It’s actually a pretty nice programming language for handling I/O’s. IEC61131 code is everywhere, in industrial machines that produce all of your things, in trains, in infrastructure, etc. Reading and writing the code is daily business for most Industrial Electrical Engineers.
Standard
The standard for software development for railway vehicles is DIN EN 50716, which describes the process for software development, what documentation has to be done and how the documentation has to be done.
The thing with software for safety critical systems is, it needs to reduce complexity everywhere possible. The code needs to be as clean as possible, the tools that interact with the software at any point in the development need to be understood as good as possible.
In the DIN EN 50716 the tooling that interacts with the software is categorized in 3 different categories, T1, T2 and T3.
T1 tools are tools that don’t alter the code and can’t obscure faults, like a code-checker that checks the grammar of code comments for example.
T2 tools are tools that don’t alter the code but can obscure faults if used improperly, like a testing tool.
T3 tools are tools that alter the code and can introduce faults by doing so. Like a code linter or a compiler.
Now you might think that the T3 tools need to adhere to strict requirements and rigorous testing, at least that’s what I was expecting. But the requirements are pretty vague.
Anyway. Compiler.
Compiler
The compiler is a very widely used C-compiler. And because of the requirements for safety critical software, it does no optimization whatsoever.
The C-compiler can’t directly compile the IEC61131 code of course. That’s why it needs to be transpiled from the IEC61131 language to C. This is relatively easy if you consider that any IEC61131 language is just a different representation of C. Especially for Function-Block-Diagram it’s pretty apparent. It’s kinda like drawn C-code. So, like svg-c. hehe.
FBD to C
When looking at some examples of C-implementations of FBD functions and functionblocks.
Functions are operations without any memory-value, like AND, OR or Bitshifts. Here are two examples of AND and OR operations with the respective C-implementation.


Functionblocks are operations that hold memorized values which influence the return value. One example for this would be an RS-Functionblock. The C-implementation of this functionblock is a little more complicated, but not that much.

There is a struct, which is the representation of the header of the function. The instance of the type is used to hold the memory of the function. The function itself has no memory.
The compilation is deterministic and thus, reversible?
A compiler must be deterministic, if it weren’t, you could never be sure that the program really does the thing you want it to do. But just being deterministic, does not make it reversible. So to be able to (easily) reverse the compiled machine code back to something that can be read and edited, it still needs to contain enough information to do so.
Remember the debugging interface of the Tricore? With this interface you can read and set variables (in the implementations of train CPU’s). There is a lookup table for these variables, that is often accessible to maintenance persons to perform troubleshooting. It is just a csv file that has the variable name, the default value, the datatype and, most importantly, an “address” for every observable variable. Observable variables are all variables that are defined by the user (user means the developer). With access to this lookup table, it is really easy to connect a variable name to a machine code variable. But what if there is no access to this lookup table?
Reverse Engineering
The paragraph of FBD to C described that FBD can be interpreted as a graphical representation of C. The transpiler is also deterministic, which means that the transpiled C-code is easily reversible to FBD.
The software architecture of the transpiled C-code follows the style of a typical IEC61131 project. This is important, because it’s a pattern. Keep that in mind.
When reverse engineering compiled machine code, you don’t just look at a black screen with green 0s and 1s. I mean, you could, but that would make no sense. Instead, you use a software that reverses compiling, by decompiling. What you get out of that software after decompilation is assembly code, which is very low-level. But even the assembly representation of the code gives broader information about memory organization, especially when comparing it to the memory-map of the Tricore microcontroller. The reverse engineering software I am using is ghidra, which is open source and used by many people in the reverse engineering community. Ghidra can not only decompile machine code to assembly, but can also give a representation of that assembly code as C-code. And this C-code representation of the machine code looks damn similar to the transpiled C-code.
The only problem left before finally being able to read the code is that there are just some numbers and letters as variable- and function names. But when the transpiled C-code looks so similar to the decompiled C-code, and compilers are deterministic, then functions can be identified by looking for the pattern of the function in the decompiled code. Of course this only works for standard functions that always have the same pattern, but thats also just what I am looking for.
Now there are still the instance- and variable names left, that don’t make sense yet. As mentioned somewhere above, if the lookup table is accessible, that’s not that big of a problem. If not, identifying those is a little more involved, but not impossible.
Patterns everywhere
Just as there are patterns emerging from deterministic compilation, there are also patterns emerging from what the code is supposed to do. For example, many similar operations on variables that are close to each other in memory, can be an interface. The size of the interface or the datatypes can tell what system the interface might be for. Or a more train-specific example, a part of the program with many variable value comparisons of variables bigger than one byte can be break-system control or speed control.
Literals
It can be even easier to identify variables and instances, when there are string literals in the code. It’s debatable if it’s a good idea to put string literals in embedded code for controllers that have a very limited flash capacity. But it can be the case, that some error- debug- or info messages are stored in flash as string literals. Those damn Literals!
Security
Of course editing the firmware and flashing it onto the CPU is made impossible by having mandatory code signing in the development process for safety critical software. right? right?? No. It is possible to sign the code, but not mandatory. And signing costs money, so companies tend to not do it. There is just a checksum for the project that gets checked by the operating system when loading the project from flash to ram. But this is meant for safety reasons. At least the OS is signed.
Operating system?
In this paragraph, I will talk about the “project” and the “user application”. With this I mean the software that gets written by the train manufacturer.
In case of Selectron CPU’s from the 8xx generation, the OS is proprietary and lives together with the project in user flash of the Tricore controller. The OS does… what an OS does, so handling the execution of the user application, providing abstracted access to peripherals and of course providing the debugging capabilities.
Conclusion
So, is it possible to do chip tuning on a train? Yes, and it’s easier than I thought. It’s really just about finding the correct variables, modifying the code, generating a new hash and flash it back onto the CPU. Kinda like a chip tune on a car.
Something bothers me about the fact that a vehicle that carries hundreds of people can be manipulated without any cryptographic protection. There is not security through obscurity.
About Me

Hanna Lieding
Software/Electronics Engineer
Hello, I’m Hanni, I like to mess around with electronics, cars, drones, 3D-printers, code and broken things.
Leave a Reply