Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

figure out IOSC #13

Closed
ea opened this issue May 1, 2021 · 20 comments
Closed

figure out IOSC #13

ea opened this issue May 1, 2021 · 20 comments

Comments

@ea
Copy link
Owner

ea commented May 1, 2021

Linux and RTOS communicate with each other over an interface called IOSC. OSAL library seems to implement an abstraction layer above it. We should reverse engineer users of libosal to figure out how
it's supposed to be used so additional utilities can be written to get more interesting data from RTOS.

ea added a commit that referenced this issue May 1, 2021
added a sample program that shows how to use libosal to read RTOS devices
@raburton
Copy link
Contributor

raburton commented May 4, 2021

This is very interesting, I'm trying to follow various bit of code that uses this through but it's not that easy. The various gui apps seems to make extensive use of libosal, I already found multiple references in code I looked at that verified the map data signatures and encryption of the speed camera updates. I can't work out why though, but perhaps this was all incidental. It looks like there is some tracing system on the other side, so maybe it was just making use of that and nothing to do with the core functionality.

Do you know what /dev/kds is for? There are various other references to devices in /dev which I had found in the code previously, but didn't exist on the linux side, so now I guess these must all be over on the rtos side. e.g. /dev/registry which seems to hold config (and looks modelled on the windows registry from key names I've seen). Why is that on the rtos side though? Maybe it's needed on both and felt better to share a single one instead of duplicating it in each os.

