Skip to content

Tool for integrating Intel Processor Trace (PT) with Ghidra.

Notifications You must be signed in to change notification settings

mqf20/ghidra-PT

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

Ghidra Integration with Intel Processor Trace

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:

About

Tool for integrating Intel Processor Trace (PT) with Ghidra.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages