Skip to main content

Reversing the EVBox ChargeStation Tool

Project | Article by Maarten Tromp | Published , updated | 2395 words.

In this article I reverse-engineer the EVBox ChargeStation Tool, the proprietary software and USB adapter used to configure EVBox charter up to G4, and document the process of replacing the original adapter with open hardware.

Reading an EVBox charger with the open source adapter
Reading an EVBox charger with the open source adapter

In this article:

Background

After writing an article about getting my charger to work without the EVBox backend, I started receiving emails with all kinds of questions about EVBox chargers, especially now that EVBox has more or less gone under. However, I am by no means an expert on the subject; I am simply a hobbyist tinkering with my own charger.

To configure chargers and ChargePoint modules in larger installations, EVBox provides the ChargeStation Tool (part number 471050). This software is supplied with a proprietary USB-to-RS-485 adapter. Several people asked me whether I had a copy of this software and whether it would work with a generic USB-to-RS-485 adapter, but all I had were a few screenshots. Eventually, the team at Borentik IDF kindly provided me with a copy of the software, which sparked my interest in the proprietary adapter. What makes this adapter so special? Let’s see if we can find out.

My initial thought was that the adapter would be an off-the-shelf USB-to-serial adapter with a modified Vendor ID and Product ID. For some adapters, this can be achieved as simply as adding an EEPROM with the desired values, which would make it relatively easy to replicate. The project would, of course, be easier if I had an actual adapter to analyze.

The ChargeStation Tool software

The software I received is EV-Box ChargeStation Tool Zero, version 1.1.6.271 (32-bit) and version 1.1.6.272 (64-bit). The screenshots I already had are from EV-Box ChargeStation Tool version 1.1.1.360.

The most noticeable differences are that the later version includes "Zero" in the name, and uses blue interface elements, whereas the older version uses green. Since the older version has a lot more options, I assume the later version is a "lite" variant.

Running under Wine

As a Linux user, I wondered whether the software would work under Wine. This also seemed like a good platform for logging and general experimentation. Somewhat to my surprise, the software ran without issues under Wine on the first attempt.

Enabling Wine logging (WINEDEBUG=hid) revealed that the software is looking for a USB HID device with Vendor ID 0x845e and Product IDs 0x0001 and 0x0002. This Vendor ID does not appear in any list of known vendors, which was in line with my expectations. (Note: at this point, I did not yet know that these values are unrelated to the adapter. I still have no idea where they came from.)

I also noticed that the software has a separate window for logging USB HID events. Combined with the Wine logging results, this indicates that the adapter presents itself as a HID device rather than as a serial port. This strongly suggests a microcontroller-based solution rather than an off-the-shelf adapter, which would make it much harder to replicate.

Based on these observations, I updated my hypothesis and now expect the adapter to have been developed by the same party as the charger and ChargePoint modules. Consequently, I expect solid hardware but somewhat questionable software, reusing the same microcontroller, protocol, and implementation as found in the other modules. Luckily, I have some experience with these.

Strings and hexdump

Since running under Wine gave limited raw data, the next step was to look inside the binary itself. Fortunately, it does not appear to be stripped. Here are some of the more interesting strings I came across:

Embarcadero Delphi for Win32 compiler version 35.0 (28.0.46141.0937)
C:\Users\leon\Downloads\jvcl-master\jvcl-master\jvcl\run\JvStringGrid.pas
HID.dll
Device_VID
Device_PID
Device_Serialnumber
DevVID
DevPID
DevSerialnumber
1234hoedjevanpapier
chargestation.exe
ev-box_chargestation_config.ini
SPS-130212

From this, we can conclude that the software is written in Embarcadero Delphi 11 (previously known as Borland Delphi for Win32), using the JEDI Visual Component Library (JVCL).

Many of the strings reference HID.dll method calls, primarily focusing on Vendor ID, Product ID, and device serial number. This reinforces the hypothesis that security is based on VID/PID/serial number and that the adapter uses USB HID rather than USB serial.

Decompiling

Wouldn't it be great if we could recover the original Delphi source code from the compiled binary? For this purpose, I found IDR, the Interactive Delphi Reconstructor.

IDR only supports 32-bit executables, which is fortunately what we have. However, Delphi 11 proved to be too recent, as the reconstructor only supports versions up to Delphi 10.

Static analysis

Failing to get much out of IDR, I turned to Ghidra, which was able to decompile the binary to C. This is much more readable to me than x64 assembler. I started by examining calls to HID.dll and using its methods to identify functions and variables in the reconstructed code. ChatGPT also proved a useful resource for identifying functions, function signatures, and for de-spaghettifying the code. There were very long variables and frequent use of offsets within them, but I assume that is typical for a Delphi binary.

After a while, I came across a function that compared the Vendor ID, Product ID, and device serial number against predetermined values. I then turned to a debugger to inspect these values at runtime.

In hindsight, I was so focused on the comparison function that I initially overlooked the function that called it — which is exactly where all the relevant values were stored in plain sight. But of course, everything is obvious in hindsight.

Dynamic analysis

Since the binary runs under Wine, I needed a debugger that would also work under Wine. Running Ghidra itself under Wine is not trivial, but fortunately there is x64dbg. It can set breakpoints and inspect memory, although it only displays assembler code. As instruction addresses line up with those in Ghidra, I ran both tools side by side.

I set a breakpoint on the comparison function and read the whitelisted values directly from memory. This revealed that the Vendor ID is 0x04d8 (Microchip), the Product ID is 0x003f, and the serial number is "SPS-130212". Later, I also found the Product String "EV-BOX USB-to-ChargeStation-LM" in Ghidra.

These values did not match those observed earlier while logging Wine HID activity, but I have more confidence in the values obtained here. The Vendor ID matches the PIC32 microcontroller I expected to be used, and the serial number appears to consist of the manufacturer name (Small Processor Systems) followed by a timestamp that aligns with the copyright year. At this point, I have enough information to build a compatible adapter.

Simulating an adapter

Raspberry Pi as USB device

How could I create a fully configurable and programmable USB device to simulate the adapter? I wanted a quick and easy solution, and something hacky would be perfectly acceptable for development. This would not be the final product, just a prototype. I have various development boards lying around, but did not want to go through the hassle of setting everything up. Ideally, it would be as simple as writing a Python script.

I did have a few Raspberry Pis and wondered whether they could be used. They seemed to tick all the boxes for rapid development and should have a USB OTG port. However, after spending hours experimenting with different Pi models and images, and reading large amounts of documentation, it turned out that none of my Raspberry Pis could actually do this.

Linux USB gadget

It had never occurred to me that a USB device could be implemented entirely in software rather than hardware. However, that turned out to be a much simpler solution: the Linux USB gadget API. This is a kernel interface for creating software-defined USB devices.

I created a Python gadget, and I now have a software-defined USB device with full control over what goes in and out. This also integrated well with the Wine-based approach, although Wine must be run as root so that USB devices can be passed through.

Within the ChargeStation software, the VID and PID checks passed, but the adapter serial number was always reported as 0x00000000, regardless of the value actually configured. This turned out to be a limitation of Wine, which only implements a subset of the USB/HID stack. I therefore used the debugger to bypass this check, after which the ChargeStation software happily accepted my virtual adapter.

When I press "Read ChargeStation", the adapter outputs: 02 38 30 46 44 45 42 37 39 30 44 03 ff. This is even better than I had hoped: it appears to be the Max protocol, which I had already reversed in a previous project.

And with this, the ChargeStation software reversing is complete.

Connecting a generic serial adapter

To test if it really worked, I connected a generic USB-to-RS-485 adapter to the virtual adapter and forwarded all traffic between the two. The virtual adapter acts as a translation layer, rewriting data from the generic adapter so that it works with the ChargeStation software.

There were a few details that needed tweaking. The ChargeStation software only functions correctly when USB reports are aligned with protocol frames, and when those frames contain no invalid values. As a result, the adapter buffers each incoming frame and filters out invalid ones. Aside from this, the adapter acts as a simple, transparent bridge.

With these changes in place, the virtual adapter worked a treat, and I am now able to communicate with ChargePoint and ChargeBox devices using the ChargeStation software with a generic adapter. Milestone reached! I have updated the Max protocol documentation with the newly discovered information.

This solution is free of charge, but it does require some Linux experience to set up.

Building a physical adapter

While the virtual adapter worked fine as a proof of concept, I still wanted a physical adapter as a true drop-in replacement for the EVBox proprietary one.

My first impulse was, of course, to design a circuit board from scratch. That would certainly be fun, but it would also mean a lot of work. On second thought, selling counterfeit adapters from my website seemed like a bad idea. Instead, let’s see what can be built using commonly available and inexpensive hardware. Everyone could build their own adapters, if they wanted. This approach also saves a significant amount of development time and effort.

The simplest and cheapest solution I could come up with is a Raspberry Pi Pico combined with a WaveShare RS-485 module. The Pico is widely available, well tested, and well supported. I chose WaveShare because I have had good experiences with their products, and there are not many RS-485 modules that plug directly onto a development board. I could not find a smaller, cheaper, or all-in-one solution. This rings up at around 15 euros delivered, and the setup is easy to assemble and flash.

The software side of things was a bit more work, and took a few iterations to get right. First of all I had to restrain myself from writing everything from scratch in Rust. Therefore I started with porting the virtual adapter code to MicroPython. I then discovered that setting a custom VID/PID required building MicroPython from source. After doing that, I created a custom board definition to keep all configuration in one place. At that point, I froze the Python code into the firmware image, so that both could be flashed in a single step. Only once this was finished did I find out that MicroPython has no USB device support. I had confused it with CircuitPython.

The next day, I repeated the same process for CircuitPython. This solved the USB device issue and provided configurable VID/PID support. However, there was no clean way to set the USB device serial number. As a result, in addition to the custom board definition, I ended up patching CircuitPython to get this working. Freezing the Python boot and main code is not supported by CircuitPython, so flashing has to be done in two steps.

Once this was complete, the physical adapter fully emulated the EVBox adapter. You can use the unmodified version of the ChargeStation software on a stock Windows computer to connect to your charger using this adapter.

This solution costs a small amount of money and requires some electronics experience, but it works with a stock computer.

Patching the ChargeStation software

A final option would be to make the ChargeStation software work with a generic adapter. This approach would be easy to distribute and would run on a stock computer.

The idea would be to reverse-engineer the parts of the software that handle communication with the proprietary adapter, and then write drop-in replacements that talk to a generic adapter instead. By trampoline-patching the original binary to redirect these calls to the new code, the rest of the application could remain untouched. This would offer the best of both worlds: a generic adapter while still using the original software.

While the technical challenges are certainly interesting, I’m not interested in maintaining closed Windows software. This project has always been about openness, and patching proprietary software for a closed operating system runs counter to that philosophy.

Connection to ChargeBox

On the ChargeBox, the RS-485 interface is exposed on the black 2-pin connector (Phoenix Contact MC 1.5/ 2-ST-3.5 ). Pin A is closest to the blue connector; pin B is closest to the black 3-pin connector. If communication does not work, try swapping A and B.

No termination or separate signal ground connection is required for typical short connections.

Open source

Everything in this project is done using free and open-source software and hardware wherever possible.

Accordingly, the software, article, and documentation I created for this project are released into the public domain. You can find the relevant files in the downloads directory associated with this article.

The exception to this is anything I did not create myself, as it is not mine to give away. This includes the EVBox software and protocol, which remain subject to their original licences and copyright.

Closing thoughts

This project started as a leap into the deep end for me. I had never done this kind of reversing before, but it was fun to learn it. I've had my eye on this adapter since the previous reversing project, and this was the opportunity I was waiting for. Opening up closed systems has always appealed to me, and this project turned out to be a good excuse to do exactly that.

Along the way, it touched on a surprisingly wide range of topics: from Windows to Linux, software to embedded hardware, assembler to Python, and both reverse engineering and forward engineering. Looking back, it is surprising that all of this came together in roughly a week of work.

Hopefully, this work will prove useful to others who are stuck with EVBox chargers that depend on a backend which no longer exists. At the very least, it documents how the ChargeStation Tool and its adapter behave, which should make further work easier.