ICSim Scripting with Python and Shell Scripts
- Author: Dr. Jim Marquardson (jimarqua@nmu.edu)
- Updated 2024-06-15
You can script some of your exploration using different scripting languages. This exercise introduces sample programs using Python and Bash. These programs can help you focus your exploration. You can tweak this code to suit your needs.
Learning Objectives
In this exercise, you will learn to:
- run Python programs,
- run bash scripts, and
- change script inputs to focus your exploration.
Prerequisites
This exercise assumes that the following are available:
- Kali Linux VM with a graphical user interface,
can-utils
has been installed,ICSim
has been installed to~/ICSim
.
Setup a CAN Network
Your CAN network may already be configured. If not, run the following commands.
- Open a terminal.
- Navigate to the
~/ICSim
directory.
cd ~/ICSim
- Create the
vcan0
network. Thisvcan0
network essentially simulates a physical wire to sensors in a bus topology.
sudo sh setup_vcan.sh
Enter the password (kali
) if prompted.
- You may not see any output. The command likely worked. Check for the
vcan0
network usingifconfig
.
ifconfig
You should see vcan0
in the list of network adapters.
vcan0: flags=193<UP,RUNNING,NOARP> mtu 72
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- If you run
sudo sh setup_vcan.sh
and see a message like, "RTNETLINK answers: File exists," this means that thevcan0
network has already been set up. You can ignore this message and continue.
Launch the Simulator
- Run the following command to launch the vehicle simulator. Ensure that your working directory is
~/ICSim
before running this command. You will likely have to press theenter
twice in the terminal to return to the terminal prompt.
cd ~/ICSim
./icsim vcan0 &
The Python Program
I created a short Python program that sends CAN messages. This program is useful if you know the arbitration ID and the data length the system wants, but you don't know how the data will be interpreted. The program contains the following Python code.
import sys
import time
from subprocess import call
def send_can_codes(network, template, delay):
num_x = template.count("x")
i = 0
while i < 4**(num_x*2):
hex_str = hex(i)[2:].zfill(num_x)
can_message = template.replace("x"*num_x, hex_str)
can_cmd = f"cansend {network} {can_message}"
print(f"Running {can_cmd} - press control+c to stop execution.")
call(["cansend", network, can_message])
time.sleep(delay)
i += 1
def print_syntax():
print("This script sends a sequence of CAN messages with a variable part.")
print("It is useful if you know the arbitration ID and the data bytes of a message, but you don't know how the data will be interpreted.")
print()
print("Syntax: python3 seq.py <network> <template> <delay>")
print("network: the CAN network to send the messages")
print(" Example: vcan0")
print("template: the CAN message to send. Use 'x' as a placeholder for the variable part")
print(" Example: 19B#0000xx000000")
print("delay: the delay between messages in seconds")
print(" Example: 0.1")
print()
print("1 x will produce 16 messages. 2 x's will produce 256 messages. 3 x's will produce 4096 messages, etc.")
print()
print("Example: python3 seq.py vcan0 19B#0000xx000000 0.1")
if __name__=="__main__":
if len(sys.argv) != 4:
print_syntax()
sys.exit(1)
network = sys.argv[1]
template = sys.argv[2]
delay = float(sys.argv[3])
send_can_codes(network, template, delay)
Running the Python Program
- In a Kali terminal, make a new folder.
cd ~
mkdir scripts
cd scripts
- Download seq.py to your
/home/kali/scripts
directory. You can open Firefox in Kali and open this web page to download the file. You may need to right-click on the link and choose "save as."- Alternatively, you can use
wget
to download the URL. Copy the URL to your clipboard, then paste the URL into the wget command.
- Alternatively, you can use
wget paste_the_url_here_that_ends_with_seq.py
- In the terminal, run the following command to see the program's syntax.
python3 seq.py
- Test the script using the following command. The program will send
canplayer
messages using the19B
arbitration ID. The program will replace the x's in the data with every possible combination of hex characters.
python3 seq.py vcan0 19B#0000xx000000 .2
- Run the program again using different delays. For example:
python3 seq.py vcan0 19B#0000xx000000 .01
python3 seq.py vcan0 19B#0000xx000000 .5
python3 seq.py vcan0 19B#0000xx000000 2
- Run the program again with different arbitration IDs. For example:
python3 seq.py vcan0 188#xx00 .1
- Change different 0's to x's in the data and see what happens. Note that the x's must be contiguous.
python3 seq.py vcan0 188#0x00 .5 # Works fine
python3 seq.py vcan0 188#xx00 .5 # Works fine
python3 seq.py vcan0 188#00xx .5 # Works fine
python3 seq.py vcan0 188#0x0x .5 # Busted - there is a 0 between the two x's
Bash Scripting
The following shell script largely implements the same logic as the Python program above. You can download it here. However, this shell script is meant to stand alone and not require the use of candump
or cansniffer
to record the messages.
- Make the file executable.
chmod +x seq.sh
- Run the program to see its syntax and sample usage.
./seq.sh
The code is found below.
#!/bin/bash
# Check if cansend is installed
cansendInstalled=false
if command -v cansend >/dev/null 2>&1; then
cansendInstalled=true
echo "cansend found. Running."
else
echo "cansend not found. Please install can-utils."
echo "Press an key to start without cansend."
echo "The codes will be printed, but not sent to the CAN network."
read -n 1
fi
# If there are no parameters, print usage
if [[ $# -eq 0 ]]; then
echo "This script generates sequential can codes and gives and opportunity to save codes to a file."
echo ""
echo "Usage: ./seq.sh <can_code_template> [-network <network>] [-delay <delay>] [-out <out>]"
echo " -can_code_template : Required. The arbitration ID, #, and data. E.g., 19B#0000xx000000"
echo " Each x will be replaced with all possible hex values."
echo " -network <network> : Optional. The network to send the CAN commands on. Default is vcan0."
echo " -delay <delay> : Optional. The delay between each command. Default is 1.0 seconds."
echo " -out <out> : Optional. The file to save the commands to. Default is saved.txt."
echo ""
echo "Examples:"
echo " ./seq.sh 19B#0000xx000000"
echo " ./seq.sh 19x#000000030000 -delay 0.5"
echo " ./seq.sh 188#00xx -delay 0.5"
echo " ./seq.sh 188#xx00 -delay 0.5"
echo " ./seq.sh 18x#0000 -delay 2.0 -network vcan0"
echo " ./seq.sh 188#00xx -network can0"
echo " ./seq.sh 188#00xx -network can0 -out try2.txt"
echo " ./seq.sh 188#00xx -network vcan0 -delay 0.5 -out try3.txt"
exit
fi
# Set the default values
can_code_template="19B#0000xx000000"
network="vcan0"
delay=1.0
out="saved.txt"
# Parse the parameters
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-network)
network="$2"
shift
shift
;;
-delay)
delay="$2"
shift
shift
;;
-out)
out="$2"
shift
shift
;;
*)
can_code_template="$1"
shift
;;
esac
done
# find the numer of x characters in $can_code_template
num_x=$(echo $can_code_template | grep -o "x" | wc -l)
x_str=$(printf 'x%.0s' $(seq 1 $num_x))
stop=$((4**($num_x*2)))
for ((i=0; i<$stop; i++))
do
# convert $i to base 4 padded with 0s
hex=$(printf "%0${num_x}x\n" $i)
# replace x characters in $can_code_template with $can_command
can_command=$(echo $can_code_template | sed "s/$x_str/$hex/g")
echo "($((i+1)) of $stop) cansend $network $can_command. Press 's' to save the CAN message, 'x' to exit, 'p' to pause."
if [ "$cansendInstalled" = true ]; then
cansend $network $can_command
fi
read -t $delay -N 1 input
if [[ $input = "s" ]]; then
echo " Appending $can_command to $out."
echo $can_command >> $out
elif [[ $input = "x" ]]; then
echo "Exiting."
exit
elif [[ $input = "p" ]]; then
echo "Paused. Press any key to continue."
read -n 1
fi
done
- Execute the script to see the help documentation.
./seq.sh
- Explore different uses of the script.
./seq.sh 19B#0000xx000000
./seq.sh 19x#000000030000 -delay 0.5
./seq.sh 188#00xx -delay 0.5
./seq.sh 188#xx00 -delay 0.5
./seq.sh 18x#0000 -delay 2.0 -network vcan0
./seq.sh 188#00xx -network can0
./seq.sh 188#00xx -network can0 -out try2.txt
./seq.sh 188#00xx -network vcan0 -delay 0.5 -out try3.txt
- Run some of the examples.
- As the script executes, press
s
to save the CAN message. Pressp
to pause. If you want to exit early, pressx
. - You may want to increase the delay between sending different messages if you do not have enough time to press
s
so save.
Challenge
- Edit the scripts using
nano
. Add an extra features. - Create a minimal Python script that sends CAN messages. Extract the useful bits from the Python source code above. It might only be a couple of lines of code.
Shutting Down
- Close the ICSim window. You may have to click
Yes
to confirm closing it. - Close all terminals.
Reflection
- Why would it be important to specify a reasonable delay?
- At what point in your investigation would this technique be useful?