From your test code it looks like you send a request code and the buffer length(?) as the first two words. We get back the same request code in the first word and the return length (I don't have many valid examples to extrapolate that from yet) in the next word. Then it looks like there is a 3rd word (always zero so far) before the data starts.
I have 0xdfe: returns 0x18 as length and the string "MYCAR", I assume null terminated and null padded to 0x18. This is the bluetooth device name when pairing.
0xdff: length 0x0e and the string CM3118EXXXXXXX (where XXXXXXX is the numeric head unit device id, as shown in the speed camera updates device info screen, although there it that has an extra digit on the end (checksum?)
0x1214 returns a length of 0x28, which is more than the specified buffer size. I haven't checked if the data is truncated, hopefully it is or I'm not sure what the point of passing in the buffer length is (assuming that's what it is). Don't know what that data is yet.
0x1215 returns a length of 0x10 unknown data
0x1216 did something but I didn't capture it

Got a reboot somewhere after that, skipped up to 0x1300 and got nothing till next reset. I wonder if flooding the rtos with requests is just upsetting it and it reboots deliberately to try and recover from the flood of requests. Might try adding in a small delay and see if rate limiting it works better.

@raburton
Copy link
Contributor

raburton commented May 4, 2021

Ok, few extra bits. I tested the longer response for 0x1214. Despite passing 0x18 as the second parameter I still get back 0x28 bytes of data, so if we are passing in the length of the buffer it's being ignored. If this second parameter isn't the buffer size, what is it? Maybe it is the size, but only used for longer non-fixed length fields, and a minimum buffer size is assumed (and not checked for certain queries). Totally guessing.
Also noticed the response to 0xdfe is zero padded to 0x16 chars, not to the end, then there are two more chars "FQ" in my case. 0x1216 returns 0x10 bytes of unknown data.
Btw, do you know the significance of the 0xf6 on the ioread call? I've seen other values used. Actually, it'd make a lot more sense if this is the length of the buffer, being the next parameter after the buffer itself in a read call.
Can't keep going out to the car in the rain, that's enough for tonight.

@raburton
Copy link
Contributor

raburton commented May 4, 2021

pushed a few changes to the test code

here is some sample output for a couple of codes mentioned above:

0dfe 0018 0000:
4d594341520000000000000000000000
0000000000004651
MYCAR...........
......FQ
0dff 000e 0000:
434d333131384531313131313131
CM3118E1111111

(device id edited to all 1s)

@raburton
Copy link
Contributor

raburton commented May 5, 2021

I've got it to stop causing a reboot
When you load libosal it creates an exit hander, which reboots the system - I suppose none of the headunit apps are supposed to exit, so if they do it thinks something has gone wrong. It can be disabled by touching /opt/bosch/disable_reset.txt You still get a big dump to the terminal though, which you have to scroll back past to get to see your output.

@raburton
Copy link
Contributor

raburton commented May 11, 2021

I've made a start decoding some of the data available from KDS...

// code 0x0d60, len 0x04
struct ECORoute {
	uint8  FuelType : 1;          // byte 0
	uint8  DragCoefficient : 7;
	uint8  TransmissionType : 2;  // byte 1
	uint8  unused : 6;
	uint16 crc;                   // byte 2-3
};

Example 20c078ea
FuelType = 0 (from an unleaded car)
DragCoefficient = 20
TransmissionType = 3 (from a manual 6 speed car)
crc = 0xea78


// code: 0x0d70, len 0x18
struct BTName {
	uint8  Name[16];
	uint16 crc;
};

Example 4d59434152000000 0000000000000000 0000000000004651
Name = "MYCAR" (null padded, max len 15 null temrinated or 16 if not???)
crc = 0x5146


// code: 0x0d5e, len: 0x1b
struct PartsNumber {
	uint8  PartNumber[5];
	uint8  ConfigurationHash[20];
	uint16 crc;
};

Example 335a4c3742...... ................ ................ ..b0e9
PartNumber = "3ZL7B" (appears fixed length, not null terminated)
ConfigurationHash = (hidden, in case unique)
crc = 0xe9b0


// code: 0x0d61, len: 0x04
struct CameraSystem {
	uint8  CameraSystem : 3;        // byte 0
	uint8  AnticipatoryLine : 1;
	uint8  unused : 4;
	uint8  Guideline;               // byte 1
	uint16 crc;                     // byte 2-3
};

Example 80008b83
CameraSystem = 4 (from car with birds eye view, 4 camera system)
AnticipatoryLine = 0
Guideline = 0
crc = 0x838b


// code: 0x0d59, len: 0x0a
struct VehicleInformation {
	uint8  unknown1;                        // byte 0
	uint16 VehicleType;                     // byte 1-2
	uint8  CANGeneration1 : 1;              // byte 3
	uint8  Region : 4;
	uint8  SteeringWheel : 3;
	uint8  SteeringPosition : 1;            // byte 4
	uint8  unknown2 : 1;
	uint8  ShowClock : 1;
	uint8  MeterClockSynchronisation : 1;
	uint8  PlatformType : 1;
	uint8  DistanceUnitsSupported : 2;
	uint8  unknown3 : 1;
	uint8  OpeningAnimation : 2;            // byte 5
	uint8  unknown4 : 6;
	uint8  OffRoadInformation : 1;          // byte 6
	uint8  unknown5 : 1;
	uint8  VehicleConfiguration : 1;
	uint8  HEV1 : 1;
	uint8  AntiTheft : 1;
	uint8  DrivingType : 2;
	uint8  JudgementForOP : 1;
	uint8  VoiceRecognition : 1;            // byte 7
	uint8  unknown6 : 1;
	uint8  CAN : 1;
	uint8  AUXKind1 : 2;
	uint8  ISA : 1;
	uint8  unknown7 : 2;
	uint16 crc;                             // byte 8-9
};
enum Regions {USA = 1, CAN, EUR, PRC, GCC, RUS, ASR, ARG, BRA, SAF, MEX, THI, TKY};

Example 00124c19bc400928 8c5d
...
Region = 3 (from UK car)
...
crc = 0x5d8c

@raburton
Copy link
Contributor

raburton commented May 11, 2021

I haven't worked out the CRC algorithm yet. I've coded up a C version of the one I found in the application, but it doesn't seem to get called to verify these structures, so I don't know for sure if it's the right one. Where I have seen it called for other purposes it takes a starting value of 0, but using this it does not produce the a crc that matches the ones in my own data. I can use brute force to work out a starting value to get the right CRC out for any particular data structure, but each one seems to be different and that doesn't seem likely.

@raburton
Copy link
Contributor

code: 0x0106, len: 0x07
uint8 DeviceSerialNumber[7];

code: 0x1216, len: 0x10
uint8 CryptedFileAesKey[16];

used for .ntq alert files


code: 0x0105
code: 0x010e
code: 0x0d52

used for ipod control


code: 0x0104, len: 0x08
uint8 TelematicsPassword[8];

Not seen yet for real. Password appears to be encrypted/hashed.

@ea
Copy link
Owner Author

ea commented May 12, 2021

Awesome work.
I am not sure what KDS could stand for , but all the retrieved data seems to be static. I'll try to correlate it with some stuff in the RTOS binary.
From my notes , I've seen the following /dev/kds addresses :

0xD59 VehicleInformation
0xD61 CameraSystem
0xDFE BTName
0xD53 SystemConfig2FormerAudio
0xD60 ECORoute
0xD30-0xD38 SDSECNR (what could this acronym mean?)
0xD52 SystemConfiguration
0xD40-0xD48 PhoneECNR
0xD5D FMAMTunerParameter
0xD5F AudioParamterSet
0xD5B , 0xD5C - DABParameterSet
0xD5E PartsNumber

The structure of returned data can easily be inferred from Vtables of corresponding classes as all have obvious getters in the binary. I pulled the above ones from smartphone support app.

ea added a commit that referenced this issue May 12, 2021
@ea
Copy link
Owner Author

ea commented May 12, 2021

Over the weekend , I've been digging through OSAL_s32Message* APIs and their usage, but don't have a working example just yet. I can see some magic words associated with different juicy looking data, but haven't been successful at setting up a full OSAL messaging client just yet. A little more digging and testing ...

ea added a commit that referenced this issue May 12, 2021
@ea
Copy link
Owner Author

ea commented May 12, 2021

Meanwhile , i've added a similar tool that shows how to walk the registry device. Please pay no attention to the questionable C, it's that way for easy testing of various structures.

@raburton
Copy link
Contributor

I've got the crc sussed out.
I couldn't find any crc algorithm in the binaries that would produce crcs that matched the values in the real data. I started to think that perhaps they had tried to obfuscate the crc for some reason. I'd tried using non-standard starting values, and tried xoring the output without finding anything. Then I tried drvBtAsipCrc from libosal_linux_so.so still not joy, so I tried to brute force all possible starting values and all possible xor outputs at the end, against multiple data items to see if I could find an overlap - and I did. A modified version of drvBtAsipCrc passed the data and an initial value of 0x07f0 and final xor of 0x07f0 produces the correct checksums. I was feeling pretty pleased with myself, after hours of work!, and decided to google this number to see if it had any significance. I didn't find any, but I did come across a tool call reveng which can help find crc algorithms from data and it was instantly able to solve it (aaah!) in a different way. Apparently the algorithm is CRC-16/IBM-SDLC with it's standard parameters (none of which are 0x07f0). It's fascinating that a different (but obviously related) crc algorithm could produce the same results with a particular change to initial and xor.

Anyway, here it is:

unsigned short crc16(unsigned char* data, int len) {
	unsigned short crc = 0xffff;
	for (int i = 0, x; i < len; i++) {
		x = crc ^ data[i];
		x = (x ^ (x << 4)) & 0xFF;
		crc = (crc >> 8) ^ (x << 8) ^ (x >> 4) ^ (x << 3);
	}
	return (crc ^ 0xffff);
}

@ea
Copy link
Owner Author

ea commented May 16, 2021

Figured out messaging mechanism. Partially at least. One listens on a queue and can wait for messages to be delivered. Haven't yet figured out the structure of the received message notification , but it contains who it comes from , message code and some sort of a pointer which is used to look up the actual message contents inside shared memory. Haven't yet figured out quite how to actually retrieve the message content. To be continued...

@raburton
Copy link
Contributor

raburton commented May 19, 2021

Have you tried writing to kds? I've tried replacing the BT device name (seems to be stored in two different kds locations, so I changed both). A call to OSAL_s32IOControl(fp, 2, 1), after opening, appears to make it writeable. The write works fine, and a read back shows the updated value, but after a reboot they have gone back to the old value. The only write to kds I've found in any of the modules is to store the telematic password, so it doesn't look like it's a common thing but it should be possible, and I'm sure that password would be expected to persist.

@ea
Copy link
Owner Author

ea commented May 20, 2021

I have not tried to write to KDS device yet , for fear of bricking my device. I wonder if there some sort of caching involved that would return the updated value but not make it persist after a reboot. Maybe it requires some sort of a flush or sync...

@ea
Copy link
Owner Author

ea commented May 20, 2021

I have noticed that OSAL_IOOpen is sometimes called with an argument other than 4. Probably depends on weather the target is under RTOS or linux.
For example, if you try do OSAL_IOOpen("/dev/root/proc/mounts",4) it fails, but OSAL_IOOpen("/dev/root/proc/mounts",1) passes and actually reads out linux's /proc/mounts.
I've been trying to figure out how exactly the directory reading functions work, in order to be able to list what structure the RTOS sees.

@ea
Copy link
Owner Author

ea commented May 20, 2021

It's actually very simple

    int r = OSALUTIL_prOpenDir("/dev/ffs");
    printf("%x\n\n\n",r);
    int dr; 
    while(dr = OSALUTIL_prReadDir(r)){
    printf("%s\n",dr);
}

But doesn't work for / , i guess that's not how RTOS works with these. I should check out some t-kernel internals...

ea added a commit that referenced this issue May 30, 2021
@ea
Copy link
Owner Author

ea commented May 30, 2021

Cleaned up a bunch of stuff and now have a properly working messages listener. Now to figure out what/where the fun ones are.

ea added a commit that referenced this issue May 31, 2021
@ea ea closed this as completed in b744411 Aug 10, 2021
@ea
Copy link
Owner Author

ea commented Aug 10, 2021

whoops, didn't mean to close it just yet

@ea ea reopened this Aug 10, 2021
@ea
Copy link
Owner Author

ea commented Aug 16, 2021

@raburton i just added a code sample that lets you write things to KDS, I successfully managed to change the bluetooth name of on my test device. The trick was indeed to flush the write by an additional IOCTL.

Additionally, I've documented everything I got so far about interaction between Linux and RTOS in "rtos_interaction.md". I'll do some more cleanup and rearranging and finally close this issue , soon :)

@ea
Copy link
Owner Author

ea commented Aug 20, 2021

Closing issue , see docs/rtos_interaction.md and rtos_interaction/

@ea ea closed this as completed Aug 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants