More documentation (should complete the whole batch)

This commit is contained in:
Collin Kidder
2017-11-29 20:24:29 -05:00
parent 7997ebc966
commit c90d15b5bb
3 changed files with 160 additions and 3 deletions
+17
View File
@@ -5,3 +5,20 @@ Bisector Window
.. image:: ./images/Bisector.png .. image:: ./images/Bisector.png
Using the Bisector Window
==========================
The purpose of this window is obviously to split the list of frames into two pieces. You have many options for how to do this. You can split by:
ID Range - Grab a set of frames between two values. Note that you cannot pick and choose frame IDs here but rather just use a list. If you want to pick and choose then use the filter interface on the main form and then save the filtered list from the File menu.
Frame Number - You can split right at a given frame number. All frames up to that number will be on one side with all the rest on the other.
Percentage - Pretty much just like the Frame Number option but in percentage instead in case that is more convenient.
In all cases, you have the option of which side of the split you want to save. Click "Calculate Split" to process the split. You will see above the buttons a reference of how many frames there were in total and how many you would be saving after the split. From here you *should* be able to do one of two things:
"Save split frames to a new file" - Save the new list of frames (after the split) to a file. You can save to any file format that SavvyCAN supports elsewhere.
"Replace main list with split frames" - Were this to work it would replace the frames loaded in the rest of the application with the split list. I'm sure this would be a really nice thing to be able to do. Well, you can't right now. It's not implemented yet. So, just imagine you can do this. In the mean time you can save to a file then load that file. Sorry...
+127 -1
View File
@@ -5,4 +5,130 @@ Scripting Interface
.. image:: ./images/ScriptingWindow.png .. image:: ./images/ScriptingWindow.png
Woah boy, this one needs some explaining! This will be a very long help file indeed! Leaving this for last! Purpose of the Scripting Interface
==================================
To give you an open ended place where you can write JavaScript files that do whatever you need them to do. You can load several files at once and they'll all work at the same time. Scripts can expose parameters that can then be edited by you while the program is running. They also update 4 times per second so they can be used to give feedback of the current state of the script as well. But, it is safer to give status in the "Log Window" instead. However, for values that might need to be seen and frequently updated it might be easiest to show them as "Public Variables".
Managing Scripts
=================
In the bottom left is the "Loaded Scripts" list. You can create a new script by clicking the "New" button below the list. The new script will have a random name until you save it. The "Del" button will delete the currently selected script but it will ask you first. The "Load" button will load a new script from a file. The "Save" button is above the main script view which is in the upper right of the window. "Revert" will revert the script to the last version that was compiled. Any changes you've made since compiling well be reverted. "Recompile" is used to compile the script and begin running the new version.
Getting Script Status
======================
There are two places you can look for the status of a script. The "Log Window" is directly below the script source code editor. This window is shared between all scripts and shows the status of compiling scripts as well as log messages from each script. The script name that sent the log message is prepended. The number before the script name is the amount of time the scripting window had been open for when the message was sent. This unified interface can be used to keep an eye on all of the running scripts and to debug issues when a script is compiled. Any compile errors will show up in the log window. You can set the checkbox on "Auto Scroll Log Window" to make it continue to stay at the bottom of the log. You can clear the log at any time as well.
The other way to see script status is to use the "Public Variables" interface. Here you will find variables that were registered by the current script. Each script has its own list so information that needs to be updated frequently and/or specific to a script and easily accessible should be registered here. But, public variables can have their value set by you, the user, as well. So, care should be taken not to edit variables used for script feedback and scripts shouldn't try to change the value of variables used for input to the program.
Writing Scripts
================
You are more or less free to write JavaScript scripts but, of course, you aren't in a web browser so browser specific functions are just not there. In their place are a couple of JS objects that allow the script to interface with the CAN buses connected to SavvyCAN. Also, certain functions can be created to automatically register callbacks.
Callback Functions
===================
These functions can be created in your scripts to enable certain functionality:
setup () - If you create a function named setup then it will be called as soon as the script starts. Yes, you probably could just dump code into no function at all right into the file but that's bad form!
tick () - If you registered to receive a periodic tick within your setup function then the script interface will call this function for every tick. You can do whatever you need to periodically do here. But, you get only one tick handler so if you need multiple tick rates you'll have to create a fast tick here and dispatch from this function at different rates yourself.
gotCANFrame (bus, id, len, data) - A callback that will be called whenever a CAN frame comes in that you've registered for. You did register for frames in your setup function didn't you? Well, if you use one of the below callbacks you might not need this one.
gotISOTPMessage (bus, id, len, data) - If you are instead looking for ISO-TP messages (which could have been multiple CAN frames in length) then you can create this function and it will automatically be registered with the system. But, you still will need to set which ISO-TP message IDs you want to receive. That is covered later on.
gotUDSMessage (bus, id, service, subfunc, len, data) - UDS messages are transmitted over ISO-TP but with additional structure. If you're looking to interface directly at the UDS level then you can create this function to have it automatically registered. As with raw CAN and ISO-TP you still need to specify which messages IDs you are interested in.
The host Object
================
The first object you can use is "host" This object handles setup of the tick timer as well as logging output and registration of public variables.
host.setTickInterval(interval) - If the interval is more than 0 then your tick callback will be called every "interval" milliseconds. If a value of 0 is passed then the tick timer will be stopped.
host.log(text) - Send text to the log window. It will be timestamped, marked according to which script sent it, and placed into the log window.
host.addParameter("variablename") - Add the named variable to the list of public variables. From then on any changes that you make in the GUI will immediately show up in the script and any changes the script makes to a value will reflect in the GUI within 250ms. Remember to use quotes around the variable name. You want to pass the variable name, not its value.
The can Object
===============
This object is your interface to raw CAN. It has the following functions:
can.setFilter(id, mask, bus) - register to receive messages based on an ID, Mask, and Bus. It works like this. First the bus is compared. If it doesn't match the frame is not delivered to you. Then, the incoming frame has its ID ANDed with your mask. Let's say your mask is 0x7F0 and the incoming frame has an ID of 0x235. 0x235 AND 0x7F0 is 0x230. This value is compared to the ID you passed. So, if your filter ID is 0x230 then the frame is accepted and you will get a callback with the frame. Otherwise the frame is not delivered to you. This masking setup is very common in CAN bus interfaces. Basically, the mask allows a single filter to accept a range of IDs. 0x7F0 would accept 16 different IDs (0x230 through 0x23F in this case). 0x700 accepts 256 different IDs, etc.
can.clearFilters() - remove all filters and revert to a clean state. You will no longer receive any CAN callbacks unless you create more filters with setFilter.
can.sendFrame(bus, id, length, data) - Send a CAN frame out the given bus. The CAN id will be what you set as will the length. The length can thus be different from the actual length of "data" which should be a valid javascript array. The length can not exceed 8. The frame will be sent as soon as possible so long as that bus is connected and not in listen only mode.
The isotp Object
================
isotp.setFilter(id, mask, bus) - Exactly like the raw CAN version in the can object. Allows you to register a filter so that you can receive ISO-TP traffic from the filtered addresses. It should be noted that you'll essentially only get traffic that seems to be able to be turned into ISO-TP traffic. Any CAN frames obviously not ISO-TP will be rejected.
isotp.clearFilters() - Clear all ISO-TP filters and no longer receive ISO-TP traffic.
isotp.sendISOTP(bus, id, length, data) - As in the can version. The difference here is that ISO-TP messages can be longer than 8 bytes and so might get turned into a multi-frame set of messages with flow control. This is handled for you by SavvyCAN so you needn't handle of the details of the exchange.
The uds Object
===============
uds.setFilter(id, mask, bus) - Exactly like the other two setFilter functions. Register for a set of IDs to be interpreted as UDS (if possible) and sent through to your callback. Any obviously not UDS traffic will be discarded.
uds.clearFilter() - Remove all filters and quit receiving UDS traffic.
uds.sendUDS(bus, id, service, sublen, subfunc, length, data) - Sends a UDS message out from the script. service must be between 0 and 255, subfunc can be larger than one byte if needed. data is only needed for extended payloads as the actual UDS protocol is handled by the service and subfunc parameters.
A full example script
=====================
``
var newID = 0; //set this to the ID you want your RLEC to become
function setup ()
{
host.log("RLEC ID Changer");
can.setFilter(0x0, 0x0F, 0);
can.sendFrame(0, 0x7E0, 8, [0x0d, 1, 0, 0, 0, 0, 0, 0]);
}
function gotCANFrame (bus, id, len, data)
{
var dataBytes = [];
if (len == 8)
{
if (data[0] == 0xd && data[1] == 1 && data[2] == 0xAA)
{
host.log("Got challenge: 0x" + data[3].toString(16) + data[4].toString(16));
var notData3 = ~data[3];
var notData4 = ~data[4];
dataBytes[0] = 0xD;
dataBytes[1] = 2;
dataBytes[2] = ((notData4 & 0xF) << 4) + ((notData3 >> 4) & 0xF);
dataBytes[3] = ((notData4 >> 4) & 0xF) + ((notData3 & 0xF) << 4);
dataBytes[4] = 0;
dataBytes[5] = 0;
dataBytes[6] = 0;
dataBytes[7] = 0;
can.sendFrame(0, 0x7E0, 8, dataBytes);
}
if (data[0] == 0xd && data[1] == 2 && data[2] == 0xAA)
{
host.log("Passed security Check!");
dataBytes[0] = 4;
dataBytes[1] = 0x15;
dataBytes[2] = newID;
can.sendFrame(0, 0x7E0, 8, dataBytes);
}
if (data[0] ==4 && data[1] == 0x15 && data[2] == 0xAA)
{
host.log("ID Reprogramming Successful!");
}
}
}
``
+16 -2
View File
@@ -16,6 +16,20 @@ Using the UDS Scan Window
UDS queries are sent out on the bus from "Starting ID" to "Ending ID". Usually UDS compliant ECUs will respond to 0x7E0 through 0x7E7 which is why those are the defaults. Some vehicles use UDS "like" protocols on other IDs. Usually UDS nodes reply with an ID 8 higher than the request ID. This is thus the default in the program. However, some nodes cheat and do not do this. It is quite common for responses to come from an address 16 higher instead. To deal with this situation there is a checkbox "Allow adaptive reply offset." If this is checked then replies will be accepted no matter what address they come from. Deselecting this will cause only replies of the proper offset to be accepted. The offset defaults to 8 but can be changed with the "Reply Offset" selector. Additionally, you can select which bus to scan and set how long you want to wait for replies. UDS queries are sent out on the bus from "Starting ID" to "Ending ID". Usually UDS compliant ECUs will respond to 0x7E0 through 0x7E7 which is why those are the defaults. Some vehicles use UDS "like" protocols on other IDs. Usually UDS nodes reply with an ID 8 higher than the request ID. This is thus the default in the program. However, some nodes cheat and do not do this. It is quite common for responses to come from an address 16 higher instead. To deal with this situation there is a checkbox "Allow adaptive reply offset." If this is checked then replies will be accepted no matter what address they come from. Deselecting this will cause only replies of the proper offset to be accepted. The offset defaults to 8 but can be changed with the "Reply Offset" selector. Additionally, you can select which bus to scan and set how long you want to wait for replies.
You need to also set a type of scan to do. You can select more than one type. "Show tests with no Replies" - This checkbox does what it says. It is a personal preference whether you'd like to see an entry in the list for scans that returned no results. Sometimes an ECU will just plain ignore messages it doesn't like. In that case you have the option to see an entry in the list telling you that the message was ignored or whether you'd prefer to reduce clutter and just skip anything that had no reply.
"Read By ID" - UDS allows one to read data from the ECU by an ID number. These are not defined anywhere and are custom to each ECU. But, you can use this to scan a range of IDs to see if you get a response to any of them. You need to also set a type of scan to do. You can select more than one type but if you don't set any then you aren't going to see any results. Keep that in mind as none are checked by default.
"Read By ID" - UDS allows one to read data from the ECU by an ID number. These are not defined anywhere and are custom to each ECU. But, you can use this to scan a range of IDs to see if you get a response to any of them. There is no real standard for how many bytes the ID will be. It could be 1, it could be 2, 3, 4. It's likely to be around 2. You can set the number of subfunction bytes which will set the size of the ID. Then you can set the upper and lower bound to scan.
"Read By Addr" - You can also read data by address. Like IDs the address could be different sizes depending on the hardware you are querying. This works the same as reading by ID but by address instead.
"Session Ctrl" - UDS has the concept of session type. Some types are "normal" "extended diagnostics" "programmming". Scanning for session type will try them all and let you know which the device supports. However, note that you might get a response that indicates that conditions are not correct or that access was denied. This probably means that the mode is actually supported but you'd have to do the right things first. This is still useful information. This scan window is too simple to use for further cracking of such things but the scripting interface is the perfect thing to use instead.
"ECU Reset" - The ECU might also support being reset by a UDS message. This scan type will try the various reset types and see which are supported.
"Security Access" - When a device is first started and normally operating it will generally not allow you to do potentially dangerous or sensitive operations such as downloading firmware or changing parameters. To do these things you need to enter a different security level. The security access mechanism is used for this. There are a few different security levels that are likely to be supported. This scan type will attempt to find secutity levels and see if they are protected or not. That is, unfortunately for the casual cracker, most of the time the elevate security levels will be protected by a challenge/response system. The ECU will send you a challenge in the form of one or more random looking bytes. You are tasked with returning the proper response for those challenge bytes. You generally don't have very many guesses before your hands are slapped. Sometimes the C/R is actually fixed and you can just capture valid traffic once and then use the same response forever. Sometimes the C/R is stupidly easy or there are only a couple of different possible answers. Sometimes the ECU developer actually took more than 2 seconds to implement these features and your work will be cut out for you. This scan type will find which levels the ECU seems to support but is unlikely to actually unlock them.
"Tester Present" - A scan that tries to see if tester present is supported. It almost certainly is. This scan can be used to sweep a wide range of addresses just to narrow down the list of addresses to scan more thoroughly. Normally tester present is sent periodically by a connected device just to let the ECU know that someone is still there.
"Wildcard" - Allows for you to set a lower and upper range for the service byte as well as the number of subfunction bytes and the range there as well. This allows for UDS fuzzing by shooting the moon and trying a huge range of traffic just to see what is supported and what isn't. This test can take a VERY long time if you aren't careful but will thoroughly determine what the ECU will support and what it won't.