Pages: [1]
Author Topic: Reversing of simos7.1  (Read 1046 times)
fknbrkn
Hero Member
*****

Karma: +219/-24
Offline Offline

Posts: 1556


mk4 1.8T AUM


« on: January 04, 2026, 08:05:52 AM »


  • An old Simos7 ECU, part number 06A906033DM, with a Euro2 modification “with ecology” in the classic “bring me back to 2007” style — lots of P0000 errors, glitches, etc.
  • The ECU itself is unavailable at a time, a software-only approach is used initially.
  • The closest available references are the Funktionsrahmen for Simos 8.5 and a DAMOS for 3.2 FSI VR6 CALA. Practical overlap is close to zero.
  • Known hardware: C167 CPU and 29F400BB flash memory. This combination is relatively straightforward to reverse.

---

Loading the firmware into IDA PRO

The firmware is loaded into IDA PRO. The first step is locating the DPP registers:

Code:
seg080:0634 E6 00 12 00 mov DPP0, #12h
seg080:0638 E6 01 14 00 mov DPP1, #14h
seg080:063C E6 02 13 00 mov DPP2, #13h

Multiplying these values by 4000h reveals the calibration segments:
0x48000, 0x50000, and 0x4C000.
Unlike Bosch ECUs, the 0x800000 base is not used here.

An existing ME7 script by Andy Whittaker is adapted to these values, resulting in readable code so far

Note on DPP:
For details, refer to the CPU documentation. In short, DPP provides compact 16-bit addressing for different memory segments. Since the CPU is 16-bit but memory space is larger, full extended addressing would require additional instructions. DPP windows are therefore used for fast access. Typically, some DPPs point to calibration areas, while others point to RAM.

---

Finding an initial reference point

The Euro2-modified firmware is used to locate a simple and well-known element, such as the IGA_BAS ignition angle. Parameters of this type usually originate from very early ECU generations, and Simos is no exception.

A simple comparison with WinOLS shows that the modification in the Euro2 file strongly resembles an ignition angle change.

Bosch ECUs are generally easier to reverse because map axes and their sizes are often placed directly before the map data. Uncommon in Siemens.

Additionally, on C167 processors, map addresses are passed as plain immediate values:

Code:
mov r12, #03FACh

This is just a number that is later interpreted as an address. While it is possible to write a script to automatically convert such values into addresses, doing so for a single ECU is not practical.

A simpler approach is visual inspection. A sequence such as `74 74 74` looks like the beginning of a map (e.g. 0x4AFCC). Searching for `FCCh` in IDA typically yields results where usage together with registers r12, r13, or r5 indicates a map or axis reference in the vast majority of cases.

Such a reference is located. So far so good.

---

Map access characteristics in Simos

Compared to Bosch ECUs, map access in Simos looks unusual: first one axis is evaluated, then the second axis, and only afterward is the map value fetched.

Since the values originate from DPP0 (12h), Ctrl+R is used to assign the base address 0x48000 (12h × 4000h) to all registers holding addresses (commonly r12, sometimes r13).

If there is uncertainty whether a value represents an address, the called procedure can be inspected. If the register later appears in square brackets (e.g. `[r12]`), it confirms that an address was passed.

After this adjustment, proper references into the calibration area become visible. Axis sizes are found before the axes themselves, and the layout appears consistent.

This yields a valid intermediate result.

---

Map validation

In this case, the map size is identified as 16×12. The values 0Ah and 0Ch preceding the axes confirm this.

An axis size of 16 corresponds to engine speed (RPM), while a size of 12 corresponds to MAF. The variable associated with these axes therefore represents MAF versus RPM. Naming conventions may follow Bosch terminology for convenience.

Map calculation routines typically return the result in register r4. This is verified, and it is assumed that the ignition angle value is written to address 0D22Fh.

This is not considered the final ignition angle. The exact purpose of this particular map is not yet fully known, and multiple ignition-related maps may exist.

The important outcome is that RPM and MAF have been identified and the general mechanism is understood. With known addresses, coefficients can be taken from Simos 8 and applied to this map.

The result appears plausible, confirming the approach.

It is also recommended to review cross-references and identify 8-bit clones of variables. These are commonly used for diagnostics and may be useful later.

---

Limitations and further strategy

This approach alone is insufficient, as firmware variants differ significantly and further understanding is required. A parameter such as `c_tps_max` (maximum throttle angle) may be found, but this alone is not enough.

Reverse engineering typically involves identifying known patterns, educated guessing, and leveraging external reference points. In the case of engine control units, useful external stimuli include:

  • CAN bus identifiers and message layouts, which largely match ME7.
  • Connector pinout information, allowing signal tracing from pins to internal logic.
  • KWP1281 measuring blocks, whose channel descriptions are available in VCDS label files (this is not UDS).

The CAN-based approach appears promising but, in Simos, message IDs are not stored explicitly (or are not easily located). Even their offsets may be absent.

The pinout-based approach involves reviewing ME7 documentation and schematics (e.g. BSF). In practice, these do not match sufficiently.

---

Variable Intake Manifold (VIM) as a candidate

A practical candidate is the intake manifold flap, which is known to switch around 5000 RPM. Its control map typically consists of binary values (0/1), and engine speed has already been identified.

Various ME7 reference spreadsheets are examined without success. However, one reference to “swirl diag” stands out. While abbreviations such as PMOEL or TKY are unclear, Bosch refers to the intake flap as SU (SaugrohrUmschaltung), whereas Simos uses VIM (Variable Intake Manifold).

Processor output pins are known and statically mapped in IDA. These ports are binary. In code, their state is usually controlled with instructions such as:

Code:
bclr p2_4
bset p2_4

Here, `bclr` enables pull-down, while `bset` leaves the line floating. A quick search for `p2_4` in IDA leads to a simple routine based on RPM and throttle angle.

The resulting map is binary, as expected for an intake flap. After populating the axes, the result appears plausible.

In addition to direct port control, several additional bits are modified, referred to here as `vim_3` and `vim_4`.

Note: Instead of ones, any non-zero value (even arbitrary data) would work, since the logic only checks for zero.

The intake flap is also convenient because it appears in diagnostics.

---

Diagnostic representation (KWP1281)

Quote
095,0, Variable Intake Manifold (Single Stage Changeover)
095,1, Engine Speed, Specification: 640…900 RPM
095,2, Engine Load
095,3, Coolant Temperature, Specification: 80…115 °C
095,4, Variable Intake Manifold Status, Display Range: ON/OFF

The key observation is that block 095.4 is displayed as ON/OFF.

In KWP1281, diagnostic values are transmitted using a formula number and parameters. The tester interprets the formula number to determine scaling and units. The relevant formula here is 37, which represents textual values.

From the KWP1281 specification (e.g. `text_table_EN.h`):

Code:
const char KWP_TEXT_0087[] = "ON";
const char KWP_TEXT_0088[] = "OFF";

Thus, `vim_3` / `vim_4` map directly to diagnostic values 0x87 and 0x88. Cross-references confirm logic that outputs 0x88 when the state is false and 0x87 when true, clearly indicating diagnostic output.

---

Logged
fknbrkn
Hero Member
*****

Karma: +219/-24
Offline Offline

Posts: 1556


mk4 1.8T AUM


« Reply #1 on: January 04, 2026, 08:06:56 AM »

the pepe picture posted by mistake but i cannot edit attachments for some reason  Roll Eyes

part 2

Function dispatch and tables

Unlike Bosch ECUs, no obvious static table mapping diagnostic variables to measuring blocks is visible. Each block ends with an unconditional jump to `lloc_end`, yet execution still reaches the corresponding calculation routines.

This implies the presence of dynamic dispatch via instructions such as:

Code:
jmpi cc_uc, [reg]

Such blocks are located later.

It is assumed that a table exists containing entries of the form:
ID → function address(es), one per diagnostic value.

The intake flap handler is located at address 0x34782. Searching for the binary pattern `82 47` yields only two matches, one of which resides in DPP2:

Code:
dpp1:0CDA 82 47 dw 4782h

Converting this to an offset with base 0x30000 leads directly to the corresponding function. Neighboring entries resolve to other diagnostic functions. The table can be structured and conveniently converted using IDA (e.g. Alt+Q), and the function is renamed to `vim_diag`.

This table contains preparation routines for diagnostic values rather than direct measuring block layout. A separate mapping table likely assigns these functions to measuring block channels.

---

Dynamic function selection

The table base is found at 0x50A9E, referenced by the following code:

Code:
seg8:0974 mov r4, [r0+10h]
seg8:0978 mov r5, [r4+2]
seg8:097C cmp r5, #159h
seg8:0980 jmpa cc_UGT, lloc_end
seg8:0984 shl r5, #1
seg8:0986 add r5, #4A9Eh
seg8:098A mov r5, [r5]
seg8:098C jmpi cc_UC, [r5]

The value 159h (345) appears to be the number of diagnostic variables, which is plausible for this ECU generation (ME7 has ~700).

Additional similar blocks exist with smaller array sizes (5–10 elements), identified by similar patterns.

---

Applying the method: coolant temperature

As a practical example, coolant temperature is examined:

Quote
131,0, Mapped Cooling
131,1, Coolant temp., engine outlet (actual), 80…115 °C
131,2, Coolant temp., engine outlet (specified), 0…115 °C
131,3, Coolant temp., radiator outlet, 0…100 °C
131,4, Thermostat duty cycle, 0…100 %

The target is channel 131.2. Using the same approach, offsets are resolved:

Code:
dpp1:1D10 85 0F 4C 01 ; group 131
dpp1:1D14 85 0F 4F 01 ; target

This leads to function pointer 0x50D3C, which resolves to:

Code:
seg8:3A94 tmot_sp:
...

The routine reads `byte_D452`, applies scaling and offset, and outputs the result to diagnostics. A configuration bit (`loc_FD5E.2`) can disable this output entirely.

Cross-references to `byte_D452` lead to a familiar map calculation routine involving two 3D maps.

---

Conclusion

With diagnostic group layout understood, variables can be identified and mapped back to calibration data. From this point onward, tracking maps and signals becomes significantly easier.

This results in a fully software-based reverse engineering workflow, performed without hardware access and with minimal documentation, achieved over several flights and a few evenings.
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Page created in 0.013 seconds with 14 queries. (Pretty URLs adds 0s, 0q)