Vida CEM swapping
-
dikidera
- Posts: 1304
- Joined: 15 August 2022
- Year and Model: S60 2005
- Location: Galaxy far far away
- Has thanked: 67 times
- Been thanked: 175 times
Re: Vida CEM swapping
MY2005 with 500kbps CEM with chassis ID 483189.
A while back I also bought a 2.5 head with Dual VVT, but it's the head where the VVT solenoids face each other.
https://cdn.izap24.ru/images/prodacts/s ... 5254t2.jpg
So from a B5254T2 most likely. Since this was a while back, the car is no longer available, all that is left is to research which harness cable and ECM combination, apart from said motor, are compatible.
A while back I also bought a 2.5 head with Dual VVT, but it's the head where the VVT solenoids face each other.
https://cdn.izap24.ru/images/prodacts/s ... 5254t2.jpg
So from a B5254T2 most likely. Since this was a while back, the car is no longer available, all that is left is to research which harness cable and ECM combination, apart from said motor, are compatible.
-
T5Luke
- Posts: 142
- Joined: 11 November 2020
- Year and Model: S60 T5 2001
- Location: DE
- Has thanked: 11 times
- Been thanked: 130 times
So you should buy a used ECM which was build in a car with same engine configuration. MY of donor car should be 2005- . About the automatic gearbox module i'm not 100% certain, it could be yours will work, otherwise just buy another module of a car with same engine type and same MY 2005- , all modules from 2005 and up are compatible to each other, it is easier to buy modules with software on than software for modules...
-
T5Luke
- Posts: 142
- Joined: 11 November 2020
- Year and Model: S60 T5 2001
- Location: DE
- Has thanked: 11 times
- Been thanked: 130 times
ECM you need should be 30668478A 0261208289
some standard Bosch petrol ETM. The rest should stay the same. About the TCM i'm not 100% certain but think it should also stay...
some standard Bosch petrol ETM. The rest should stay the same. About the TCM i'm not 100% certain but think it should also stay...
- prometey1982
- Posts: 46
- Joined: 5 June 2021
- Year and Model: 2010 XC90
- Location: Novosibirsk
- Has thanked: 4 times
- Been thanked: 5 times
- Contact:
Just by EC.2 ECM and 29.1 version of TCM. It's hardware numbers. TCM can be flashed for your type of gearbox. ECM too. And you already have 29.1 TCM. Just buy an ECM. I'll flash needed version to your ECM.
Они просто сдохнут, а мы попадем в рай.
-
dikidera
- Posts: 1304
- Joined: 15 August 2022
- Year and Model: S60 2005
- Location: Galaxy far far away
- Has thanked: 67 times
- Been thanked: 175 times
The Denso ECU is employing quite a lot of obfuscation. Even such where it modifies the return value in the stack to trick the control flow.
And address FFFF7448 is at the heart of all this. It almost feels like a mini virtual machine simply because anytime this address comes up it's in a function/handler which saves the entire registers of the CPU, all of them. It's setup in routine 0x200c and code jumps to 0xc3a0 without being easily identified unless you do dynamic execution.
Even if it's not a VM, almost all interrupts are handled by a function which includes address FFFF7448. Several versions of the function exist for specific use-cases so it's not super generic like most "VMEnter" I have seen which contain a single Prologue and dispatch to handlers, this is just a general overview and not very specific.
I am attaching the most recent and up-to-date so far IDB of the results so far of my research.
I have seen that the sensors are updated when an Interrupt is generated on the ADC channels, although I have yet to see how and where it checks the specific source, however I saw that it immediately converts the data from the ADC to usable data, but only depending on specific flags set at RAM address FFFF96B6 which is why I've named it in that name.
The flow is the following. An interrupt is generated by an on chip module. A generic handler is located at the custom vector table, this generic handler has a specific offsets associated with the type of interrupt, this number is multiplied by 4.
Remember when I said the address FFFF7448 is accessed by specialized functions? This generic handler for a portion of the interrupt vectors has a 2 or 3 special offsets.
0x84 is again some flag.
But furher down is our most important part
FFFF7448 + 0x38 = an address 3081a4, which points to a table full of the actual handlers. Then 3081a4 + handler_offset*4 = actual_handler.
Looking at the handler which updates our very very important variables,
Address FFFF96B6 seems to specify IF only the MAP sensor is updated, OR a function is executed which increments r6 by 2 and does bulk update+conversion.
So I think this is how it mostly works....but remember, at some point FFFF96B6 will specify single update for every interrupt which means the variables might get updated elsewere in a different way.
Now, according to the docs, interrupt sources for HCAN0 and HCAN1 are 222 and 230 respectively. Multiplied by 4, I arrive at two handlers in the vector table, one is for HCAN0 and is an empty loop waiting for a different interrupt to take hold, but HCAN1 is different. I find this very very odd, because it is HCAN0 which for instance is read for processing of bootloader commands...unless it is operating in a single 32-bit buffer mode. But I am unsure if this means that HCAN1 and HCAN0 can be transparently used.
Moving on, if HCAN1 interrupt is the origin of processing bootloader and later, D2 commands, then the flow seems to be:
HCAN1 interrupt -> generic/global interrupt handler->HCAN1 handler which is located at 0xB720, from there it is almost certain it jumps to a function that is executed on startup, which is 0xB748 and is part of the main startup sequence when the ECU is first powered on. Of course the functions there re-initialize the CPU so it's not direct CAN message handling, it must happen waaay wayyy deep.
And address FFFF7448 is at the heart of all this. It almost feels like a mini virtual machine simply because anytime this address comes up it's in a function/handler which saves the entire registers of the CPU, all of them. It's setup in routine 0x200c and code jumps to 0xc3a0 without being easily identified unless you do dynamic execution.
Even if it's not a VM, almost all interrupts are handled by a function which includes address FFFF7448. Several versions of the function exist for specific use-cases so it's not super generic like most "VMEnter" I have seen which contain a single Prologue and dispatch to handlers, this is just a general overview and not very specific.
I am attaching the most recent and up-to-date so far IDB of the results so far of my research.
I have seen that the sensors are updated when an Interrupt is generated on the ADC channels, although I have yet to see how and where it checks the specific source, however I saw that it immediately converts the data from the ADC to usable data, but only depending on specific flags set at RAM address FFFF96B6 which is why I've named it in that name.
The flow is the following. An interrupt is generated by an on chip module. A generic handler is located at the custom vector table, this generic handler has a specific offsets associated with the type of interrupt, this number is multiplied by 4.
Remember when I said the address FFFF7448 is accessed by specialized functions? This generic handler for a portion of the interrupt vectors has a 2 or 3 special offsets.
Code: Select all
mov.l #SomeFunctionTable_FFFF7448, r0
mov.l #0x84, r12
mov.l @(r0,r12), r11
shll2 r14
tst r11, r11
bf loc_2746But furher down is our most important part
Code: Select all
ldc r13, sr
mov.l #SomeFunctionTable_FFFF7448, r1
mov.l @(0x38,r1), r0
mov.l @(r0,r14), r0
jsr @r0
nopLooking at the handler which updates our very very important variables,
Code: Select all
mov.l #MAP_Sensor_FFFF9676, r6
mov.l #adc_convert_opt???_FFFF96B6, r3Code: Select all
loc_A584: ! CODE XREF: convert_analog_to_digital_sub_A578+1C↓j
mov.w @r4+, r3
add #1, r7
extu.w r3, r3
shlr2 r3
shlr2 r3
shlr2 r3
mov.w r3, @r6
cmp/hs r0, r7
bf/s loc_A584
add #2, r6Now, according to the docs, interrupt sources for HCAN0 and HCAN1 are 222 and 230 respectively. Multiplied by 4, I arrive at two handlers in the vector table, one is for HCAN0 and is an empty loop waiting for a different interrupt to take hold, but HCAN1 is different. I find this very very odd, because it is HCAN0 which for instance is read for processing of bootloader commands...unless it is operating in a single 32-bit buffer mode. But I am unsure if this means that HCAN1 and HCAN0 can be transparently used.
Moving on, if HCAN1 interrupt is the origin of processing bootloader and later, D2 commands, then the flow seems to be:
HCAN1 interrupt -> generic/global interrupt handler->HCAN1 handler which is located at 0xB720, from there it is almost certain it jumps to a function that is executed on startup, which is 0xB748 and is part of the main startup sequence when the ECU is first powered on. Of course the functions there re-initialize the CPU so it's not direct CAN message handling, it must happen waaay wayyy deep.
- Attachments
-
- Volvo 64F7055 Flash ORI BIFUEL.bin.idb.7z
- (1.92 MiB) Downloaded 81 times
-
oscilloscope
- Posts: 285
- Joined: 20 May 2022
- Year and Model: 2005
- Location: uk
- Has thanked: 27 times
- Been thanked: 11 times
all so i am messing around with chatGPT to see what it can do , and to see if i can get it to make a small application in python to decrypt a .bin file from a cem unit i have here which i am aware is encrypted. so far it would appear the decryption method given on here a while ago. doesn't seem to like being used in this manner. here is the code
import tkinter as tk
from tkinter import filedialog
import hashlib
def decrypt_file():
# Load the file contents
file_path = file_path_var.get()
with open(file_path, 'rb') as f:
file_data = f.read()
# Decrypt the file
key = 'my_secret_key'
crypto_key = hashlib.md5(key.encode()).digest()
len_data = len(file_data)
decrypted_data = bytearray()
for i in range(len_data):
decrypted_data.append(file_data ^ crypto_key[i % 0x3d] ^ (i // 7))
# Save the decrypted file
save_path = filedialog.asksaveasfilename(defaultextension='.bin')
if save_path:
with open(save_path, 'wb') as f:
f.write(decrypted_data)
status_label.config(text='File decrypted and saved: ' + save_path)
else:
status_label.config(text='File decryption canceled.')
def select_file():
# Prompt the user to select a .bin file
file_path = filedialog.askopenfilename(filetypes=[('Binary files', '*.bin')])
if file_path:
file_path_var.set(file_path)
decrypt_button.config(state='normal')
status_label.config(text='Selected file: ' + file_path)
# Create the GUI
root = tk.Tk()
root.title('File Decryptor')
file_path_var = tk.StringVar()
file_path_var.set('')
status_label = tk.Label(root, text='Please select a .bin file to decrypt.')
status_label.pack()
file_button = tk.Button(root, text='Select File', command=select_file)
file_button.pack(pady=10)
decrypt_button = tk.Button(root, text='Decrypt File', command=decrypt_file, state='disabled')
decrypt_button.pack(pady=10)
root.mainloop()
import tkinter as tk
from tkinter import filedialog
import hashlib
def decrypt_file():
# Load the file contents
file_path = file_path_var.get()
with open(file_path, 'rb') as f:
file_data = f.read()
# Decrypt the file
key = 'my_secret_key'
crypto_key = hashlib.md5(key.encode()).digest()
len_data = len(file_data)
decrypted_data = bytearray()
for i in range(len_data):
decrypted_data.append(file_data ^ crypto_key[i % 0x3d] ^ (i // 7))
# Save the decrypted file
save_path = filedialog.asksaveasfilename(defaultextension='.bin')
if save_path:
with open(save_path, 'wb') as f:
f.write(decrypted_data)
status_label.config(text='File decrypted and saved: ' + save_path)
else:
status_label.config(text='File decryption canceled.')
def select_file():
# Prompt the user to select a .bin file
file_path = filedialog.askopenfilename(filetypes=[('Binary files', '*.bin')])
if file_path:
file_path_var.set(file_path)
decrypt_button.config(state='normal')
status_label.config(text='Selected file: ' + file_path)
# Create the GUI
root = tk.Tk()
root.title('File Decryptor')
file_path_var = tk.StringVar()
file_path_var.set('')
status_label = tk.Label(root, text='Please select a .bin file to decrypt.')
status_label.pack()
file_button = tk.Button(root, text='Select File', command=select_file)
file_button.pack(pady=10)
decrypt_button = tk.Button(root, text='Decrypt File', command=decrypt_file, state='disabled')
decrypt_button.pack(pady=10)
root.mainloop()
-
dikidera
- Posts: 1304
- Joined: 15 August 2022
- Year and Model: S60 2005
- Location: Galaxy far far away
- Has thanked: 67 times
- Been thanked: 175 times
Because I am simply unfamiliar, I know that the immobilizer key is in the CEM, but is there a copy of it on the ECU as well?
I got my Bosch ECU and simply wish to be informed on how to handle the possible immo key mismatch.
I got my Bosch ECU and simply wish to be informed on how to handle the possible immo key mismatch.
-
oscilloscope
- Posts: 285
- Joined: 20 May 2022
- Year and Model: 2005
- Location: uk
- Has thanked: 27 times
- Been thanked: 11 times
I think someone mentioned that some ecu variants do hold a copy of the key. But it was quite some pages back.
Or are you referring too what I wrote above ?
-
dikidera
- Posts: 1304
- Joined: 15 August 2022
- Year and Model: S60 2005
- Location: Galaxy far far away
- Has thanked: 67 times
- Been thanked: 175 times
Which would be the immobilizer key, yes? So I need to dump my CEM, the EEPROM? Copy that key to the ECU? I probably generalized the steps, but I am not sure what the steps are.
-
- Similar Topics
- Replies
- Views
- Last post
-
- 1 Replies
- 6396 Views
-
Last post by RickHaleParker
-
- 5 Replies
- 8644 Views
-
Last post by forumoto






