Perry is a tool to automatically generate hardware models from corresponding hardware drivers. Please refer to our USENIX Security'24 paper for more details: "A Friend's Eye is A Good Mirror: Synthesizing MCU Peripheral Models from Peripheral Drivers".
Perry is tested under the following environment:
- Ubuntu 20.04
- LLVM/Clang 13
- Z3 4.11.0 or above
We recommend building Perry with Docker.
Execute the following command to build the image. In case you need a proxy, set the environment variable PROXY_ADDRESS
:
# PROXY_ADDRESS=http://xx.xx.xx.xx:xx
./build_docker.sh
This will build a docker image
"perry"
which contains all the necessary materials to execute Perry and reproduce our experiments.
To launch the container:
./run_docker.sh
A container
"perry"
will be created the first time you execute the script. You should be able to see a shell spawned within the container. The container is still running even if you exit from the shell, which means that you can always spawn a new shell by executing the script later.
All materials are places under the /root
directory of the container:
Path | Description |
---|---|
/root/perry |
Perry source code and binaries |
/root/perry-clang-plugin |
Perry Clang plugin and compiler wrapper source code and binaries |
/root/perry-experiments |
Artifacts to reproduce Perry's experiments |
/root/HAL-Collection |
Drivers used in Perry's experiments |
/root/qemu |
QEMU v7.2 source code and binaries, used to emulate firmware |
/root/qemu-system-fuzzing |
Source code of our QEMU fork, used to fuzz firmware |
/root/AFL |
AFL source code and binaries, used to fuzz firmware |
/root/gcc-arm-none-eabi-10.3-2021.10 |
GNU Arm embedded toolchain, used to compile drivers |
/root/gperftools and /root/z3 |
Dependencies of Perry/KLEE |
In case you cannot build a image, we provide a pre-built docker image on Docker Hub. Execute the following command to use it:
docker rmi perry:latest
docker pull ray999/perry
docker tag ray999/perry perry:latest
cd perry
./run_docker.sh
To synthesize hardware models with Perry, run the following commands:
python synthesizer/synthesize.py [-c CONFIG-FILE] [-o OUTPUT-DIR] [-a]
-c CONFIG-FILE
: YAML-format config file for the synthesizer. For an example, please refer tosynthesizer/example/*/config.yaml
(e.g.,synthesizer/example/STM32F103/config.yaml
).-o OUTPUT-DIR
: Where to write the generated model. (default to stdout if not specified)-a
: Output everything within a single file so that you can easily integrate the model into QEMU. If not set, models for the board and each peripheral are splitted into multiple files.
Currently supported MCUs are listed in synthesizer/example
. The following steps are required to support a new MCU:
- Compile drivers for the MCU with our Perry Clang plugin and compiler wrapper to collect auxiliary information and generate LLVM bitcode files. Please refer to the
README
file in the repo for how to use them. - Write a configuration file for the MCU. Please refer to
synthesizer/example/*/config.yaml
(e.g.,synthesizer/example/STM32F103/config.yaml
) for how to write a configuration file. - Execute Perry using the configuration file.
Please refer to the perry-experiments repository for more details.
@inproceedings {Lei::Perry::Sec24,
author={Chongqing Lei and Zhen Ling and Yue Zhang and Yan Yang and Junzhou Luo and Xinwen Fu},
title = {A Friend’s Eye is A Good Mirror: Synthesizing {MCU} Peripheral Models from Peripheral Drivers},
booktitle = {Proceedings of the 33rd USENIX Security Symposium (USENIX Security)},
year = {2024},
}