xorhex logo

xorhex

Focus on Threat Research through malware reverse engineering

ImHex Pattern and YARA Functionality

Using ImHex to build understanding of structured content and how to use the built-in YARA functionality.

xorhex

5-Minute Read

#ImHex

Summary

This article covers:

  • Installing and setting up ImHex
  • Using the pattern editor
  • YARA integration

Installation

I prefer to install ImHex by source. There are also nightlies that can be downloaded. I recommend trying those first before trying the compiling guide below, as it should be simpler. ImHex works on Windows, Linux, and MacOS.

ImHex installation steps on a Ubuntu 21.10 VM are roughly as follows:

Build

git clone --recurse-submodules https://github.com/WerWolv/ImHex.git
cd ImHex/dist
sudo ./get_deps_debian.sh
cd ..; mkdir build; cd build;
export CXX=g++-10
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j

Install

sudo ln -s /path/to/ImHex/build/imhex /usr/bin/
sudo ln -s /path/to/ImHex/build/imhex/plugins/libimhex/libimhex.so /usr/lib/

mkdir ~/.local/share/imhex
mkdir ~/.local/share/plugins
mkdir ~/.local/config/imhex

ln -s `pwd`/plugins/libimhex/libimhex.so ...
ln -s `pwd`/plugins/builtin/builtin.hexplug ~/.local/share/imhex/plugins/

Add Additional Resources

Next clone this to some directory outside of the ImHex git repo.

git clone https://github.com/WerWolv/ImHex-Patterns.git

Set up some soft links:

cd ImHex-Patterns
ln -s `pwd`/constants ~/.local/share/imhex/
ln -s `pwd`/includes ~/.local/share/imhex/
ln -s `pwd`/magic ~/.local/share/imhex/
ln -s `pwd`/patterns ~/.local/share/imhex/
ln -s `pwd`/tips ~/.local/share/imhex/
ln -s `pwd`/yara ~/.local/share/imhex/

Running

If everything is set up correctly, then hit alt+f2 and type in imhex to launch it.

Alt+F2

The initial screen will look something like this:

ImHex Default Screen

Post Starting ImHex Setup

Use the File -> Open dialog and select a PE file to open.

For this exercise use the file hashed as 53a8a63c14bb562ab71bf2283f10e3ed23717f7393aa3f6f8eb213ac48465769.

The screen initially probably won’t look like this.

File Loaded

Use the View drop down menu to add panels to the screen.

View Menu

They can be dragged and dropped to where desired.

Using ImHex

ImHex has many features, the two covered here are file format research using patterns and drafting/testing YARA rules using the baked in YARA functionality.

File Format Research

ImHex comes with some pre-made patterns installed via https://github.com/WerWolv/ImHex-Patterns.git earlier but let’s create a new one.

As part of the #100DaysOfYARA I had created a pattern for the CodeView structure; let’s use that here.

First draft the struct from some online documentation.

struct CodeView {
    char signature[4];
    u128 pdb_guid;
    u32 age;
    char pdb_path[];
};

The ImHex pattern documentation can be found here and defines what each of these types are. One thing to note, char with an empty [] will stop once a null byte is found. char with a number in the [] like [4] means the array is hardcoded to that length.

Next, tell ImHex where in the file to read the byte from.

CodeView codeview @ std::mem::find_sequence(0, 0x52, 0x53, 0x44, 0x53);

Start with the type being looked for (aka. what we defined above), CodeView. Follow that with a variable name; in the code snippet it’s called codeview. Then tell it where to start reading the bytes from with what is on the right side of the @ sign.

One way to find the CodeView section is to look for the sequence of bytes for RSDS (we should properly walk all of the PE files structures to get here but that is an exercise for another time). ImHex has a function called std::mem::find_sequence which can be used to find the first occurance of RSDS.

std::mem::find_sequence

The return value of find_sequence gives the address from which the pattern will read the bytes from.

To recap:

struct CodeView {
    char signature[4];
    u128 pdb_guid;
    u32 age;
    char pdb_path[];
};

CodeView codeview @ std::mem::find_sequence(0, 0x52, 0x53, 0x44, 0x53);

To apply the pattern, hit the play button.

Apply Pattern

ImHex is a little buggy. If there are typos in the pattern, ImHex will likely crash. If ImHex crashes, please create an issue of GitHub; the developer is quite responsive.

Notice the pdb_guid value is an uint64 number; however, it should be represented as a GUID. ImHex allows for custom formatting of the value; so define a function that will read in a uint64 value and return a GUID value.

fn guid(u128 value){
    u32 one = value & 0xffffffff;
    u16 two = value >> 8*4 & 0x0000ffff;
    u16 three = value >> 8*6 & 0x0000ffff;
    be u16 fourth = value >> 8*8 & 0x0000ffff;
    be u32 fifthPartOne = value >> 8*10 & 0xffffffff;
    be u16 fifthPartTwo = value >> 8*14 & 0x0000ffff;
    return std::format("{:x}-{:x}-{:x}-{:x}-{:x}{:x}", one, two, three, fourth, fifthPartOne, fifthPartTwo);
};

The parts of the PDB GUID value are read differently. The first three parts are read in little endian and the last two parts are read in big endian - though different tools may read them differently. Here we are following how VirusTotal reads them.

Update the struct to tell pdb_guid to use this function to interpret the value:

u128 pdb_guid [[format("guid")]];

The parameter for the format function is the name of the function passed in as a string value.

The last modification needed is to set the color for each section. Add an unique RGB color code for each of the items in the struct like so [[color("0000FF")]].

The final result should look like this:

fn guid(u128 value){
    u32 one = value & 0xffffffff;
    u16 two = value >> 8*4 & 0x0000ffff;
    u16 three = value >> 8*6 & 0x0000ffff;
    be u16 fourth = value >> 8*8 & 0x0000ffff;
    be u32 fifthPartOne = value >> 8*10 & 0xffffffff;
    be u16 fifthPartTwo = value >> 8*14 & 0x0000ffff;
    return std::format("{:x}-{:x}-{:x}-{:x}-{:x}{:x}", one, two, three, fourth, fifthPartOne, fifthPartTwo);
};

struct CodeView {
    char signature[4] [[color("FF0000")]];
    u128 pdb_guid [[format("guid"),color("00FF00")]];
    u32 age [[color("0000FF")]];
    char pdb_path[] [[color("ff00ff")]];
};

CodeView codeview @ std::mem::find_sequence(0, 0x52, 0x53, 0x44, 0x53);

ImHex’s pattern language can be quite helpful when drafting YARA rules against structured data.

YARA Testing

ImHex’s YARA functionality is useful when developing YARA rules due to the feedback it gives the user. Before diving into using YARA rules in ImHex, let’s go over a YARA development setup for ImHex.

ImHex does not currently have a built-in YARA editor so an external editor is needed; one choice is VSCode. Second, save the YARA rules to ~/.local/share/imhex/yara for ImHex to find them.

To showcase ImHex’s YARA features, create and save this rule to ~/.local/share/imhex/yara/test.yar

rule find_set {
    strings:
        $set = "set" nocase
    condition:
        $set
}

Make sure 53a8a63c14bb562ab71bf2283f10e3ed23717f7393aa3f6f8eb213ac48465769 is loaded into ImHex and run the YARA rule against it.

Follow the arrows from right to left to run the rule for the first time.

Load and Run

Each of the matching strings can be selected and the hex view will update to the corresponding location. This can be really valuable when trying to visualize what was found and what may be nearby the string.

Recent Posts

Categories

About

Hosting my custom tools, threat research, and general reverse engineering notes.