ghidra-PT

Project Url: mqf20/ghidra-PT
Introduction: Tool for integrating Intel Processor Trace (PT) with Ghidra.
More: Author   ReportBugs   
Tags:
Ghidra Integration with Intel Processor Trace Prerequisites CPU with Intel PT Support perf cmake Intel XED libipt and ptxed Ghidra Installation Example

Prerequisites

CPU with Intel PT Support

Verify that Intel PT is supported by your CPU and display its capabilities:

$ ls /sys/devices/intel_pt/format

branch  cyc  cyc_thresh  fup_on_ptw  mtc  mtc_period  noretcomp  psb_period  pt  ptw  pwr_evt  tsc

perf

Use apt:

sudo apt install linux-tools-common linux-tools-generic linux-tools-`uname -r`

Verify that Intel PT is supported by perf:

perf list | grep intel_pt

cmake

Use apt:

sudo apt install cmake

Intel XED

Clone the Intel XED Github repository:

git clone https://github.com/intelxed/mbuild.git mbuild

git clone https://github.com/intelxed/xed

cd xed

./mfile.py --share

./mfile.py examples

sudo ./mfile.py --prefix=/usr/local install

sudo ldconfig

sudo cp ./obj/wkit/examples/obj/xed /usr/local/bin

libipt and ptxed

Clone the libipt Github repository:

git clone https://github.com/intel/libipt

Configure cmake to build ptxed:

cd libipt

mkdir build && cd build

cmake .. -D PTXED=ON

Finally build:

make

sudo make install

sudo ldconfig

Ghidra

Tested on Ghidra 10.0.

Installation

Copy ghidra_scripts/IntelPTColorControlFlow.java into {GHIDRA_INSTALL_PATH}/Ghidra/Features/Base/ghidra_scripts.

Example

We will use a simple C++ program for demonstration:

#include <iostream>
#include <cstdlib>

int main(int argc, char *argv[]) {

    if (argc > 1) {

        std::cout << "You have entered " << argc << " arguments:" << "\n"; 

        for (int i = 0; i < argc; ++i) 
            std::cout << argv[i] << "\n"; 

    } else {

        std::cout << "Usage: " << argv[0] << " [arguments]\n";

    }

    return EXIT_SUCCESS;
}

Build the C++ program:

g++ main.cpp -o app_O0_g -O0 -g

Test the C++ program:

$ ./app_O0_g "hello world"
You have entered 2 arguments:
./app_O0_g
hello world

Assume that we are only interested in tracing the .text section. Using readelf, we know that .text section’s offset is 0x10c0 and size is 0x2b5:

$ readelf -S ./app_O0_g

There are 36 section headers, starting at offset 0x8e58:
...
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  ...
  [16] .text             PROGBITS         00000000000010c0  000010c0
       00000000000002b5  0000000000000000  AX       0     0     16

Before we collect an execution trace using perf, you may have to:

echo kernel.kptr_restrict=0 | sudo tee -a /etc/sysctl.conf # Configure sysctl.conf to make kernel symbols visible:

echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid # Configure system to allow events by all users

Run perf record with the required filter:

$ perf record -e intel_pt/cyc=0,noretcomp,tsc=0,mtc=0/u --filter 'filter 0x10c0 / 0x2b5 @ ./app_O0_g' -o perf.data-app_O0_g -- ./app_O0_g "hello world"

You have entered 2 arguments:
./app_O0_g
hello world
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.003 MB perf.data-app_O0_g ]

By default, the Intel PT trace output and auxiliary data generated by perf record are saved to perf.data. We only want the Intel PT trace output (without the auxiliary data) -- we can extract the Intel PT trace output using libipt's perf-read-aux.bash:

sudo apt install gawk # required by perf-read-aux.bash

{LIBIPT_INSTALL_PATH}/script/perf-read-aux.bash perf.data

By default, libipt's perf-read-aux.bash will save the Intel PT trace output in a new file with the -idx??.bin appendix (where ?? will depend on your CPU number).

Finally, we use ptxed to reconstruct the control flow:

{LIBIPT_INSTALL_PATH}/build/bin/ptxed --pt ./perf.data-idx??.bin --raw ./app_O0_g:0x555555554000 > ptxed_output # update the path ./perf.data-idx??.bin accordingly

Note that we use the base address 0x555555554000 for the .text section because perf record will automatically disable ASLR.

Beware, the output of ptxed can be verbose:

$ tail ./ptxed_output
00005555555550fe  cmp rax, rdi
0000555555555101  jz 0x555555555118
0000555555555118  ret
000055555555518c  mov byte ptr [rip+0x2fbd], 0x1
0000555555555193  pop rbp
0000555555555194  ret
[disabled]
[cbr: 2d]
[cbr: 2e]
[paging, cr3: 00000002aee0a000]

Next, import the C++ program into Ghidra at the same base address 0x555555554000 (IMPORTANT!!!).

In Ghidra's Code Browser,

`sample.png`

The console will display some useful information:

IntelPTColorControlFlow.java> Running...
IntelPTColorControlFlow.java> >> opening /home/user/ptxed_output
IntelPTColorControlFlow.java> >> processed 201 addresses
IntelPTColorControlFlow.java> Finished!

References

Inspired by:

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools