-
Notifications
You must be signed in to change notification settings - Fork 55
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
IC211, IC209 #12
Comments
IC164 is from the same generation, found here one more example: https://youtu.be/ap3CYx5iMIU?t=116 SW Version: 2519021500_00E1 |
Hi @jglim here is the algorithm for all these clusters implemented in Rust: https://github.com/VladLupashevskyi/ki211-seed-key It needs however different key for each SW version. Most probably there is some logic for generating those as well which is based on SW or something. There is a table of root keys for each access level for example for 0095 SW Version: (0) 13151416 If you take a look at how 8 bytes seed is used for key calculation you will see that only half of it is actually used. The other dummy bytes are actually generated based on 4 bytes seed and lvl. 2 key, so they might indicate something. I tried to find out whether these access levels depend on each other by the same algorithm (as one root key would be seed and second a key) and actually there was match for lvl key pairs (0,1), (1,2), (2,3), but no more and the brute forced key was different always, so not sure whether it was just coincidence. However, coming back to this issue #13, I can confirm that these algorithms are build in CBF files and I managed to emulate 171 cluster Flash procedure with Teensy, where I've got key calculated for my given seed. I have also tried to emulate 211 cluster, but it was not requesting any seed from emulated cluster, but I'm pretty sure it has those capabilities, given strings that are stored in that file. Unfortunately I'm not sure how to catch which calls it does to the c32s.dll, maybe you could help with that some day. |
Reference implementation from @VladLupashevskyi : #12
@VladLupashevskyi Awesome! I've added that as I've tried searching for the above constants (e.g. If these keys can be extracted from the CFF files, I'm okay with manually dumping them as it should hopefully be a short list (and thus less painful than figuring out the backing logic). However, I haven't been able to find a matching CFF file for the On the last bit on tracing c32s.dll calls, I can recommend drltrace for bulk tracing of library calls. This tool came in handy while figuring out the internals of SMR-D/F in my other ODB project. Again, this is a bulk strategy which slows down the process a lot and generates fairly chunky logs. If you have specific functions of interest, it may be quicker to stick a debugger on them instead, or write an "injectable" library to hook them. |
@jglim thanks for implementation :) just couple of corrections, these clusters (except for 171) are using 27 01 for seed (which is generic for all access levels) and 27 02 for key response of all access levels and the key response is formed as follows Please also take a look at test section of rust.rs file, there are also keys for other SW such as ki209 1057, ki211 0095, ki211 00A9 and 171 AEJ 07/1 (pay attention to the response for 171). I might add it later here, when I have access to my computer, but just if you faster than me :) What can be also useful if somebody has an EEPROM programmer and some clusters is that the default access level is actually stored in EEPROM and can be changed which allows to get a firmware with potential keys table. The address in EEPROM for ki211 that I checked was 0x0DE, 0x0DF which is for default lvl 2 is 0xA2C4 and for level 7 it's 0x5779. They use some obfuscation to store it on EEPROM as you can see. I did look those keys in cbf files, and also did find anything. I don't have any CFF files for 211 cluster, and not sure whether they actually exist. What I did however is I took some dummy CFF file with ID name of 5 characters like KI171 (or IC171 can't remember now) and replaced all occurrences with KI211 + I have patched c32s CRC check so it returns always true and that's how I was able to use any CFF file with 5 chars ID for flashing with my simulator. I cannot remember whether I have used only KI171 off file for KI171 sim or also some other patched CFF file. Need to check that again. So if it actually calculates key for non original CFF file, then we can pretty sure tell that generation is done only by CBF. What I noticed in almost all CBF files where we know exact key and can find it in CBF, the endian inverted key is prefixed with 0x43 and 0xFE byte goes almost always after key. So I found the place in 211 cbf in Flash routine section exactly before seed key related strings and it's Thanks for pointing me to drltrace, it looks like exactly what I need for that. I will check that out as soon as I find time for that. And also I will check whether seedkey is gonna be generated for 171 if I take some dummy patched CFF file and post an update here. |
Prior definition was for a range of levels for 211_0095. This removes unused 211_0095 levels, and adds 209_1056, 209_1057, 211_00A9 #12 (comment)
Got it, thanks for taking time to explain how the levels work. The db.json definitions have been updated based on the rust tests, so there are a total of 4 entries now:
I've yet to include Looking at 2 random eeprom dumps, Here's a dump of the first 16 bytes, starting from 0xDE.
That's a creative workaround to test the algo. The pattern When the script is dumped into a standalone file, the This is the list of functions inside
|
@jglim re EEPROM, thanks for confirming that A2C4 exists on other EEPROMs, that's great news!. Sorry I might not expressed myself correctly - this value has nothing to do with root key. It's just default access level that is gonna be used after boot. On these clusters there is a function That's the way it gets computed:
So one can desolder that small EEPROM change to value 0x5779 and be able to read the firmware via diagnostics, which is located starting at And thanks for confirmation of the location of that 4 byte value in CBF that motivates me :) |
Nice, that's the first time that I've heard of persistent security levels. Appreciate the explanation. For what it's worth, I took a look at |
If this topic is still actual, here is the list of the hashes for the sw ID's of security level 7.
|
Looks like |
Some of them are same between different sw numbers. |
Yeah, I noticed that. Another interesting thing is that I cannot find these exact SW version numbers (2nd line on photo) in any diagnostics responses and it seems it's only obtainable from engineering menu in cluster. Since diagnostic app should be able to determine the version for root key, It's possible that it actually depends on other SW version (1st line for example) that is present in diagnostic responses. |
Request 31 FB 00 then sw I'd will be on 6th index |
Contribution from @WSorban at #12 (comment)
Added, Thank you @WSorban for this huge list of keys! |
Hey @jglim, some updates from my side. Tried with drltrace, but somehow Vediamo hangs after startup I cannot even connect to ECU :( As you might remember I could not get seed key calculation function to be called during flash, but using your amazing app which decodes fn offsets, I just replaced offset of function that is getting called with seed key calculation function and got this nice output in logs: Thanks to the person that has added such a nice output for logs :D It does not request seed, just does calculation (and 33...33 is just some value that's stored in the memory where seed should be). As we can see it does just exactly what I have implemented in algorithm, and nothing else to do with SW dependant key generation. In fact the value that I had gut feeling about ( With KI171 it's more interesting... First of all after running 171 cbf file trough your DSCContext loader I found that there is actually a constant which is called "Key Constant" the value is: Then there is another constant in the beginning of seed calculation function in Flash routine: In original flash sequence before doing seed key calculation it get Boot ID via request But then I tried to do that trick with replacing fn offsets and I replaced "get boot id" function with calculate key function and the resulting key was different. I assume it took the first SW in this case which is probably: For the default constant value in the beginning of the function and seed So it looks like current version of algorithm will not work for 171 cluster and it needs more digging. However good news are that we pretty sure that the algorithm is just in CBF file and nothing is used from CFF files for these clusters at least. CFF files that I took had nothing to do with those clusters. I have also found out that _MIInterpreter function looks for dll which has interesting name: At last I found that DSCContext was failing when reading PAL files and I had to update on line 16 in new MemoryStream(dscContainerBytes) to new MemoryStream(dscContainerBytes, 0, dscContainerBytes.Length, true, true) |
Your function offset hack is brilliant, and makes a lot of sense in hindsight — most functions take 0 parameters and return nothing so they should be interchangeable. I'm still trying to figure out more uses for your technique, and might report back if I find anything new. On InterpreterDebugPanel seems to only export 3 functions. There might be more callbacks from the dll, that are returned when the panel is opened but I haven't understood enough of it. Also, there are additional checks on the PAL header to determine if debugging is enabled (e.g. before the dll is loaded). I saved some notes but never finished the dll: // this will require a *.def file to ensure that exported names are not mangled
// the function params might not be visible in ida if they are unused
/*
unk1: c string, either "unknown" or something else depending on some field within the script's header
interpreter_context: handle to the currently running vm, allocated at MIInterpreterCreate (structure, size=0x55)
mi_debug_set_breakpoint_callback: offset to the "set breakpoint" function
mi_debug_clear_breakpoint_callback: offset to the "clear breakpoint" function
*/
__declspec(dllexport) void* __cdecl ControlPanelOpen(const char* a_unk1, void* interpreter_context, void* mi_debug_set_breakpoint_callback, void* mi_debug_clear_breakpoint_callback)
{
// returns some sort of handle, no idea
return 0;
}
/*
open_result seems to be the return value of ControlPanelOpen
a2 might be an address..?
can't confirm if it returns anything.
*/
__declspec(dllexport) void* __cdecl ControlPanelBreakpoint(void* open_result, int a2)
{
__asm
{
int 3
}
return 0;
}
/*
this needs to exist even if it's probably not useful
no idea what the signature is; will definitely crash
a debugger exception should be raised *first* to find the caller
*/
__declspec(dllexport) void* __cdecl ControlPanelClose()
{
__asm
{
int 3
}
return 0;
}
|
Hello again, here's a small release that might help when working with the interpreter: I've written a dll C32NativeExtension_221215_2.zip that hooks into c32s.dll, and traces every instruction that goes through MIInterpreter. At the very least, they will show up like this, with the current opcode, program counter, PAL file offset, and the stack pointer:
Some instructions may be accompanied with a description on their behavior and the values as they are used or modified:
This dll expects an exact c32s.dll, version 3.2.6.2, sha1: This project was built via a vanilla vs2019. It should build without much trouble as there are few third-party dependencies. Any dll-loading technique (e.g. injection) should be fine, though CFF Explorer is especially recommended as a tool to add C32NativeExtension.dll as an import under c32s.dll, so that it is automatically loaded whenever c32s.dll is loaded by any process. When using this method, remember to put C32NativeExtension.dll in the same directory as c32s.dll after building it. Whenever the library is loaded, it will create/overwrite a log file To understand how the trace might be helpful, A CRD3 is emulated to log its unlocking behavior (I am having difficulty emulating a KI171 as I am not sure of the messages that it expects). After initiating contact, an unlock script is run through
The log for the entire script execution can be viewed here: c32s_SecurityAccess_9New.txt. As global variables come with names, it helpfully describes what it is doing, such as:
Many of the instructions do not come with descriptions, as I only fixed up enough for the CRD3 to produce meaningful traces. Hope this still comes in handy! Extra stuff "minimum" CRD3 for emulation at a j2534 level (PassThruWriteMsgs/PassThruReadMsgs)
|
Additional info on bench ki211:
|
Hi, I have so far not been able to get the hash for the following sw ID: I had this in ki209 clusters, and if memory serves me right, in ki211 as well - 2007 variants I am wondering if anybody managed to get it (I didn't find it in the sources either, still I thought it might be worth asking. Thanks in advance! |
@WSorban Hello, I don't have the hashes, but would like to share a tip — if you are somehow able to obtain a seed/key pair, there is a good chance of recovering the KIAlgo1 hash as it is partially reversible |
Thanks, yes, I tried, but unfortunately I was not able to get any seedkey pairs for this. |
Hello. Is there an exe available for those less experienced with KI211 files? UnlockECU |
Web based : https://unlockecu.sn.sg/ |
Thank you, I saw it. Only the PC version lacks Ki 211. |
Hello thanks for your perfect job |
OK this algo grows up. KI203M_0003; 189E370F KI209_1035; CF98760D KI171_1714420000_0052; 7B7FC59F |
Just sharing some findings about IC211 here, IC209 is gonna be similar...
Found in this video combination for IC211 https://youtu.be/DMf5G9hdKAA?t=191
SW Version: 00A9
Seed: 84 7D 94 EA 99 27 9F 96
Key: 6A E3 96 C3
I was asking the author of this video how did he get the algorithm - he said he was reverse engineering the IC firmware.
Here guy is selling the tool with all possible calculators for 203, 209, 211 instrument clusters: https://ancartech.com/sw_skctool/
The text was updated successfully, but these errors were encountered: