Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Welcome to Hex-Rays docs

Discover the core of Hex-Rays guides and manuals, guiding you through IDA features and real-life usage scenarios.

Getting Started

New to IDA? Explore our selection of documentation to guide you through the installation process and jumpstart your reverse engineering journey.

Install IDAGet your IDA instance up and running on your local machine.
Manage your licenseCheck how to handle your license key file to keep IDA subscription active.
Check basic featuresReverse your first binary file and discover the capabilities of disassembly and decompilation.

Our Guides

Delve into detailed guides to discover IDA features and maximize its capabilities.

User GuideExplore the main IDA interface and features, learn how to customize your experience and take advantage of plugins or utilities.
Developer GuideExplore the intuitive Domain API and start scripting with ease, or dive deeper with the low-level C++ and IDAPython SDK.
Admin GuideCheck how to install and manage Teams and Lumina servers as well as handle floating licenses.

What’s new in Docs?

Check the latest changes in the Hex-Rays documentation, including new tutorials and manuals, along with significant revisions to existing content.

November 2025

Introducing IDA Plugin Manager and Enhanced Plugin Ecosystem

With the rollout of the IDA Plugin Manager and a refined plugin ecosystem for discovering, installing and maintaining plugins we’re entering a new era of plugin management; for both plugin users and plugin authors.

For Plugin Users:

Plugin Manager transforms how you discover and install plugins. Browse available plugins via HCLI and install them in IDA with just a few clicks. Read the Plugin Manager docs for more.

For Plugin Developers:

Manual submissions via My Hex-Rays portal are a thing of the past. Publishing your plugin into new IDA Plugin Repository now follows a transparent, automated process that gets plugins into users’ hands faster. Ensure your plugin is compatible with HCLI and Plugin Manager, and it’s ready to be listed!

To ease the adoption, we’ve prepared a set of documents to make your plugin compatible with HCLI and Plugin Manager:

Repository Architecture | Packaging Format | Publishing guidelines | Testing checklist |

What’s Changed in a nutshell:

  • ida.plugin.json file has new required and optional fields.
  • Plugins need to be packed into ZIP Archive
  • You should publish releases on GitHub

Migrating your existing plugins

Already submitted a plugin under the plugins.hex-rays.com? Check our FAQ for guidance on updating to the new ecosystem.

October 2025

Introducing HCLI Commands and Documentation Resources

With the release of HCLI - an extendable command-line interface for managing licenses, downloads, and more - the docs now include hint boxes showing HCLI commands as faster alternatives to certain actions. This is especially worth taking a glimpse at for admins who manage multiple license environments or plugin authors looking to automate their workflows.

Getting started:

  • Check out the HCLI documentation for installation steps, usage examples, and guidance on creating extensions.

Automation workflow:

  • Are you a plugin developer who wants to automate plugin testing and workflows? Take a look at the HCLI IDA GitHub Action for CI/CD integration that automatically installs IDA Pro and allows you to run tests across multiple platforms.

August 2025

Domain API Documentation Resources

The easy-to-use Domain API is our newly released, Pythonic interface for developing IDA plugins and scripts. To help you get up and running quickly with this open-source API, we’ve prepared a set of documentation resources:

Not sure if the Domain API is right for you?

If you’re new to the Domain API, start with our FAQ to see how it compares with existing approaches and whether it suits your needs.

June 2025

Revamped Subviews Overview

We refreshed and updated the Subviews listing and overview.

March 2025

Improved IDC Reference

We’ve refined the experience for the IDC Reference documentation. Starting now, you can explore it just like the IDAPython and C++ SDK references. To improve searchability and usability, we’ve moved the IDC function lists to a dedicated site. Meanwhile, conceptual documentation, such as core concepts, remains under the Developer Guide.

License Server on WSL – New Guide

We updated our Admin Guide with a step-by-step tutorial on how to configure the license server on WSL, making it easier for Windows users to set up and manage the Hex-Rays server for floating licenses.

February 2025

Debugger Tutorials – revamped and expanded

License management command line options

The -Olicense command line switch is now documented as a part of the license manager.

January 2025

New Floating Licenses User Guide

We’ve introduced a Floating Licenses User Guide, that explains core concepts such as seats allocation, checking out, and borrowing licenses.

December 2024

Updated Porting Guides

With the recent changes to our API that came into life with SP1 for IDA 9.0, we updated Porting Guides for IDAPython and C++ SDK.

New IDAPython examples

With the new or reworked IDAPython examples that were added to our examples library, we revamped the examples categories to make the navigation among them more intuitive. Take a look at the new Working with types category for samples that utilize our updated Types endpoints.

Revamped IDAPython reference

We updated the UI layout of IDAPython Reference Documentation and improve cross-referencing.

November 2024

Other updates

  • To reflect the current state of Local Types window as a one hub to all types-related operations, we updated the Subviews.

October 2024

With IDA 9.0, we changed how the Hex-Rays documentation is organized and added new guides and tutorials to kickstart your IDA journey and ease the migration from previous IDA versions.

New Structure

Our docs are divided into three main categories:

  • User Guide, dedicated to individual users and covering whole IDA products (including add-ons, like Teams and Lumina). Most of the documentation regarding IDA, like manuals or tutorials, is currently accessible under the User Guide.
  • Developer Guide, which focuses on developer’s needs, covers the reference and contextual documentation for IDAPython API and C++ SDK, as well as native IDC language. This part is mainly dedicated to plugin authors and devs interested in enhancing basic IDA capabilities with our development kit or scripting.
  • Admin Guide mainly focuses on administrators installing and managing servers for Teams and Lumina or floating licenses.

In Archive, we gathered docs with rather historical value that some of you may still find interesting but focused on previous versions of IDA.

New Getting Started Guides

We prepared a Getting Started section for IDA newbies and also gathered additional materials to help you find your way around our IDAPython API or IDA SDK.

Migration and Porting Guides

For those familiar with previous versions of IDA, we prepared Porting Guides for IDAPython and C++ SDK. If you use the Flexera server for floating licenses, check our Migration Guide for new Hex-Rays license server.

New features described

We added installation and setup guides for IDA Feeds plugin and idalib.

Getting Started

First experience with IDA? Great, you are in the right place. Here you can find guides designed to quickly onboard you into IDA. We will walk you through license activation and IDA installation to the essential tasks you can perform in IDA.

Activate your license Check how to activate your license in My Hex-Rays portal.
Install your IDA Get smoothly through installation process on your machine.
Start using IDA Check basic features of IDA and reverse your first binary.
Begin scripting with Domain API Explore a simple and open-source Python API for common tasks.

Install IDA

By following the steps in this guide, you can successfully install your IDA instance on macOS, Linux, and Windows.

The installation steps are valid for all product versions: IDA Pro, IDA Home, or IDA Free.

This installation guide is dedicated to individual users.

Minimum system requirements

{% tabs %} {% tab title=“macOS” %} macOS 12 (Monterey) or later (x64 or ARM64) {% endtab %}

{% tab title=“Linux” %} x64 (x86_64) CentOS 7 or later, Ubuntu 16.04 or later. Other equivalent distributions may work but not guaranteed. {% endtab %}

{% tab title=“Windows” %} Windows 8 or later (x64) {% endtab %} {% endtabs %}

Pre-installation steps

Activate your named or computer license via My Hex-Rays portal.

Installation on macOS

Prerequisites:

  • Ensure that you have activated your computer/named license and downloaded your license file (ida.hexlic) locally.
  • Make sure Python 3 or later is installed on your computer for the IDAPython API to function properly.

Step 1: Download the installer

  • Download the macOS version of IDA Pro from Download Center in My Hex-Rays portal.

Quick alternative
{% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli download {% endhint %}

Step 2: Run the installer

  • Extract the .zip archive.
  • Double-click on the extracted file to run the instalation wizard.
  • Follow the wizard’s instructions to complete the installation:
    • accept the license agreement and installation directory;
    • copy your ida.hexlic file to IDA installation directory or to $HOME/.idapro directory before launching IDA.

Quick alternative {% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli ida install <path-to-installer> {% endhint %}

Step 3: Launch IDA Pro for the first time

  • Double-click on the IDA Pro icon to launch the application.

Step 4: Point to your named/computer license

{% hint style=“info” %} The step below is valid for named and computer licenses for individual use. If you are going to use floating licenses, check this alternative step. {% endhint %}

  • In the License manager pop-up window, specify the path of your license file and click OK.

License manager

{% hint style=“info” %} You won’t be asked about your license again unless the subscription period expires or you move your license file to a different location. {% endhint %}


Installation on Linux

Prerequisites:

  • Ensure that you have activated your computer/named license and downloaded your license file (ida.hexlic) locally.
  • Make sure Python 3 or later is installed on your computer for the IDAPython API to function properly.
  • Verify that you have the required libraries installed. Use your package manager to install any missing dependencies. Common dependencies include libx11, libxext, libxrender, and libglib2.0.

Step 1: Download the installer

  • Download the Linux version of IDA Pro from Download Center in My Hex-Rays portal.

Quick alternative
{% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli download {% endhint %}

Step 2: Run the installer

  • Navigate to the directory containing your IDA installer, and make it executable.
  • Run the installer by double-click it or enter ./<your_IDA_version_>linux.run in the terminal to execute it.
  • Follow the wizard’s instructions to complete the installation:
    • accept the license agreement and installation directory;
    • copy your ida.hexlic file to IDA installation directory or to $HOME/.idapro directory before launching IDA.

Quick alternative {% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli ida install <path-to-installer> {% endhint %}

Step 3: Launch IDA Pro for the first time

  • Go to the directory where IDA is installad and run the command: ./ida90

Step 4: Point to your named/computer license

{% hint style=“info” %} The step below is valid for named and computer licenses for individual use. If you are going to use floating licenses, check this alternative step. {% endhint %}

  • In the License manager pop-up window, specify the path of your license file and click OK.

{% hint style=“info” %} You won’t be asked about your license again unless the subscription period expires or you move your license file to a different location. {% endhint %}


Installation on Windows

  • Ensure that you have activated your computer/named license and downloaded your license file (ida.hexlic) locally.
  • Make sure Python 3 or later is installed on your computer for the IDAPython API to function properly.

Step 1: Download the installer

  • Download the Windows version of IDA Pro from Download Center in My Hex-Rays portal.

Quick alternative
{% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli download {% endhint %}

Step 2: Run the installer

  • Locate the downloaded .exe file and double-click it to run the installer.
  • Follow the installation wizard’s instructions to complete the installation:
    • accept the license agreement and installation directory;
    • copy your ida.hexlic file to IDA installation directory or to %APPDATA%/Hex-Rays/IDA Pro directory before launching IDA.

Quick alternative {% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli ida install <path-to-installer> {% endhint %}

Step 3: Launch IDA Pro for the first time

  • Navigate to the Start Menu or desktop shortcut and launch IDA Pro.

Step 4: Point to your named/computer license

{% hint style=“info” %} The step below is valid for named and computer licenses for individual use. If you are going to use floating licenses, check this alternative step. {% endhint %}

  • In the License Manager pop-up window, specify the path of your license file and click OK.

{% hint style=“info” %} You won’t be asked about your license again unless the subscription period expires or you move your license file to a different location. {% endhint %}


Use floating license server

Step 1: In the License manager pop-up window, select the option Use floating license server and then type a license server hostname provided by your administrator.

Step 2: Borrow one of the licenses visible under the available licenses list and click OK.

Note that you don’t need a license file stored on your machine locally while using floating licenses.


Common Post-Installation Steps

Step 1: Update IDA Pro

  • After installation, check for any available updates. Hex-Rays often releases patches and updates for IDA Pro. You can check for updates within the application via Help -> Check for free update or download the latest version from My Hex-Rays portal.

Step 2: Configure environment (optional)

Step 3: Install additional plugins (optional)

  • You can extend the functionality of IDA Pro by installing additional plugins that can be found on the official Hex-Rays repository or other trusted sources in the reverse engineering community.

Licensing

In this document, we covered the fundamentals of our licensing model—including how to activate your license based on its type, check license’s details and share them with your team members.

Here, you can learn how to:

Licenses overview

License types

At Hex-Rays, we offer two basic license types for IDA products, which are suitable for individual users:

  • Named licenses, that are assigned to specific individuals.
  • Computer licenses that are assigned to specific devices.

There is also an additional type, called floating licenses, that allow a set number of concurrent users but are not assigned to specific individuals or devices.

{% hint style=“info” %} Floating licenses are available only for IDA Pro and dedicated to business/organization purposes. {% endhint %}

How many licenses should I have?

Beside the license for IDA product, you need also a separate active license for each server available in your subscription.

The components of your subscription that require their own license:

  • Base IDA license (e.g., IDA PRO Expert 4)
  • Teams server for Teams add-on
  • Lumina server for Lumina add-on
  • License server for floating licenses

Example: You’ve purchased IDA PRO Expert 4 Plan with Teams and Private Lumina, along with floating type of license with 6 seats. In this case, you’ll need to activate the following four licenses:

  1. License server license
  2. Private Lumina server license
  3. Teams server license
  4. IDA PRO Expert 4 license

What’s a license file?

The .hexlic license file contains your license ID and other data, and is required to make your IDA instance fully operative after installation (or your Lumina, Teams or License server). You can download your license files from My Hex-Rays portal, after their activation.

{% hint style=“info” %} Once you’ve downloaded your license, it cannot be modified. {% endhint %}

License activation

To complete the installation, you need an active IDA license with an assigned owner (for a named license) or a MAC address (for a computer/floating license). Without activation, you cannot download your license file.

What is needed to activate my license?

  • for named licenses: the email address of the owner,
  • for computer licenses: the MAC address of a specific device
  • for floating licenses: the MAC address of the device where the license server will be running

{% hint style=“info” %} The license type (named/computer/floating) is selected when you purchase your subscription. {% endhint %}

Where can I activate my license?

From the License tab in My Hex-Rays portal, you can initiate the activation process and open the License activation dialog from several locations:

  • In the table, locate your license and click Activate Now (1),
  • Click on the desired license to open its detail view, then click Activate License (2), or
  • Select multiple licenses of the same type by ticking their checkboxes, then click Bulk Activation (3).

Activate license

Activate license

Bulk Activate

Named licenses activation

  1. Go to My Hex-Rays portal and navigate to the Licenses tab.
  2. Locate the license ID you want to activate. Ensure it has the Pending activation status.

{% hint style=“info” %} If you haven’t completed the KYC procedure yet, you will need to do so for accessing paid products. A Pending KYC status indicates that your verification is still in progress and must be completed before you can activate your license. {% endhint %}

  1. Open the License activation dialog, select decompilers and click Next.
  2. Assign the ownership of the license: set the email address for this IDA instance user (it can be yours) and click Activate license.

Activate named license

Your license is now active.

You can check the license details and modify it if needed. If all details are correct, you can download your license key.

Computer licenses activation

  1. Go to My Hex-Rays portal and navigate to the Licenses tab.
  2. Locate the license ID you want to activate. Ensure it has the Pending activation status.

{% hint style=“info” %} If you haven’t completed the KYC procedure yet, you will need to do so for accessing paid products. A Pending KYC status indicates that your verification is still in progress and must be completed before you can activate your license. {% endhint %}

  1. Open the License activation dialog, select decompilers and click Next.
  2. Add the MAC address of the machine where this IDA instance will be installed and running (it can be yours) and click Activate license.

Activate computer license

Your license is now active.

You can check the license details and modify it if needed. If all details are correct, you can download your license key.

Download the license files

If you are sure that all of the license details are correct, you can go ahead and download your license hexlic file. You will need it to complete the installation process.

{% hint style=“warning” %} Downloading the license locks the configuration and prevents further edits. {% endhint %}

  1. Go to the Licenses tab in My Hex-Rays portal.
  2. Under the Actions column, click the three dots and then Download hexlic from the dropdown menu (1), or, alternatively, in the license detail view, click Download hexlic.

Download hexlic

  1. To download multiple license files at once, select the desired licenses by ticking their checkboxes, or click Select all. Then, click Download License Files (2). You’ll receive an email with a link to download all license files and a CSV.

Download the floating license files

  1. Go to the Servers tab in My Hex-Rays portal and locate your IDA License Server Plan.
  2. Under the Actions column, click the three dots and then Download hexlic from the dropdown menu.

Download hexlic

{% hint style=“info” %} In a floating license setup, you don’t need the individual hexlic files for the IDA clients installed on users’ machines. {% endhint %}

Quick alternative {% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli license get {% endhint %}

What’s next?

Now you are ready to install your IDA instance.

Floating licenses activation

To use floating licenses, you need to activate:

  • A license for your license server
  • A base IDA Pro license linked to that server

Both licenses can be activated and linked in a single step, as described below.

  1. Navigate to the Licenses tab and look for your IDA license with Floating label. Ensure it has the Pending activation status.
  2. Open the License activation dialog, select decompilers and click Next.
  3. Assign a license server. If you added the license server before, select the Use existing server option and then tick the server from the list. If you haven’t done it yet, you can add and activate a license server now—select Add new server option, type the MAC address and click Add.

License activation floating

  1. Add tags if needed, and click Activate license to finalize.
  2. Your license(s) is now active.

You can check the license details and modify it if needed.

If all details are correct, you can download your license key and license files for the license server.

Bulk activation

If you have multiple licenses of the same type (for example, ten IDA PRO Expert 2 licenses), you can activate them all in a single batch operation. All licenses activated in bulk will share the same configuration details, decompilers set, and add-ons, while allowing for unique owner email addresses and MAC addresses.

  1. Go to My Hex-Rays portal and navigate to the Licenses tab.
  2. Locate the licenses you want to activate with the Pending activation status. Select all of them by ticking the checkboxes on their left side.
  3. In the top menu that appears after selection, click Bulk Activation.

Bulk activate licenses

  1. In the new dialog, select decompilers (this action is done for all licenses in a batch) and click Next.
  2. Depending on your licenses type, assign the license user’s emails or set the MAC addresses. Optionally, you can add tags.
  3. Click Activate Licenses.

You’ve noticed a mistake? No worries, you can still edit your selected licenses before downloading them.

Bulk download the license files

  1. In the Licenses tab, select the licenses for bulk download and click Download License Files.
  2. After confirmation, you’ll get an email with link to download all license files + CSV.

License details

The License Details card provides a complete overview of the license, including assigned decompilers and users it has been shared with. You can edit access permissions and tags at any time, even for active and already downloaded licenses.
To open the License Details view, go to the My Hex-Rays portal, open the License or Servers tab, and click the license you want to view.

License Details view

License editing

When you activate your license using one of the methods shown above, you can still make changes—such as modifying the decompiler set—as long as you have not downloaded the license file(s). Once the license file(s) are downloaded, further modifications will no longer be possible.

To edit the license:

  1. Go to My Hex-Rays portal and navigate to the Licenses or Servers tab.
  2. Locate the licenses you want to edit with the Active status. Under the Actions column, click the three dots and then Edit from the dropdown menu, or alternatively, in the license detail view, click Edit. If the Edit option is not visible, it means the license has already been downloaded and can no longer be edited.

Edit license

  1. Make changes and click on Next/Activate license to confirm.

Server licenses

If your subscription includes a server (for Private Lumina, Teams or floating licenses), you’ll need to activate the corresponding server licenses to download the license files. To do so, make sure to add the relevant servers to your account.

{% hint style=“info” %} You can create and activate the license server simultaneously during the IDA floating license activation process. {% endhint %}

Add servers

  1. In My Hex-Rays portal, go to the Servers tab and click + Add server.

Add server

  1. Select the type of server(s) you want to add and click Next. You may add multiple servers at one go.

Add servers dialog

  1. Assign MAC addresses and click Create servers to finalize.
  2. After that, your servers will appear in the Servers list with an Active status, allowing you to download the server certificates (1) and hexlic files (2).

Active server licenses

  1. If you are using floating licenses, you can now go ahead and activate your IDA licenses that uses the server.

{% hint style=“info” %} Ensure all floating license plans associated with the license server are activated before downloading the license server hexlic file. {% endhint %}

Downloading the server license files

Once all IDA PRO licenses intended for use with your floating license server have been activated, you can proceed to download the server’s hexlic file and license certificate.
Maintaining this order is crucial—the hexlic file contains essential details about the linked licenses, which are properly embedded only when the IDA license is associated with the specific floating license server.

License server installation for admins

Server installation for floating licenses should be done by the administrator. Check our Admin Guide for details.

How can I start using IDA as a floating license user?

Once your administrator installs a license server, adds particular license seats to the pool, and hands over the credentials, you are ready to install your IDA instance.

You don’t need to download a license file/key to your local machine while using the floating licenses server.
New to the floating licenses? Check our Floating Licenses User Guide.

Floating licenses check-out

Every time you launch IDA, you’ll see the License Manager pop-up window. As long as there are free seats, you can check-out one of the available licenses and start using IDA.

{% hint style=“info” %} Note that some of the available licenses may have different decompilers and add-ons enabled. {% endhint %}

Add-ons servers’ licenses

Private Lumina server activation for admins

Each of our add-ons, Teams and Private Lumina, requires an active license to work properly. To proceed with Lumina installation and setup, an active server’s license is required.

  1. Add server in your account (activate the license).
  2. Locate your server license on the Servers tab and download the following files:
  • lumina server certificate (1)
  • .hexlic file (license key) (2)

Download Lumina license files

You’ll need both files to continue with the server installation and setup.

Quick alternative {% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli license get {% endhint %}

Private Lumina server installation for admins

Server installation for Private Lumina should be done by the administrator. Check our Admin Guide for details.

Teams server activation for admins

Each of our add-ons, Teams and Private Lumina, requires an active license to work properly. To proceed with Teams installation and setup, an active server’s license is required.

  1. Add server in your account (activate the license).
  2. Locate your server license on the Servers tab and download the following files:
  • teams server certificate (1)
  • .hexlic file (license key) (2)

Download Teams license files

You’ll need both files to continue with the server installation and setup.

Quick alternative {% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli license get {% endhint %}

Teams server installation for admins

Server installation for Teams should be done by the administrator. Check our Admin Guide for details.

Grant access to manage licenses

You can invite your teammates to view and activate licenses via their own My Hex-Rays account. To grant access:

  1. Select license(s) you want to share and click Grant Access (1).
  2. Add the email address of your teammate and click Confirm (2).
  3. Your team member will receive an email invitation to log in to the portal and access the shared licenses.

Grant access

The License Details view allows you to review who currently has access to the license, remove users, or grant access to new ones.


Key points:

  • Once a license has been downloaded, it cannot be modified.
  • Multiple licenses of the same type can be activated in bulk.
  • You can grant the access to manage licenses to other teammates, while the ownership of the license remains the same.

Change your plan

If you need additional decompilers or add-ons, you can upgrade your plan at any time through My Hex-Rays portal.

Steps to update your plan:

  1. Go to the Licenses tab.
  2. Find/select the IDA license plan you want to renew.
  3. Click Renew/Change plan in the top panel or in the license’s row in the table.

Renew/Change plan

  1. Review the plan options. You can upgrade your plan, change the license type to floating, and add seats or add-ons.
  2. Select Change plan (starts immediately) to apply the changes right after the upgrade. Click Continue to Payment to finalize.

Review plan options

  1. The new plan will appear under the Licenses tab with a Pending Activation status. Activate the license to start using the updated plan.

{% hint style=“info” %}

Actions Required After Update

If you upgraded your plan (for example, from IDA PRO Expert 2 to IDA PRO Expert 4), you will need to activate your new license and download the new license files before you can use the updated plan. {% endhint %}

Renew your plan

You can renew your subscription and, if needed, change your plan(s) in one go through My Hex-Rays portal.

Steps to renew and change your plan:

  1. Go to the Licenses tab.
  2. Find/select the IDA license plan you want to renew.
  3. Click Renew/Change plan in the top panel or in the license’s row in the table.

Renew/Change plan

  1. Select subscription duration and review the plan options. You can upgrade/downgrade your plan, change the license type, and add seats or add-ons.
  2. Select one of the following options:
  • Renew (starts after current period), if you want all changes to be applied at the renewal date, or
  • Change plan (starts immediately), if you want the changes to take effect right away. Click Continue to Payment to finalize.

Review plan options

  1. Based on your selection, follow the appropriate scenario:
  • a. Renewal without plan change: The subscription validity is automatically extended. Re-download the license files and save them in your usual location (You can check and change the .hexlic location via Help → License Manager…).
  • b. Renewal with plan change: The new plan will appear under the Licenses tab with a Pending Activation status. You need to activate it, then download and save the new license file locally.

{% hint style=“info” %} If you would like to downgrade your current plan, you can do that at your next renewal date only. {% endhint %}

{% hint style=“info” %}

Actions Required After Renewal With/Without Upgrade

If you upgraded your plan (for example, from IDA PRO Expert 2 to IDA PRO Expert 4), you will need to activate your new license and download the new license files before you can use the updated plan. If you renewed your existing plan without changes, re-download a license file to apply the extended validity period. {% endhint %}

License Renewal and Update FAQ

How can I change only my decompilers?

If you only want to change the type of decompilers (not the number of decompilers, and without upgrading or downgrading your plan), this can be done after your current plan expires. Instead of renewing the current plan, you will need to place a new order. A new license will then be generated, and during activation you will be able to choose different decompilers.

How can I add more decompilers to my current plan?

To add more decompilers to your active subscription, you’ll need to upgrade to a higher plan that includes the desired number of decompilers. You can upgrade your plan at any time through My Hex-Rays portal, and choose to apply the changes immediately.

What changes can I make during renewal?

You can apply the following changes during renewal via My Hex-Rays portal:

  • Switch to a different license type
  • Upgrade or downgrade your plan
  • Add optional add-ons (Teams or Lumina)
  • Add additional seats

Some changes, such as downgrading a plan or changing the license type from computer to named, can only take effect at the next term, not during the active subscription period.

For other modifications, such as changing an active license type from named to computer, contact our Sales team

What changes can I make to my active license?

During your current subscription period, you can:

  • Upgrade to a higher plan
  • Add seats or add-ons
  • Switch to a floating license type

You can apply these changes immediately to your active license.

Can I change the license type of my active subscription plan?

During an active subscription period, the only license type change you can make yourself via My Hex-Rays portal is switching to a floating license. Other changes (e.g., switching between named and computer licenses) are only possible at renewal for the next term, or require assistance from our Sales team.

Can I downgrade my active license?

Downgrades are possible only for your next renewal date.

I have IDA Pro Essential and want to upgrade to IDA Pro Expert 4. How can I do this?

You can upgrade your plan at any time through the Customer Portal, and choose to apply the changes immediately, or at your next renewal date. Check the details on how to change your current plan.

I have named license, can I change the license type to computer?

You can change the license type (for example, from the named to computer) via customer portal only while renewing for the next term. In other words, you cannot change the license type for active subscription period. If you need to do that for some reason, contact our Sales team.

Why can’t I renew or change the license?

If the Renew/Change plan option is missing or greyed out, it means the license was shared with you and bought by someone else. Only the person who purchased the license can renew or modify the plan.

Basic Usage

Basic Usage

In this document, we’ll explore the essentials of IDA capabilities to kickstart your journey and disassemble your first binary file.

Prerequisites

Your IDA instance is installed and running.

Before you begin

What files and processors are supported?

IDA natively recognizes plenty of file formats and processors.

If you later realize that’s not enough, you can always use one of our community plugins that add additional formats or processor types or try to write your own with C++ SDK.

What are IDA database files?

IDA stores the analysis results in the IDA Database files (called IDB), with the extension .i64. This allows you to save your work and continue from the same point later. After loading a file at the beginning, IDA does not require access to the binary.

Any modifications you make are saved in the database and do not affect the original executable file.

Dive deeper

What decompilers can I work with?

IDA provides decompilers designed to work with multiple processor architectures. The number of decompilers and their type (local or remote) available in your IDA instance depends on your chosen product and subscription plan and affects your ability to produce C-like pseudocode.

Where can I find exemplary binaries to work with?

Check CrackMe, from where you can download executable files to test your reverse engineering skills.

Part 1: Loading your file

When you launch IDA, you will see a Quick Start dialog that offers three ways to continue. For now, we’ll focus on loading a new file and proceeding to disassembly results.

  1. Launch IDA and in the Quick start dialog (1), click New.
  2. Specify the path for your binary file.
  3. In the Load a new file dialog (2), IDA presents loaders that are suited to deal with a selected file. Accepting the loader default selection and then the processor type is a good strategy for beginners. Click OK to confirm your selection.

Quick start

  1. IDA begins autoanalysis of your binary file.

After completion, you will be present with the default IDA desktop layout, that we’ll describe in the next part.

Dive deeper

Part 2: UI overview

After autoanalysis is done, you’ll see the main IDA desktop with the initial results. Let’s examine the default desktop layout and commonly used UI elements.

UI overview

  1. Main menu bar (1)
  2. Toolbar (2)
  3. Navigation band (3)
  4. Subviews (4)
  5. Output (5)
  6. Status bar (6)

The main menu bar provides quick access to essential features. Moreover, almost all menu commands can be quickly accessible via customizable shortcuts.

Main Menu Bar

For a handy cheatsheet of all commands and their hotkeys, check Options -> Show command palette….

Dive deeper

  • Docs: :book: Check our User Guide for a comprehensive description of all menu items.

Toolbar

Below the main menu bar, you will see a toolbar with icons that give you quick access to common functionalities (available also via the main menu/shortcuts). It has just one line by default, but you can customize it by adding or rearranging your actions.

Toolbar

Dive deeper

  • Video: :video_camera: Curious about practical ways to set up your toolbar? Watch our video tutorial.

The navigation band shows the graphical representation of the analyzed binary file and gives a short overview of its contents and which areas may need your attention. The yellow arrow (indicator) shows where the cursor is currently positioned in the disassembly view.

Navigation band

As you’ll soon recognize, the colors used in the nav band match those in other views.

Dive deeper

  • Blog: :pencil: A detailed navigation band overview with the full colors legend you can found in Igor’s tip of the week.

Output

The output window is a place where various messages and logs are displaying, often describing what currently IDA is doing, like analyzing data or running a script. In the CLI box you can type commands in IDC language or IDAPython.

Status bar

At the bottom left corner of the IDA window, you can see the status bar, which contains:

  • analysis indicator AU, which shows the actual status of autoanalysis (1). In our case, it is idle, which means the autoanalysis is already finished.
  • search direction indicator (2)
  • remaining free disk space (3)

Status bar

Right-clicking on the status bar brings up a context menu that allows you to reanalyze the program.

Dive deeper

  • Docs: :book: To check all possible values and their meaning, take a look at analysis options.

Subviews

The subviews are one of the most prominent parts of your everyday work with IDA. These additional views (behaving like tabs) give a different perspective and information on the binary file, but the number of native IDA subviews may be a bit overwhelming. Here, we will focus on the most versatile and common subviews for beginners, where you’ll spend most of the time, like:

  • IDA View
  • Pseudocode
  • Hex Dump View
  • Local Types
  • Functions View

Subviews

IDA View / Disassembly Window

When autoanalysis is done, you will see a graph view inside an IDA View by default. This flowchart graph should help you to understand the flow of the functions.

{% hint style=“info” %} The graph view is available only for the part of the binary that IDA has recognized as functions. {% endhint %}

IDA view has three modes:

  • graph view (1), that shows instructions grouped in blocks,
  • linear view (2), that lists all instructions and data in order of their addresses,
  • and proximity view (3), which allows you to see relations between functions, global variables, and other parts of the program.

IDA view modes

{% hint style=“info” %} Press Space to switch between graph and linear mode. Proximity view is available from the context menu in IDA view. {% endhint %}

Dive deeper

Hex View Window

In hex view, you can see the raw bytes of the program’s instructions.

There are two ways of highlighting the data in this view:

  1. Text match highlight, which shows matches of the selected text anywhere in the views.
  2. Current item highlight, which shows the bytes group constituting the current item.

Hex view

{% hint style=“info” %} The IDA view, pseudocode, and hex view can be synchronized, meaning that they highlight the same part of the analyzed program, and changes made inside one of the views are visible in the others. {% endhint %}

Dive deeper

Pseudocode Window

Generated by the famous F5 shortcut, the pseudocode shows the assembly language translated into human-readable, C-like pseudocode. Click Tab to jump right into the Pseudocode view.

Pseudocode Window

Local Types Window

This view shows the high-level types used in databases, like structs or enums.

Dive deeper

Functions Window

This window displays all the functions recognized by IDA, along with key details for each:

  • Function name
  • Segment the segment that contains the function
  • Start: the function starting address
  • Length: the size of the function in bytes
  • Local: the amount of stack space taken by local variables
  • Arguments: the amount of stack space taken by arguments

By default, the entire window is not visible, so you may scroll horizontally to see the hidden elements. As you probably noticed, the colors in Functions window match the colors in navigation band; in our example, green highlighting shows functions recognized by Lumina.

Functions view

This view is read-only, but you can automatically synchronize the function list with the IDA view, pseudocode, or hex view. Click to open the context menu and select Turn on synchronization.

Dive deeper

  • Docs: :book: Read the manual explaining all of the function window columns in detail.
  • Video: :video_camera: Watch our video tutorial exploring the functions view.

Part 3: Basic navigation

A crucial step in mastering IDA is learning how to navigate quickly to specific locations in the output. To help you get started, we’ll cover essential commands and hotkeys commonly used for efficient navigation in IDA.

Double-click and jump to the location

When you double-click on an item, such as a name or address, IDA automatically jumps to that location and relocate the display.

Jump to address

  1. Go to Jump -> Jump to address.. or press G hotkey
  2. Enter the item name or hex address in the dialog box, then click OK.

To jump back to the previous position, press Esc. To jump to the next position, press Ctrl + Enter. You can also navigate using the arrows in the toolbar.

See the list of cross-references

  1. Position the cursor on a function or instruction, then go to Jump -> Jump to xref to operand… or press X to see the dialog with listed all cross-references to this identifier.
  2. Select an item from the list and click OK to jump to that location.

Dive deeper

  • Video: :video_camera: Explore the rest of the jump commands in our video tutorial

Part 4: Manipulate your disassembly results

Now that the initial autoanalysis is done and you’ve mastered the basics of navigation, it’s time to explore the basic interactive operations that reveal the true power of IDA in transforming your analysis.

Rename a stack variable

One of the first steps you might take is to enhance readability by assigning meaningful names to local or global variables, but also functions, registers and other objects that IDA initially assigned a dummy name.

  1. In the IDA View, right-click on the variable you want to rename and click Rename or press N when the variable is cursor-highlighted.
  2. In the newly opened dialog, insert a new name and click OK.

If at any point you want to go back to the original dummy name given by IDA, leave the field blank and click OK. It will reset the name to the default one.

{% hint style=“info” %} Once you change the name, IDA will propagate the changes through the decompiler and Pseudocode view. {% endhint %}

Dive deeper

Add a comment

Adding comments may be a useful way to annotate your work.

  1. Highlight the line where you want to insert a comment and press :.
  2. In the dialog box, type your comment (you can use multiple lines) and click OK. This will add a regular (non-repeatable) comment to the location.

{% hint style=“info” %} If you want to add a repeatable comment in every location that refers to the original comment, press ‘;’. {% endhint %}

Dive deeper

  • Video: :video_camera: Watch our tutorial about commenting.

Part 5: Customizing IDA

Nearly every UI element is customizable, allowing you to rearrange and align widgets to suit your habits. You can save your personalized desktop layout by going to Windows -> Save desktop.

Most of the basic appearance you can change under Options menu.

  • To change the colors or theme, go to Options -> Colors.
  • To change the font, go to Options -> Fonts.

If you need more control over customization settings, you may check the IDA configuration files.

Part 6: Debug your file

If you are ready to delve into dynamic analysis and start debugging your programs, here are some key steps to get you started:

  1. Select the right debugger and complete the setup: Go to Debugger -> Select debugger… and pick up one of the available debuggers. Under Debugger -> Debugger options, you can configure the setup in detail.
  2. Add breakpoints: Right-click on the line where you want to stop the execution and select Add breakpoint from the context menu, or press F2.
  3. Start the process: Run the debugging session by pressing F9 or click a green arrow on the tooltip.

Dive Deeper

  • Docs: :book: Read our User Guide for local and remote debugging manuals, or check step-by-step tutorials for specific debuggers.

Part 7: Install a plugin

One of the most common way of extending IDA capabilities is to use one of our community-developed plugins.

Where can I find IDA plugins?

You can find a variety of plugins in the official Hex-Rays plugin repository, or via HCLI and Plugin Manager.

{% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli plugin search {% endhint %}

Installing your plugin

For this guide purposes, we’ll walk you through general installation steps.

{% hint style=“info” %} The installation process can vary depending on the plugin and some of them may required installing dependencies or further configuration. Don’t hesitate to refer to the specific instructions provided by the plugin author. {% endhint %}

Quick alternative
{% hint style=“success” %}

HCLI Commands | See HCLI Docs

hcli plugin install <plugin-name> {% endhint %}

Load your plugin

  1. Copy your plugin folder to the plugins directory inside your IDA installation directory.
  2. Alternatively, you can load the plugin from the command line in IDA by using File -> Script file… and selecting app.entry.py file.

Run your plugin

  1. Navigate to Edit -> Plugins -> your_plugin_name or use the assigned hotkey.

{% hint style=“info” %} You may need to restart IDA to see your plugin in the list. {% endhint %}

Dive deeper

  • Docs: :book: Want to learn about writing your own plugins?
    • For an easy entry point, check our Domain API.
    • Need more low-level control? Check our Developer Guide on how to create a plugin in IDAPython or with C++ SDK.

Key hotkeys cheatsheet

Here’s a handy list of all of the shortcuts we used so far.

  • Space Switches between graph and linear mode in the IDA View
  • F5 Generates pseudocode
  • Tab Jumps into pseudocode View
  • G Opens Jump to address dialog
  • Esc Jumps back to the previous position
  • Ctrl + Enter Jumps to the next position
  • X Shows the list of all cross-references
  • N Opens dialog to rename the current item
  • ; Adds repeatable comment
  • : Adds regular comment

Domain API: Beginner-friendly scripting and plugin development in IDA

Looking to extend IDA’s capabilities with your own scripts or plugins? Meet the Domain API—a high-level, Pythonic interface designed to simplify development and make interacting with IDA more intuitive.

What’s next?

Enroll in our trainings Maksimize your IDA experience with trainigs tailored to all skill levels.
Watch tutorials Explore the full collection of IDA Pro tutorial videos on our Hex-Rays channel.
Delve into the User Guide Read in-depth manuals that cover every aspect of IDA.
Check the blog Learn more about IDA with Igor's tip of the week and explore recent news from Hex-Rays.

User Guide

Explore our in-depth guides, crafted to help you navigate through IDA features and master its advanced capabilities.

User Interface Check the overview of the IDA interface with menu and windows views and their corresponding options
Disassembler Analize your binary and learn how to manipulate the disassembly output
Decompiler Discover strategies for optimizing pseudocode
Debugger Learn how to take advantage of all debugger features and dynamic analysis
Signatures Check how to identify known code functions and standard libraries
Type Libraries Improve your work with collections of predefined data types
Configuration Personalize IDA to meet your needs—change themes, fonts, shortcuts and more
Teams Get advantage of collaborative engineering work
Lumina Get fast function recognition with Lumina server
Plugins Learn how to install plugins and write your own
Helper Tools Check all utilities ready to extend IDA functionality
Subviews Explore the various subviews available in IDA

User Interface

Menu Bar Discover all available actions and context-sensitive options in the main menu bar
Desktops Understand how to create, save, and switch between different desktops
Subviews Explore the various subviews available in IDA

Menu Bar

{% hint style=“info” %} The menu bar in IDA gives you access to whole range of commands. All menus are always available, but some adapt their content based on your current view and your cursor position. {% endhint %}

Context-Independent Menus

These menus provide the same options regardless of which view you’re working in:

  • File: Handles opening and loading binaries, importing/exporting data, and producing output files.
  • View: Provides fast access and options to show and organize views, graphs, and toolbars.
  • Debugger: Provides controls for running, stepping through, and analyzing programs in real-time.
  • Lumina: Connects to Private or Public Lumina service to share and retrieve function metadata across different binaries.
  • Options: Configures IDA’s appearance, fonts, colors, disassembly preferences, and more.
  • Windows: Opens various tool windows and manages desktops.
  • Help: Your gateway to various help resources and license manager.

View-Dependent Menus

The following top-level menus (1) dynamically change their content based on your active view (2) and cursor location.

  • Edit - Provides context-sensitive editing operations like patching bytes, modifying instructions, renaming symbols, and changing data types.
  • Jump - Navigates to addresses, functions, cross-references, and other locations within the binary.
  • Search - Search for strings, patterns, instructions, constants, and references in the disassembly.

View-Dependent Menus

IconCurrent ViewContext-Sensitive Menu Actions
IconDisassembly/IDA ViewEdit
Jump
Search
IconHex ViewEdit
Jump
Search
IconPseudocodeEdit
Jump
Search
IconLocal TypesEdit
Jump
Search
IconFunctionsEdit
Jump
Search

File menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
New instanceNewInstanceOpen a new IDA instance
Open…LoadNewFileLoad a new file or database
Load file``
Reload the input fileReloadFileReload the input file. More…
Additional binary file…LoadFileLoad additional binary file. More…
IDS/IDT file…LoadIdsFileLoad a symbol file (IDS). More…
PDB file…LoadPdbFileLoad a debug information file (PDB). More…
DBG file…LoadDbgFileLoad a debug information file (DBG). More…
TDS file…LoadTdsFileLoad a debug information file (TDS). More…
FLIRT signature file…LoadSigFileLoad a FLIRT signature file. More…
Parse C header file…LoadHeaderFileThis command allows you to apply type declarations from a C header file to the program. More…
Produce file``
Create MAP file…ProduceMapCreate a map information file. More…
Create ASM file…ProduceAsmCreate an assembler file. More…
Create INC file…ProduceIncCreate an include file. More…
Create LST file…ProduceLstCreate a listing file. More…
Create EXE file…ProduceExeCreate an executable file. More…
Create DIF file…ProduceDiffCreate a difference file. More…
Create C file…hx:CreateCFileCreate C file
Create HTML file…ProduceHtmlCreate a HTML file. More…
Create SIG file…makesig:create_signatureCreate SIG file
Create flow chart GDL…ProduceFuncGdlCreate flow chart GDL. More…
Create call graph GDL…ProduceCallGdlCreate call graph GDL. More…
Create C header file…ProduceHeaderCreates a header file from local types. More…
Dump database to IDC file…DumpDatabaseDump database to IDC file. This command saves current IDA database into a text file. More…
Dump typeinfo to IDC file…DumpTypesDump type information to IDC file. This command saves information about the user-defined types from the IDA database into a text file. More…
Script file…ExecuteExecute a script file
Script command…ExecuteLineExecute a script command
SaveSaveBaseSave the database
Save as…SaveBaseAsSave the database as…
Take database snapshot…SaveBaseSnapTake database snapshot. More…
CloseCloseBaseClose
Quick startQuickStartDisplay the quick start window
ExitQuitIDASave everything and exit IDA

Reload the input file

Reload the input file. This command reloads the same input file into the database. IDA tries to retain as much information as possible in the database. All the names, comments, segmentation information and similar will be retained. Only the values of individual bytes will be changed. This command works for some input file types only: if the file was loaded into the database with special settings, this command may fail. In this case, use Dump database to IDC file command and reload the file manually.

Additional binary file…

Load additional binary file. The new file is added to the current database and all existing information is retained. The file content will appear as unexplored bytes in the program. This command only allows you to load binary files.

IDS/IDT file…

Load a symbol file (IDS). An IDS file contains information about well-known functions (such as functions from MS Windows API), namely:

  • their names
  • their ordinal number in the DLL
  • an eventual informative comment
  • the number of parameters passed on the stack
  • the number of parameters purged when returning IDS files are automatically loaded if they are found in the IDS directory. This command allows you to load an IDS file from any directory, even after the main file has been loaded into the database.

PDB file…

Load a debug information file (PDB). If the program being disassembled has a companion PDB file, then this command may be used to load information from the PDB file into the database. By default IDA uses in-house code to parse and load PDB files. However, our code can not parse old v2.0 PDB files. For them, IDA can fall back to using Microsoft DLLs (the default is “do not fall back”). Please read more in cfg/pdb.cfg. Command line switch -Opdb:option1:option2 overrides for ida session the value in cfg/pdb.cfg.

DBG file…

Load a debug information file (DBG). This command loads a DBG file. If the program being disassembled has a companion DBG file, then this command may be used to load information from a DBG file into the database. IDA loads DBG files automatically if it can find them in the directory with the input file. The built-in debug information loader cannot load NB10 format files and PDB files. To load those files, please use a special plugin, PDB.DLL, which can be run manually using Edit → Plugins submenu. This plugin uses MS Windows DLLs to load the debug information and therefore has the following limitations:

  • it works only under MS Windows
  • it will load only PDBs compatible with the currently installed IMAGEHLP.DLL

TDS file…

Load a debug information file (TDS). If the program being disassembled has a companion TDS file, this command may be used to load information from the TDS file into the database. The TDS file must be placed in the same directory together with the input file. The LoadTdsFile command launches a special plugin TDS.DLL, which can be run manually using Edit → Plugins submenu.

FLIRT signature file…

Load a FLIRT signature file. This command allows you to apply an additional signature file to the program. A signature file contains patterns of standard runtime functions. With their help, IDA is able to recognize the standard functions and names them accordingly. IDA attempts to detect the necessary signature files automatically but unfortunately, this is not always possible. This command adds the specified signature file into the planned signature files queue. Signature files reside in the subdirectories of the SIG directory. Each processor has its own subdirectory. The name of the subdirectory is equivalent to the name of the processor module file (z80 for z80.w32, for example). Note: IBM PC signatures are located in the SIG directory itself. Note: the IDASGN environment variable can be used to specify the location of the signatures directory.

There is another way to load a signature file: you may insert/delete signature files in the following way:

  • open the signatures window
  • press Ins to insert a signature file to the queue
  • press Del to delete a signature file from the queue

This is a preferred way of applying signatures because useful information, such as the number of identified functions is displayed in the signature window.

{% hint style=“info” %} FLIRT works only for the processors with normal byte size. The byte size must be equal to 8 (processors with wide bytes like AVR or DSP56K are not supported) {% endhint %}

Parse C header file…

This command allows you to apply type declarations from a C header file to the program. IDA reads and parses the specified header file as a C compiler does. In other words, it mimics the front-end of a C compiler with some restrictions:

  • Only type declarations are allowed. The function definitions in the input file are skipped.
  • Not all C++ header files are not supported, only simple classes can be parsed.
  • The compiler specific predefined macros are not defined, you have to define them manually in the header file.

Don’t forget to specify the compiler and memory model in the compiler setup dialog box (Options → Compiler…) before loading a header file. All type declarations found in the input file are stored in the current database in the form of a type library. These type declarations can be used to define new structure and enumeration definitions.

In the case of an error in the input file, the error messages appear in the message window. In any case, the function declarations that are already parsed are not deleted from the database. IDA stops parsing the input file when 20 errors occur. IDA 7.7 introduced an alternative header file parser based on libclang.

Create MAP file…

Create a map information file. Please enter a file name for the map. IDA will write the following information about this file:

  • current segmentation
  • list of names sorted by values

You may disable the generation of the segmentation information. You may also enable or disable dummy names (Options → Name representation…) in the output file. You can use this map file for your information, and also for debugging (for example, Periscope from Periscope Company or Borland’s Turbo Debugger can read this file).

Create ASM file…

Create an assembler file. Please enter a file name for the assembler text file. IDA will write the disassembled text to this file. If you have selected a range on the screen using the Begin selection command (action Anchor), IDA will write only the selected range (from the current address to the anchor). If some I/O problem (e.g., disk full) occurs during writing to the file, IDA will stop and a partial file will be created.

Create INC file…

Create an include file. Please enter a file name for the assembler include file. IDA will write the information about the defined types (structures and enums) to this file. If some I/O problem (e.g. disk full) occurs during writing to the file, IDA will stop and a partial file will be created.

Create LST file…

Create a listing file. Enter a file name for the assembler listing file. IDA will write the disassembled text to this file. If you’ve selected a range on the screen using the Begin selection command (action Anchor), IDA will write only the selected range (from the current address to the anchor). If some I/O problem (e.g. disk full) occurs during writing to the file, IDA will stop and a partial file will be created.

Create EXE file…

Create an executable file. Enter a file name for the new executable file. Usually this command is used after patching (see actions PatchByte, PatchWord) to obtain a patched version of the file. IDA produces executable files only for:

  • MS DOS .exe
  • MS DOS .com
  • MS DOS .drv
  • MS DOS .sys
  • general binary
  • Intel Hex Object Format
  • MOS Technology Hex Object Format

For other file formats please create a difference file (the Create DIFF file command; action ProduceDiff).

{% hint style=“info” %} Only Change byte… and Change word… commands (see actions PatchByte, PatchWord) affect the executable file contents, other commands (including the Manual… command) will not affect the content of the disassembled file. {% endhint %}

EXE files: Output files will have the same EXE-header and relocation table as the input file. IDA will fill unused ranges of the EXE file (e.g. between relocation table and loadable pages) with zeroes.

Create DIF file…

Create a difference file. This command will prompt you for a filename and then will create a plain text difference file of the following format:

 comment
 filename
 offset: oldval  newval 

Create HTML file…

Create a HTML file. Please enter a file name for the HTML file. IDA will write the disassembled text to this file. If you’ve selected a range on the screen using the Begin selection command (action Anchor), IDA will write only the selected range (from the current address to the anchor). If some I/O problem (e.g. disk full) occurs during writing to the file, IDA will stop and a partial file will be created. This command is available only in the graphical version of IDA.

Create flow chart GDL…

Create flow chart GDL. This command creates a GDL (graph description file) with the flow chart of the current function. If there is an active selection, its flow chart will be generated. IDA will ask for the output file name. Regardless of the specified extension, the .GDL extension will be used.

Create call graph GDL…

Create call graph GDL. This command creates a GDL (graph description file) with the graph of the function calls. IDA will ask for the output file name. Regardless of the specified extension, the .GDL extension will be used.

Create C header file…

Creates a header file from local types. This command saves all definitions in the local types window into a C header file.

Dump database to IDC file…

Dump database to IDC file. This command saves current IDA database into a text file.

You can use it as a safety command:

  • to protect your work from disasters
  • to migrate information into new database formats of IDA.

This command is used when you want to switch to a new version of IDA. Usually each new version of IDA has its own database format. To create a new format database, you need:

  1. to issue the ‘Dump…’ command for the old database (using old version of IDA). You will get an IDC file containing all information from your old database.
  2. to reload your database using new IDA with switch -x.
  3. to compile and execute the IDC file with command ‘Execute IDC file’ (usually F2)

Please note that this command does not save everything to text file. Any information about the local variables will be lost!

Dump typeinfo to IDC file…

Dump type information to IDC file. This command saves information about the user-defined types from the IDA database into a text file.

Information about enums, structure types and other user-defined types is saved in a text form as an IDC program.

You can use this command to migrate the type definitions from one database to another.

Take database snapshot…

Take database snapshot. The snapshot can be later restored from the database snapshot manager.

{% hint style=“info” %} Snapshots work only with regular databases. Unpacked databases do not support them. {% endhint %}

Edit

Edit menu actions for IDA View

{% hint style=“info” %} The options below appear when the Edit menu is opened from the IDA View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
CopyEditCopyCopy
Begin selectionAnchorBegin selection. Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor. More…
Select allSelectAllSelect all
Select identifierSelectIdentifierSelect identifier
UndoUndoActionThis command reverts the database to the state before executing the last user action. More…
RedoRedoActionThis command reverts the previously issued Undo command. More…
Export dataExportDataExport data
CodeMakeCodeConvert to instruction. More…
DataMakeDataConvert to data. More…
Struct var…DeclareStructVarDeclare a structure variable. More…
Strings``
StringMakeStrlitConvert to string. More…
C-style (0 terminated)StringCC-style (0 terminated)
DOS style ($ terminated)StringDOSDOS style ($ terminated)
Pascal style (1 byte length)StringPascal1Pascal style (1 byte length)
Wide pascal (2 byte length)StringPascal2Wide pascal (2 byte length)
Delphi (4 byte length)StringDelphiDelphi (4 byte length)
UnicodeStringUnicodeUnicode
Unicode pascal (2 byte length)StringUnicodePascal2Unicode pascal (2 byte length)
Unicode wide pascal (4 byte length)StringUnicodePascal4Unicode wide pascal (4 byte length)
Array…MakeArrayConvert to array. More…
UndefineMakeUnknownConvert to undefined. More…
RenameMakeNameRename the current location. More…
Operand type``
Offset``
Offset (data segment)OpOffsetConvert the current operand to an offset in the data segment. More…
Offset (current segment)OpOffsetCsConvert the current operand to an offset in the current segment. More…
Offset by (any segment)…OpAnyOffsetConvert the current operand to an offset in any segment. More…
Offset (user-defined)…OpUserOffsetConvert the current operand to an offset with any base. More…
Offset (struct)…OpStructOffsetConvert the current operand to a structure offset. More…
Number``
Number (default)OpNumberConvert the current operand to a number. More…
HexadecimalOpHexConvert the current operand to a hexadecimal number. More…
DecimalOpDecimalConvert the current operand to a decimal number. More…
OctalOpOctalConvert the current operand to a octal number. More…
BinaryOpBinaryConvert the current operand to a binary number. More…
Floating pointOpFloatConvert to floating point. More…
Toggle leading zeroesToggleLeadingZeroesToggle leading zeroes. More…
CharacterOpCharConvert the current operand to a character constant
SegmentOpSegmentConvert the current operand to a segment base
Enum member…OpEnumConvert the current operand to a symbolic constant
Stack variableOpStackVariableConvert the current operand to a stack variable
Change signChangeSignChange the sign of the current operand
Bitwise negateBitwiseNegatePerform bitwise negation of the current operand
Manual…ManualOperandEnter the current operand manually. More…
Set operand type…SetOpTypeSet the current operand’s type
Comments``
Copy pseudocode to disassemblyhx:EditCmtEdit func comment
Add pseudocode comments…hx:AddPseudoCmtAdd pseudocode comments
Delete pseudocode comments…hx:DelPseudoCmtDelete pseudocode comments
Enter comment…MakeCommentEnter a regular comment. More…
Enter repeatable comment…MakeRptCmtEnter repeatable comment. More…
Enter anterior lines…MakeExtraLineAEnter lines preceding the generated lines. More…
Enter posterior lines…MakeExtraLineBEnter lines following the generated lines
Edit block comment…mv:EditBlockCmtEdit block comment of microcode line
Edit comment…mv:EditCmtEdit comment of microcode line
Segments``
Create segment…CreateSegmentThis command allows you to create a new segment. More…
Edit segment…EditSegmentEdit segment attributes. More…
Delete segment…KillSegmentDelete segment. More…
Move current segment…MoveSegmentChange the current segment boundaries. More…
Rebase program…RebaseProgramRebase program. More…
Change segment translation…SegmentTranslationChange the current segment translation table
Change segment register value…SetSegmentRegisterChange segment register value. More…
Set default segment register value…SetSegmentRegisterDefaultSet default segment register value. More…
Structs``
Struct var…DeclareStructVarDeclare a structure variable. More…
Force zero offset fieldZeroStructOffsetToggle display of the first field of a structure in an offset expression. More…
Select union member…SelectUnionMemberChoose the representation of a union member. More…
Create struct from selectionCreateStructFromDataThis command defines a new structure from data already defined. The new structure is created with adequate data types, and each member uses the current data name if it is available. More…
Copy field info to pointersCopyFieldsToPointersCopy field info to pointed addresses. This command scans the current struct variable and renames the locations pointed by offset expressions unless they already have a non-dummy name. More…
Functions``
Create function…MakeFunctionCreate a new function in the disassembly. More…
Edit function…EditFunctionEdit function attributes - change function properties, including bounds, name, flags, and stack frame parameters. More…
Append function tail…AppendFunctionTailThis command appends an arbitrary range of the program to a function definition. A range must be selected before applying this command. This range must not intersect with other function chunks (however, an existing tail can be added to multiple functions). More…
Remove function tail…RemoveFunctionTailRemove function tail. More…
Delete functionDelFunctionDelete function. Deleting a function deletes only information about a function, such as information about stack variables, comments, function type, etc. The instructions composing the function will remain intact.
Set function endFunctionEndChange the function end address. This command changes the current or previous function bounds so that its end will be set at the cursor. If it is not possible, IDA beeps.
Stack variables…OpenStackVariablesOpen the stack variables window. See subviews for more.
Change stack pointer…ChangeStackPointerChange stack pointer. This command allows you to specify how the stack pointer (SP) is modified by the current instruction. More…
Rename register…RenameRegisterRename a general processor register. More…
Set type…SetTypeSet type information for an item or current function. More…
Patch program``
Change byte…PatchByteChange program bytes. More…
Change word…PatchWordChange program words
Assemble…AssembleThis command allows you to assemble instructions. Currently, only the IBM PC processors provide an assembler, nonetheless, plugin writers can extend or totally replace the built-in assembler by writing their own. More…
Patched bytesPatchedBytesOpen the Patched bytes window. More…
Apply patches to input file…ApplyPatchesApply previously patched bytes back to the input file. If the “Restore” option is selected, then the original bytes will be applied to the input file. More…
Other``
Specify switch idiom…uiswitch:SpecSwitchIdiomSpecify switch idiom
Create alignment directive…MakeAlignmentCreate alignment directive. More…
Manual instruction…ManualInstructionSpecify alternate representation of the current instruction. More…
Color instruction…ColorInstructionThis command allows you to specify the background color for the current instruction or data item. More…
Reset decompiler information…hx:ResTypeInfoReset decompiler information
Toggle skippable instructions…hx:ToggleSkippableInsnToggle skippable instructions
Decompile as call…hx:UserDefinedCallDecompile as call
Toggle borderToggleBorderToggle the display of a border between code and data. More…
detect and parse golang metadatagolang:detect_and_parsedetect and parse golang metadata
Open picture in default viewerpicture_search:open_in_viewerOpen picture in default viewer
Save picturepicture_search:save_pictureSave picture
Plugins``
Quick run pluginsQuickRunPluginsQuickly run a plugin

Begin selection

Begin selection. Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor.

To drop the anchor, you can either use the Alt + L key or the Shift + , , , combination, which is more convenient. You can also drop the anchor with the mouse by simply clicking and dragging it.

After you’ve dropped the anchor, you can navigate freely using arrows, etc. Any command that uses the anchor, raises it.

The anchored range is displayed with another color.

When you exit from IDA, the anchor value is lost.

Undo

This command reverts the database to the state before executing the last user action. It is possible to apply Undo multiple times, in this case multiple user actions will be reverted.

Please note the entire database is reverted, including all modifications that were made to the database after executing the user action and including the ones that are not connected to the user action. For example, if a third party plugin modified the database during or after the user action, this modification will be reverted. In theory it is possible to go back in time to the very beginning and revert the database to the state that was present immediately after performing the very first user action. However, in practice the undo buffers overflow because of the changes made by autoanalysis.

Autoanalysis (Options → General… → Analysis) generates copious amounts of undo data. Also, please note that maintaining undo data during autoanalysis slows it down a bit. In practice, it is not a big deal because the limit on the undo data is reached quite quickly (in a matter of minutes). Therefore, if during analysis the user does not perform any actions that modify the database, the undo feature will turn itself off temporarily.

However, if you prefer not to collect undo data at all during the initial autoanalysis, just turn off the UNDO_DURING_AA parameter in ida.cfg.

The configuration file ida.cfg has 2 more undo-related parameters:

ParameterDescriptionDefault
UNDO_MAXSIZEMax size of undo buffers. Once this limit is reached, the undo info about the oldest user action will be forgotten.128MB
UNDO_DEPTHMax number of user actions to remember. If set to 0, the undo feature will be unavailable.1000000

Since there is a limit on the size of undo buffers, any action, even the tiniest, may become non-undoable after some time. This is true because the analysis or plugins may continue to modify the database and overflow the buffers. Some massive actions, like deleting a segment, may be non-undoable just because of the sheer amount of undo data they generate.

Please note that Undo does not affect the state of IDC or Python scripts. Script variables will not change their values because of Undo. Also nothing external to the database can be changed: created files will not be deleted, etc.

Some actions cannot be undone. For example, launching a debugger or resuming from a breakpoint cannot be undone.

Redo

This command reverts the previously issued Undo command. It is possible to use Redo multiple times.

This command also reverts all changes that were done to the database after the last Undo command, including the eventual useful modifications made by the autoanalysis. In other words, the entire database is modified to get to the exact state that it had before executing the last Undo command.

Code

Convert to instruction. This command converts the current unexplored bytes to instruction(s). IDA will warn you if it is not possible.

If you have selected a range using the Anchor action, all the bytes from this range will be converted to instructions.

If you apply this command to an instruction, it will be reanalyzed.

Data

Convert to data. This command converts the current unexplored bytes to data. If it is not possible, IDA will warn you.

Multiple using of this command will change the data type:

 db -> dw -> dd -> float -> dq -> double -> dt -> packreal -> octa \;
 ^                                                                 |;
 \---------<----------------<--------------<-----------------------/;

You may remove some items from this list using the Setup data types… command (action SetupData).

If the target assembler (Options → General… → Analysis) does not support double words or another data type, it will be skipped. To create a structure variable, use the Struct var… command (action DeclareStructVar). To create an array, use the Array… command (action MakeArray). To convert back, use the Undefine command (action MakeUnknown).

Struct var…

Declare a structure variable. IDA will ask you to choose a structure type. You must have some structure types defined in order to use this command. If the target assembler supports it, IDA will display the structure in terse form (using just one line). To uncollapse a terse structure variable use the Unhide command. You can also use this command to declare a structure field in another structure (i.e., nested structures are supported too).

String

Convert to string. This command converts the current unexplored bytes to a string. The set of allowed characters is specified in the configuration file, parameter StrlitChars. Character ‘\0’ is not allowed in any case. If the current assembler (Options → General → Analysis → Target assembler) does not allow characters above 0x7F, characters with high bit set are not allowed. If the anchor has been dropped, IDA will take for the string all characters between the current cursor position and the anchor. Use the anchor if the string starts a disallowed character.

This command also generates a name for the string. In the configuration file, you can specify the characters allowed in names (NameChars). You can change the literal string length using Array… command (action MakeArray). The GUI version allows you to assign a special hotkey to create Unicode strings. To do so, change the value of the StringUnicode parameter in the IDAGUI.CFG file.

Array…

Convert to array. This command allows you to create arrays and change their sizes.

The arrays are created in 2 simple steps:

  1. Create the first element of array using the data definition commands (data, string, structs)

  2. Apply the array command to the created data item. Enter array size in current array elements (not bytes). The suggested array size is the minimum of the following values:

  • the address of the next item with a cross reference
  • the address of the next user-defined name For string literals, you can use this command to change the length of the string.

The dialog box contains the following fields:

  • Items on a line (meaningless for string literals):

    • 0 - place maximal number of items on a line
    • other value - number of items on a line Please note that the margin parameter affects the number of items on a line too.
  • Alignment (meaningless for string literals):

    • -1 - do not align items
    • 0 - align automatically
    • other value - width of each item
  • Signed elements: if checked, IDA treats all elements as signed numbers. Only meaningful for numbers (not for offsets and segments and strings)

  • Display indexes: if checked, IDA will display the indexes of array elements in the form of comments (0,1,2…)

  • Create as array: if not checked, IDA will create a separate item for each array element. Useful for creating huge arrays. If the box is unchecked when this command is applied to string literals, IDA will create many string literals instead of one big string.

If applied to a variable-sized structure, this command is used to specify the overall size of the structure. You cannot create arrays of variable-sized structures.

Undefine

Convert to undefined. This command deletes the current instruction or data, converting it to ‘unexplored’ bytes. IDA will delete the subsequent instructions if there are no more references to them (functions are never deleted).

If you have selected a range using the Anchor action, all the bytes in this range will be converted into ‘unexplored’ bytes. In this case, IDA will not delete any other instructions even if there are no references to them after the deletion.

Rename

Rename the current location. This command gives name/renames/deletes name for the current item.

To delete a name, simply give an empty name.

If the current item is referenced, you cannot delete its name. Even if you try, IDA will generate a dummy name (See Options → Name representation…).

List of available options:

  • Local name: The name is considered to be defined only in the current function. Please note that IDA does not check the uniqueness of the local names in the whole program. However, it does verify that the name is unique for the function.

  • Include in name list: Here you can also include/remove the name from the name list (see the Jump by name… command; action JumpName). If the name is hidden, you will not see it in the names window.

  • Public name: You can declare a name as a public (global) name. If the current assembler supports the “public” directive, IDA will use it. Otherwise, the publicness of the name will be displayed as a comment.

  • Autogenerated name: An autogenerated name will appear in a different color. If the item is indefined, it will disappear automatically.

  • Weak name: You can declare a name as a weak name. If the current assembler supports the “weak” directive, IDA will use it. Otherwise, the weakness of the name will be displayed as a comment.

  • Create name anyway: If this flag is on, and if the specified name already exists, IDA will try to variate the specified name by appending a suffix to it.

Offset (data segment)

Convert the current operand to an offset in the data segment. This command converts the immediate operand of the current instruction/data to an offset from the current data segment (DS). If the current DS value is unknown (or equal 0xFFFF) IDA will warn you - it will beep. In this case, you have to define DS register value for the current byte. The best way to do it is:

  • jump to segment register change point (the Jump to segment register… command; action JumpSegmentRegister),
  • change value of DS (the Change segment register value… command; action SetSegmentRegister)
  • return (the Jump back command; action Return) or you can change default value of DS for the current segment (the Set default segment register value… command; action SetSegmentRegisterDefault).

If you want to delete offset definition, you can use this command again - it works as trigger. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset (current segment)

Convert the current operand to an offset in the current segment. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise, it will be left unmodified. If this command is applied to a structure member in the Local types window, then IDA will create an “automatic offset”. An automatic offset is an offset with the base equal to 0xFFFFFFFF. This base value means that the actual value of the base will be calculated by IDA when a structure instance is created. To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset by (any segment)…

Convert the current operand to an offset in any segment. This command converts the immediate operand of the current instruction/data to an offset from any segment. IDA will ask to choose a base segment for the offset. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. To create offsets to structure members use Offset (struct)… command (action OpStructOffset).

Offset (user-defined)…

Convert the current operand to an offset with any base. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If the offset base is specified as 0xFFFFFFFF, then IDA will create “an automatic offset”. Automatic offsets mean that the actual value of the base will be calculated by IDA.

The following offset attributes are available:

OptionDescription
Treat the base address as a plain numberif checked, IDA will treat the base address as a number. In this case, IDA will not create a cross-reference to it and the base address will be printed as a number, not as an offset expression.
Offset points past the main objectOffsets of this type point past an object end. They do not cause an object created/deletion.
Use image base as offset baseThese offsets are based on the image base. There is no need to explicitly specify the offset base. These offsets are displayed in a concise form: rva func instead of offset func - imagebase. If you intend to reassemble the output file, execute the following IDC statement: set_inf_attr(INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) & ~INFFL_ALLASM);
Subtract operand valueUse this option when the operand value should be substracted from the base to get the target address. In this case the displayed expression will be displayed as offset base - target instead of the usual offset target - base
Signed operandUse this option if the operand should be interpreted as a signed value. This option is only available for OFF_REF8, OFF_REF16, OFF_REF32 and OFF_REF64 offset types.
Operand value of 0 is invalidIf the operand value is 0, the value will be highlighted in red.
Operand value of NOT 0 is invalidIf the operand value is zero’s complement (i.e. all bits are set), the value will be highlighted in red. For example a OFF_REF16 with an operand value of 0xFFFF would be invalid.
Use the current address as the offset baseThe offset base is dynamically calculated and is equal to the address of the current element: - for standalone items: their start address - for arrays: the start of the array element - for structures: the start of the structure field

The offset expression is displayed in the following concise form: offset target - $ where “$” denotes the start of the element (and is assembler-dependent).

To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset (struct)…

Convert the current operand to a structure offset. This command permits to convert all immediate operands of instructions in a range selection to a path of offsets through a structure and its possible sub unions. If no selection is active, IDA will simply permit to convert the current operand. In this case, it will display a simple dialog box the same way as the text version (see below). You can select the desired register in the drop-down list: all operands relative to this register will be added to the ‘Offsets’ list. A special empty line in the drop-down list is used to directly work on immediate values. Checkboxes in the ‘Offsets’ list allow you to select which operand you indeed want to modify. By default, IDA will select only undefined operands, to avoid overwriting previous type definitions. This list is sorted by operand value, by instruction address and finally by operand number. You can easily see the instructions related to the operand by moving the mouse over it, and wait for a hint to be displayed. The ‘Structures and Unions’ tree will contain all selectable structures, and sub unions. Once you select or move over a structure, the ‘Offsets’ list updates itself for each checked offset: the computed name of the operand is displayed, according to the selected structure in the tree. An icon is also drawn, to easily know if a specific structure matches the offset or not, or if the offset is too big for the selected structure. The structures who match the most offsets will be near the top of the tree. You can also move your mouse over structures in the tree to obtain an interesting hint. A ‘?’ icon can also appear, if the offset can be specialized by selecting an union member. In this case, if you expand the structure in the tree, you can select the adequate union member simply by checking the desired radio button. IDA automatically corrects the related name in the ‘Offsets’ list. The ‘Offset delta’ value represents the difference between the structure start and the pointer value. For example, if you have an operand 4 and want to convert in into an expression like “mystruct.field_6-2”, then you have to enter 2 as the delta. Usually the delta is zero, i.e. the pointer points to the start of the structure. The ‘Hide sub structures without sub unions’ option (checked by default) avoids to add unnecessary sub structures to the tree, to keep it as small as possible. If you uncheck this option, all sub structures will be added to the tree. By default, IDA displays the structure member at offset 0. To change this behavior, you can directly disable the ‘Force zero offset field’ in the ‘Options’ frame. Later zero offsets can be forced using Edit → Structs → Force zero offset menu item.

Text version

This command converts immediate operand(s) type of the current instruction/data to an offset within the specified structure. Before using this command, you have to define a structure type. First of all, IDA will ask a so-called “struct offset delta”. This value represents the difference between the structure start and the pointer value. For example, if you have an operand 4 and want to convert in into an expression like “mystruct.field_6-2”, then you have to enter 2 as the delta. Usually the delta is zero, i.e. the pointer points to the start of the structure. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the an operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. When you use this command, IDA deletes the manually entered operand. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. By default IDA doesn’t display the structure member at offset 0. To change this behavior, use the Force zero offset field command. Moreover, if there are several possible representations (this can happen if unions are used), select the desired representation using the Select union member… command.

Number (default)

Convert the current operand to a number. That way, you can delete suspicious mark of the item. The number is represented in the default radix for the current processor (usually hex, but octal for PDP-11, for example). When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Hexadecimal

Convert the current operand to a hexadecimal number. This command converts the immediate operand(s) type of the current instruction/data to a hex number, so that you can delete the suspicious mark of the item. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Decimal

Convert the current operand to a decimal number. This command converts the immediate operand(s) type of the current instruction/data to decimal. Therefore, it becomes a ‘number’. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Octal

Convert the current operand to a octal number. IDA always uses 123o notation for octal numbers even if the current assembler does not support octal numbers. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Binary

Convert the current operand to a binary number. This command makes the current instruction or data operand type binary. IDA always uses 123b notation for binary numbers even if the current assembler does not support binary numbers. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Floating point

Convert to floating point. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Toggle leading zeroes

Toggle leading zeroes.

This command displays or hides the leading zeroes of the current operand. Example: if the instruction looked like this:

    and     ecx, 40h

then after applying the command it will look like this:

    and     ecx, 00000040h

If you prefer to see leading zeroes in all cases, then open the calculator and enter the following expression: set_inf_attr (INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) | INFFL_LZERO); This will toggle the default for the current database and all numbers without leading zeroes will become numbers with leading zeroes, and vice versa. See also Edit|Operand types submenu.

Manual…

Enter the current operand manually. You may specify any string instead of an operand if IDA does not represent the operand in the desired form. In this case, IDA will simply display the specified string in the instruction instead of the default operand.

The current operand (under the cursor) will be affected.

You can use this command not only with instructions but with data items too.

IDA proposes the previous manual operand as the default value in the input form.

To delete the manual operand and revert back to the default text, specify an empty string.

IDA automatically deletes manually entered operands when you change operand representation using Edit → Operand types submenu.

{% hint style=“info” %} A text offset reference is generated if you use a label in the program as the operand string. In other cases no cross-references are generated. {% endhint %}

Enter comment…

Enter a regular comment. If you stand at the function start and your cursor is on a function name, IDA will ask you to enter a function comment. If you stand at the segment start and your cursor is on a segment name, IDA will ask you to enter a segment comment. If this command is issued in the Local types window, it allows you to change the comment of a structure/enum, or structure/enum member. If the cursor is on the structure/enum name, the structure/enum comment will be changed, otherwise the member comment will be changed. Otherwise, this command allows you to enter a normal indented comment for the current item. You can show/hide all comments in Options → General → Disassembly → Display disassembly line parts: Comments.

Enter repeatable comment…

Enter repeatable comment. A repeatable comment will appear attached to the current item and all other items referencing it. If you stand at the function start, IDA will ask you to enter a function comment. If this command is issued in the Local types window, it allows you to change the comment of a structure/enum, or structure/enum member. If the cursor is on the structure/enum name, the structure/enum comment will be changed, otherwise the member comment will be changed. Otherwise, this command allows you to enter a repeatable comment for the current item.

{% hint style=“info” %} You cannot enter repeatable segment comments. {% endhint %}

All items that refer to the current item will have this comment by default. Note that if you have defined both comment types (regular and repeatable), the regular comment will be displayed for the current item and the repeatable comment will be displayed for all items that refer to the current item, if they do not have their own comments. The repeatable comments may be used to describe subroutines, data items, etc., because all calls to the subroutine will have the repeatable comment. You can show/hide all comments in Options → General → Disassembly → Display disassembly line parts: Comments.

Enter anterior lines…

Enter lines preceding the generated lines. If you want to enter multi-line comments or additional instructions, you can use this feature of IDA.

There are two kinds of extra lines: the ones generated before the instruction line and the ones generated after the instruction line.

Do not forget that the maximal number of lines for an item is 500.

IDA does not insert a comment symbol at the beginning of the lines.

Create segment…

This command allows you to create a new segment.

If you select a range using the anchor, IDA will propose the start address and the end address of the selection as defaults for the segment bounds.

You need to specify at least:

  • the segment start address
  • the segment end address (excluded from the range)
  • the segment base

Click here to learn about addressing model used in IDA.

If “sparse storage” is set, IDA will use special sparse storage method for the segment. This method is recommended for huge segments. Later, it is possible to change the storage method of any region using set_storage_type IDC function.

If another segment already exists at the specified address, the existing segment is truncated and the new segment lasts from the specified start address to the next segment (or specified end address, whichever is lower). If the old and the new segments have the same base address, instructions/data will not be discarded by IDA. Otherwise, IDA will discard all instructions/data of the new segment.

An additional segment may be created by IDA to cover the range after the end of the new segment.

Edit segment…

Edit segment attributes. This command opens the Change segment attributes dialog.

Change segment attributes dialog

Change segment attributes options

{% hint style=“info” %} Changing the segment class may change the segment type. {% endhint %}

  • Move Adjacent Segments: means that the previous and next segments will be shrunk or expanded to fill gaps between segments. Click here for more information.

  • Disable Addresses: if set, when a segment is shrunk, all information about bytes going out of the segment will be completely removed.. Otherwise, IDA will discard information about instructions/data, comments etc, but will retain byte values so that another segment can be created later and it will use the existing byte values.

If IDA creates 2 segments where only one segment must exist, you may try the following sequence:

  • Delete one segment (action KillSegment). Choose one with bad segment base value. Do not disable addresses occupied by the segment being deleted.
  • Change bounds of another segment. Note that the Create segment… command (action CreateSegment) changes the boundaries of the overlapping segment automatically.

Segments with the “debugger” attribute are the segments whose memory contents are not saved in the database. Usually, these segments are created by the debugger to reflect the current memory state of the program.

However, the user can modify this attribute.

If it is cleared, then the segment will permanently stay in the database after closing the debugger session. The database will reflect the state of the segment which was at the time when the status is changed.

If it is set, then the segment will become a temporary segment and will be deleted at the end of the debugging session.

The debugger segment checbkox is available only during debugging sessions.

The “loader” segments are the segment created by the file loader. The segment having this attribute are considered to be part of the input file.

A segment with the “debugger” attribute set and the “loader” attribute not set is considered to be an ephemeral segment. Such segments are not analyzed automatically by IDA.

“Segment permissions” group box can be used to modify Segment access permissions (Read/Write/Execute)

Segment Name

Enter a new name for the segment. A segment name is up to 8 characters long. IDA does check if the length is ok. Try to give mnemonic names for the segments.

Class Name

The segment class name identifies the segment with a class name (such as CODE, FAR_DATA, or STACK). The linker places segments with the same class name into a contiguous range of memory in the runtime memory map.

Changing the segment class changes only the segment definition on the screen. There are the following predefined segment class names:

Segment classDescription
CODEPure code
DATAPure data
CONSTPure data
BSSUninitialized data
STACKUninitialized data
XTRNExtern definitions segment

If you change segment class and the segment type is “Regular”, then the segment type will be changed accordingly.

In order to set the segment type “Regular”, you should change the segment class to “UNK”.

{% hint style=“info” %} Segment class names are never deleted. Once you define a segment class name, you cannot reuse it as a name of another object. {% endhint %}

Segment bitness

You can choose between 16-bit and 32-bit segment addressing.

IDA will delete all instructions and data in the segment if the segment address is changed.

Never do it if you are not sure. It may have irreversible consequences, all instructions/data will be converted to undefined bytes.

Segment Alignment

You can specify the segment alignment for the selected segment. By default, IDA assumes ‘byte’ alignment.

Changing the alignment changes only the segment definition on the screen. Nothing else will happen.

Segment Combination

A field that describes how the linker can combine the segment with other segments. Under MS-DOS, segments with the same name and class can be combined in two ways: they can be concatenated to form one logical segment, or they can be overlapped. In the latter case, they have either the same start address or the same end address, and they describe a common range in memory. Values for the field are:

  • Private: Do not combine with any other program segment.
  • Public: Combine by appending at an offset that meets the alignment requirement.
  • Stack: Combine as for Public. This combine type forces byte alignment.
  • Common: Combine by overlay using maximum size.

Changing segment combination changes only the segment definition on the screen. Nothing else will happen.

Delete segment…

Delete segment. IDA will ask your the permission to disable the addresses occupied by the segment. If you allow this operation, all information about the segment will be deleted. In other words, IDA will discard the information about instructions or data, comments etc.

If you check the “disable addresses” checkbox, IDA will mark the addresses occupied by the segment as “nonexistent” in the program. You will lose ALL information, including byte values.

It is impossible to disassemble the content of addresses not located in any segment, therefore you must create a new segment if you want to resume the disassembly of that part of the code.

You can also edit an adjacent segment to expand it to those addresses (Edit → Segments → Edit segment…).

IDA will ask your the permission to disable addresses occupied by the segment. If you give your permission, information about the segment will be deleted, otherwise IDA will discard information about instruction/data, comments etc, but retain byte values so that you will be able to create another segment afterwards. To disassemble the addresses occupied by the segment, you need to create a new segment again (i.e. you cannot disassemble bytes without a segment). You can also expand another adjacent segment to these addresses.

Move current segment…

Change the current segment boundaries. This command open the Move segment dialog and allows you to move segment(s) to another address. Use it if the segment(s) are loaded at a wrong address. This command shifts (moves) the selected segments in the memory to the target address. There must be enough free space at the target address for the segments. All information in the segment will be moved to the new address, but since the addresses change, the disassembly might be not valid anymore (especially if the program is moved to the wrong addresses and the relocation information is not available).

Fix up the relocated segment

This option allows IDA to modify the references to/from the relocated segment(s). If it is turned off, the references might be wrong after the move.

Rebase program…

Rebase program. The whole program will be shifted by the specified amount of bytes in the memory. The following options are available (we strongly recommend to leave them turned on):

  • Fix up relocations: This option allows IDA to modify the references to/from the relocated segment(s). If it is turned off, the references might be wrong after the move.
  • Rebase the whole image: This option is accessible only if the whole program is selected. It allows IDA to adjust internal variables on the whole program.

Please note rebasing the program might remove user-defined xrefs.

Change segment register value…

Change segment register value. Relevant only for processors with the segment registers. Currently this command works for IBM PC, TMS320C2, Intel80196, and PowerPC processors. This command creates or updates a segment register change point. See also the Jump to segment register… command (action JumpSegmentRegister) for more info.

Set default segment register value…

Set default segment register value. Relevant only for processors with the segment registers. You can specify a default value of a segment register for the current segment. When you change the default value, IDA will reanalyze the segment, taking the default value when it cannot determine the actual value of the register. This takes time, so do not be surprised if references are not corrected immediately.

To specify a value other than the default value of a segment register, you can use the Change segment register value… command (action SetSegmentRegister).

Struct var…

Declare a structure variable. IDA will ask you to choose a structure type. You must have some structure types defined in order to use this command. If the target assembler supports it, IDA will display the structure in terse form (using just one line). To uncollapse a terse structure variable use the Unhide command. You can also use this command to declare a structure field in another structure (i.e., nested structures are supported too).

Force zero offset field

Toggle display of the first field of a structure in an offset expression. This command forces IDA to display a full structure member name even if the offset of the member is equal to zero.

If used twice, the command cancels itself.

Example: Suppose we have the following structure:

    xxx     struc
    a       db ?
    b       db ?
    c       db ?
    xxx     ends

    dloc    xxx ?

Normally IDA displays references to it like this:

    mov     eax, offset dloc
    mov     eax, offset dloc.b

If you force IDA, then it displays member ‘a’:

    mov     eax, offset dloc.a
    mov     eax, offset dloc.b

Select union member…

Choose the representation of a union member. This command tells IDA how to display references to a union from the current cursor location.

Example: Suppose we have the following union:

        xxx     union
        a       db ?
        b       dw ?
        c       dd ?
        ends   xxx
        dloc    xxx ?

Normally, IDA displays references to “dloc” like this:

        mov     al,  byte ptr dloc
        mov     eax, word ptr dloc

After using this command, IDA can display the union members:

        mov     al,  dloc.b
        mov     eax, dloc.d 

Create struct from selection

This command defines a new structure from data already defined. The new structure is created with adequate data types, and each member uses the current data name if it is available.

This command is available only in the graphical version of IDA.

Copy field info to pointers

Copy field info to pointed addresses. This command scans the current struct variable and renames the locations pointed by offset expressions unless they already have a non-dummy name.

It also copies the type info from the struct members to pointed locations.

Create function…

Create a new function in the disassembly. You can specify function boundaries using the anchor. If you don’t specify any, IDA will try to find the boundaries automatically:

  • function start point is equal to the current cursor position;
  • function end point is calculated by IDA.

A function cannot contain references to undefined instructions. If a function has already been defined at the specified addresses, IDA will jump to its start address, showing you a warning message. A function must start with an instruction.

Edit function…

Edit function attributes - change function properties, including bounds, name, flags, and stack frame parameters. This command opens an Edit Function dialog, and allows you to modify function characteristics and stack frame structure. If the current address does not belong to any function, IDA will beep.

Edit function dialog

To change only the function end address, use the FunctionEnd command instead. This command allows you to change the function frame parameters too. You can change sizes of some parts of frame structure.

Stack Frame Structure

IDA represents the stack using the following structure:

Stack SectionPointer
function arguments-
return address-
saved registers (SI, DI, etc)← BP
local variables← SP

{% hint style=“info” %} For some processors or functions, BP may equal SP, meaning it points to the bottom of the stack frame. {% endhint %}

You may specify the number of bytes in each part of the stack frame. The size of the return address is calculated by IDA (possibly depending on the far function flag).

           push    ebp
           lea     ebp, [esp-78h]
           sub     esp, 588h
           push    ebx
           push    esi
           lea     eax, [ebp+74h]

      +------------------------------+
      | function arguments           |
      +------------------------------+
      | return address               |
      +------------------------------+
      | saved registers (SI,DI,etc)  |
      +------------------------------+  <- typical BP
      |                              |
      |                              |
      |                              |  <- actual BP
      | local variables              |
      |                              |
      |                              |
      |                              |
      +------------------------------+  <- SP

In our example, the saved registers area is empty (since EBP has been initialized before saving EBX and ESI). The difference between the ‘typical BP’ and ‘actual BP’ is 0x78 and this is the value of FPD.

After specifying FPD=0x78 the last instruction of the example becomes

           lea     eax, [ebp+78h+var_4]

where var_4 = -4

Most of the time, IDA calculates the FPD value automatically. If it fails, the user can specify the value manually.

If the value of the stack pointer is modified in an unpredictable way, (e.g. “and esp, -16”), then IDA marks the function as “fuzzy-sp”.

If this command is invoked for an imported function, then a simplified dialog box will appear on the screen.

See also:

Configurable Parameters

  • Stack Frame Sizes: You can specify the number of bytes in each part of the stack frame. The return address size is calculated automatically by IDA (may depend on the far function flag).
  • Purged Bytes: Specifies the number of bytes added to SP upon function return. This value calculates SP changes at call sites (used in calling conventions such as __stdcall in Windows 32-bit programs).
  • BP Based Frame: Enables IDA to automatically convert [BP+xxx] operands to stack variables.
  • BP Equal to SP: Indicates that the frame pointer points to the bottom of the stack. Commonly used for processors that set up the stack frame with EBP and ESP both pointing to the bottom (e.g., MC6816, M32R).
  • Reanalysis: Pressing Enter without changing any parameter will cause IDA to reanalyze the function.

Append function tail…

This command appends an arbitrary range of the program to a function definition. A range must be selected before applying this command. This range must not intersect with other function chunks (however, an existing tail can be added to multiple functions).

IDA will ask to select the parent function for the selection and will append the range to the function definition.

Remove function tail…

Remove function tail. This command removes the function tail at the cursor from a function definition. If there are several parent functions for the current function tail range, IDA will ask to select the parent function(s) to remove the tail from. After the confirmation, the current function tail range will be removed from the selected function definition. If the parent was the only owner of the current tail, then the tail will be destroyed. Otherwise it will still be present in the database. If the removed parent was the owner of the tail, then another function will be selected as the owner.

Change stack pointer…

Change stack pointer. This command allows you to specify how the stack pointer (SP) is modified by the current instruction.

You cannot use this command if the current instruction does not belong to any function.

You will need to use this command only if IDA was not able to trace the value of the SP register. Usually IDA can handle it but in some special cases it fails. An example of such a situation is an indirect call of a function that purges its parameters from the stack. In this case, IDA has no information about the function and cannot properly trace the value of SP.

Please note that you need to specify the difference between the old and new values of SP.

The value of SP is used if the current function accesses local variables by [ESP+xxx] notation.

See also how to convert to stack variable (Action OpStackVariable).

Rename register…

Rename a general processor register. This command allows you to rename a processor general register to some meaningful name. While this is not used very often on IBM PCs, it is especially useful on RISC processors with lots of registers. For example, a general register R9 is not very meaningful and a name like ‘CurrentTime’ is much better.

This command can be used to define a new register name as well as to remove it. Just move the cursor on the register name and press enter. If you enter the new register name as an empty string, then the definition will be deleted.

If you have selected a range before using this command, then the definition will be restricted to the selected range. But in any case, the definition cannot cross the function boundaries.

You cannot use this command if the current instruction does not belong to any function.

Set type…

Set type information for an item or current function. This command allows you to specify the type of the current item. If the cursor is located on a name, the type of the named item will be edited. Otherwise, the current function type (if there is a function) or the current item type (if it has a name) will be edited.

The function type must be entered as a C declaration. Hidden arguments (like ‘this’ pointer in C++) should be specified explicitly. IDA will use the type information to comment the disassembly with the information about function arguments. It can also be used by the Hex-Rays decompiler plugin for better decompilation. Here is an example of a function declaration:

    int main(int argc, const char *argv[]);

It is also possible to specify a function name coming from a type library. For example, if entering “LoadLibraryW” would yield its prototype:

    HMODULE __stdcall LoadLibraryW(LPCWSTR lpLibFileName);

provided that the corresponding type library is in memory. To delete a type declaration, just enter an empty string. IDA supports the user-defined calling convention. In this calling convention, the user can explicitly specify the locations of arguments and the return value. For example:

    int __usercall func@<ebx>(int x, int y@<esi>);

denotes a function with 2 arguments: the first argument is passed on the stack (IDA automatically calculates its offset) and the second argument is passed in the ESI register and the return value is stored in the EBX register. Stack locations can be specified explicitly:

    int __usercall runtime_memhash@<^12.4>(void *p@<^0.4>, int q@<^4.4>, int r@<^8.4>)

There is a restriction for a __usercall function type: all stack locations should be specified explicitly or all are automatically calculated by IDA. General rules for the user defined prototypes are:

  • the return value must be in a register. Exception: stack locations are accepted for the __golang and __usercall calling conventions.

  • if the return type is ‘void’, the return location must not be specified

  • if the argument location is not specified, it is assumed to be on the stack; consequent stack locations are allocated for such arguments

  • it is allowed to declare nested declarations, for example: int **__usercall func16@(int *(__usercall *x)@ (int, long@, int)@);

    Here the pointer “x” is passed in the ESI register; The pointed function is a usercall function and expects its second argument in the ECX register, its return value is in the EBX register. The rule of thumb to apply in such complex cases is to specify the the registers just before the opening brace for the parameter list.

  • registers used for the location names must be valid for the current processor; some registers are unsupported (if the register name is generated on the fly, it is unsupported; inform us about such cases; we might improve the processor module if it is easy)

  • register pairs can be specified with a colon like edx:eax

  • for really complicated cases this syntax can be used. IDA also understands the “__userpurge” calling convention. It is the same thing as __usercall, the only difference is that the callee cleans the stack.

The name used in the declaration is ignored by IDA. If the default calling convention is __golang then explicit specification of stack offsets is permitted. For example:

  __attribute__((format(printf,2,3)))
  int myprnt(int id, const char *format, ...);

This declaration means that myprnt is a print-like function; the format string is the second argument and the variadic argument list starts at the third argument.

Below is the full list of attributes that can be handled by IDA.

AttributeDescription
packedpack structure/union fields tightly, without gaps
alignedspecify the alignment
noreturndeclare as not returning function
ms_structuse microsoft layout for the structure/union
formatpossible formats: printf, scanf, strftime, strfmon

Data Declaration Keywords

For data declarations, the following custom __attribute((annotate(X))) keywords have been added. The control the representation of numbers in the output:

KeywordDescription
__binunsigned binary number
__octunsigned octal number
__hexunsigned hexadecimal number
__decsigned decimal number
__sbinsigned binary number
__soctsigned octal number
__shexsigned hexadecimal number
__udecunsigned decimal number
__floatfloating point
__charcharacter
__segmsegment name
__enum()enumeration member (symbolic constant)
__offoffset expression (a simpler version of __offset)
__offset()offset expression
__strlit()string
__stroff()structure offset
__custom()custom data type and format
__invsigninverted sign
__invbitsinverted bitwise
__lzeroadd leading zeroes
__tabform()tabular form

Type Declaration Keywords

The following additional keywords can be used in type declarations:

KeywordDescription
_BOOL1a boolean type with explicit size specification (1 byte)
_BOOL2a boolean type with explicit size specification (2 bytes)
_BOOL4a boolean type with explicit size specification (4 bytes)
__int8a integer with explicit size specification (1 byte)
__int16a integer with explicit size specification (2 bytes)
__int32a integer with explicit size specification (4 bytes)
__int64a integer with explicit size specification (8 bytes)
__int128a integer with explicit size specification (16 bytes)
_BYTEan unknown type; the only known info is its size: 1 byte
_WORDan unknown type; the only known info is its size: 2 bytes
_DWORDan unknown type; the only known info is its size: 4 bytes
_QWORDan unknown type; the only known info is its size: 8 bytes
_OWORDan unknown type; the only known info is its size: 16 bytes
_TBYTE10-byte floating point value
_UNKNOWNno info is available
__purepure function: always returns the same value and does not modify memory in a visible way
__noreturnfunction does not return
__usercalluser-defined calling convention; see above
__userpurgeuser-defined calling convention; see above
__golanggolang calling convention
__swiftcallswift calling convention
__spoilsexplicit spoiled-reg specification; see above
__hiddenhidden function argument; this argument was hidden in the source code (e.g. ‘this’ argument in c++ methods is hidden)
__return_ptrpointer to return value; implies hidden
__struct_ptrwas initially a structure value
__array_ptrwas initially an array
__unusedunused function argument
__cppobja c++ style struct; the struct layout depends on this keyword
__ptr32explicit pointer size specification (32 bits)
__ptr64explicit pointer size specification (64 bits)
__shiftedshifted pointer declaration
__highhigh level prototype (does not explicitly specify hidden arguments like ‘this’, for example) this keyword may not be specified by the user but IDA may use it to describe high level prototypes
__bitmaska bitmask enum, a collection of bit groups
__tuplea tuple, a special kind of struct. tuples behave like structs but have more relaxed comparison rules: the field names and alignments are ignored.

Change byte…

Change program bytes. You can modify the executable file and eventually generate a new file (the Create EXE file… command; action ProduceExe). If you patch bytes, then you may enter multiple bytes (see also Binary string format). If this command is invoked when the debugger is active, then IDA will modify the memory and the database. If the database does not contain the patched bytes, then only the process memory will be modified. You can create a difference file too (the Create DIFF file… command; action ProduceDiff). See also How to Enter a Number.

Assemble…

This command allows you to assemble instructions. Currently, only the IBM PC processors provide an assembler, nonetheless, plugin writers can extend or totally replace the built-in assembler by writing their own.

The assembler requires to enclose all memory references into square brackets. For example:

        mov ax, [counter]

Also, the keyword ‘offset’ must not be used. Instead of

        mov eax, offset name

you must write

        mov eax, name

See also How to Enter a Number.

Patched bytes

Open the Patched bytes window. The Patched bytes view shows the list of the patched locations in the database. It also allows you to revert modifications selectively.

Patched bytes view

Reverting changes

Select location(s) and click Revert… from the context menu to revert this modification.

Patching bytes

You can change individual bytes via Edit → Patch program → Change byte….

Apply patches to input file…

Apply previously patched bytes back to the input file. If the “Restore” option is selected, then the original bytes will be applied to the input file.

See also ProduceDiff action.

Create alignment directive…

Create alignment directive. The alignment directive will replace a number of useless bytes inserted by the linker to align code and data to paragraph boundary or any other address which is equal to a power of two. You can select a range to be converted to an alignment directive. If you have selected a range, IDA will try to determine a correct alignment automatically.

There are at least two requirements for this command to work:

  • There must be enough unexplored bytes at the current address.
  • An alignment directive must always end at an address which is divisible by a power or two.

Manual instruction…

Specify alternate representation of the current instruction. Use it if IDA cannot represent the current instruction as desired. If the instruction itself is ok and only one operand is misrepresented, then use Manual… command (action ManualOperand). To delete the manual representation, specify an empty string.

Color instruction…

This command allows you to specify the background color for the current instruction or data item. Only GUI version supports different background colors. Specifying a non-defined custom color will reset the instruction color.

Toggle border

Toggle the display of a border between code and data. This command allows you to hide a thin border which is like the one generated automatically by IDA between instructions and data. If the border was already hidden, then it is displayed again.

Edit menu actions for Pseudocode View

{% hint style=“info” %} The options below appear when the Edit menu is opened from the Pseudocode View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
CopyEditCopyCopy
Begin selectionAnchorBegin selection. Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor. More…
Select allSelectAllSelect all
Select identifierSelectIdentifierSelect identifier
UndoUndoActionThis command reverts the database to the state before executing the last user action. More…
RedoRedoActionThis command reverts the previously issued Undo command. More…
Export dataExportDataExport data
CodeMakeCodeConvert to instruction. More…
DataMakeDataConvert to data. More…
Struct var…DeclareStructVarDeclare a structure variable. More…
Strings``
StringMakeStrlitConvert to string. More…
C-style (0 terminated)StringCC-style (0 terminated)
DOS style ($ terminated)StringDOSDOS style ($ terminated)
Pascal style (1 byte length)StringPascal1Pascal style (1 byte length)
Wide pascal (2 byte length)StringPascal2Wide pascal (2 byte length)
Delphi (4 byte length)StringDelphiDelphi (4 byte length)
UnicodeStringUnicodeUnicode
Unicode pascal (2 byte length)StringUnicodePascal2Unicode pascal (2 byte length)
Unicode wide pascal (4 byte length)StringUnicodePascal4Unicode wide pascal (4 byte length)
Array…MakeArrayConvert to array. More…
UndefineMakeUnknownConvert to undefined. More…
RenameMakeNameRename the current location. More…
Operand type``
Offset``
Offset (data segment)OpOffsetConvert the current operand to an offset in the data segment. More…
Offset (current segment)OpOffsetCsConvert the current operand to an offset in the current segment. More…
Offset by (any segment)…OpAnyOffsetConvert the current operand to an offset in any segment. More…
Offset (user-defined)…OpUserOffsetConvert the current operand to an offset with any base. More…
Offset (struct)…OpStructOffsetConvert the current operand to a structure offset. More…
Number``
Number (default)OpNumberConvert the current operand to a number. More…
HexadecimalOpHexConvert the current operand to a hexadecimal number. More…
DecimalOpDecimalConvert the current operand to a decimal number. More…
OctalOpOctalConvert the current operand to a octal number. More…
BinaryOpBinaryConvert the current operand to a binary number. More…
Floating pointOpFloatConvert to floating point. More…
Toggle leading zeroesToggleLeadingZeroesToggle leading zeroes. More…
CharacterOpCharConvert the current operand to a character constant
SegmentOpSegmentConvert the current operand to a segment base
Enum member…OpEnumConvert the current operand to a symbolic constant
Stack variableOpStackVariableConvert the current operand to a stack variable
Change signChangeSignChange the sign of the current operand
Bitwise negateBitwiseNegatePerform bitwise negation of the current operand
Manual…ManualOperandEnter the current operand manually. More…
Set operand type…SetOpTypeSet the current operand’s type
Comments``
Edit func comment…hx:EditCmtEdit func comment
Add pseudocode comments…hx:AddPseudoCmtAdd pseudocode comments
Delete pseudocode comments…hx:DelPseudoCmtDelete pseudocode comments
Enter comment…MakeCommentEnter a regular comment. More…
Enter repeatable comment…MakeRptCmtEnter repeatable comment. More…
Enter anterior lines…MakeExtraLineAEnter lines preceding the generated lines. More…
Enter posterior lines…MakeExtraLineBEnter lines following the generated lines
Edit block comment…mv:EditBlockCmtEdit block comment of microcode line
Edit comment…mv:EditCmtEdit comment of microcode line
Segments``
Create segment…CreateSegmentThis command allows you to create a new segment. More…
Edit segment…EditSegmentEdit segment attributes. More…
Delete segment…KillSegmentDelete segment. More…
Move current segment…MoveSegmentChange the current segment boundaries. More…
Rebase program…RebaseProgramRebase program. More…
Change segment translation…SegmentTranslationChange the current segment translation table
Change segment register value…SetSegmentRegisterChange segment register value. More…
Set default segment register value…SetSegmentRegisterDefaultSet default segment register value. More…
Structs``
Struct var…DeclareStructVarDeclare a structure variable. More…
Force zero offset fieldZeroStructOffsetToggle display of the first field of a structure in an offset expression. More…
Select union member…SelectUnionMemberChoose the representation of a union member. More…
Create struct from selectionCreateStructFromDataThis command defines a new structure from data already defined. The new structure is created with adequate data types, and each member uses the current data name if it is available. More…
Copy field info to pointersCopyFieldsToPointersCopy field info to pointed addresses. This command scans the current struct variable and renames the locations pointed by offset expressions unless they already have a non-dummy name. More…
Functions``
Create function…MakeFunctionCreate a new function in the disassembly. More…
Edit function…EditFunctionEdit function attributes - change function properties, including bounds, name, flags, and stack frame parameters. More…
Append function tail…AppendFunctionTailThis command appends an arbitrary range of the program to a function definition. A range must be selected before applying this command. This range must not intersect with other function chunks (however, an existing tail can be added to multiple functions). More…
Remove function tail…RemoveFunctionTailRemove function tail. More…
Delete functionDelFunctionDelete function. Deleting a function deletes only information about a function, such as information about stack variables, comments, function type, etc. The instructions composing the function will remain intact.
Set function endFunctionEndChange the function end address. This command changes the current or previous function bounds so that its end will be set at the cursor. If it is not possible, IDA beeps.
Stack variables…OpenStackVariablesOpen the stack variables window. See subviews for more.
Change stack pointer…ChangeStackPointerChange stack pointer. This command allows you to specify how the stack pointer (SP) is modified by the current instruction. More…
Rename register…RenameRegisterRename a general processor register. More…
Set type…SetTypeSet type information for an item or current function. More…
Patch program``
Change byte…PatchByteChange program bytes. More…
Change word…PatchWordChange program words
Assemble…AssembleThis command allows you to assemble instructions. Currently, only the IBM PC processors provide an assembler, nonetheless, plugin writers can extend or totally replace the built-in assembler by writing their own. More…
Patched bytesPatchedBytesOpen the Patched bytes window. More…
Apply patches to input file…ApplyPatchesApply previously patched bytes back to the input file. If the “Restore” option is selected, then the original bytes will be applied to the input file. More…
Other``
Specify switch idiom…uiswitch:SpecSwitchIdiomSpecify switch idiom
Create alignment directive…MakeAlignmentCreate alignment directive. More…
Manual instruction…ManualInstructionSpecify alternate representation of the current instruction. More…
Color instruction…ColorInstructionThis command allows you to specify the background color for the current instruction or data item. More…
Reset decompiler information…hx:ResTypeInfoReset decompiler information
Toggle skippable instructions…hx:ToggleSkippableInsnToggle skippable instructions
Decompile as call…hx:UserDefinedCallDecompile as call
Toggle borderToggleBorderToggle the display of a border between code and data. More…
detect and parse golang metadatagolang:detect_and_parsedetect and parse golang metadata
Open picture in default viewerpicture_search:open_in_viewerOpen picture in default viewer
Save picturepicture_search:save_pictureSave picture
Plugins``
Quick run pluginsQuickRunPluginsQuickly run a plugin

Begin selection

Begin selection. Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor.

To drop the anchor, you can either use the Alt + L key or the Shift + , , , combination, which is more convenient. You can also drop the anchor with the mouse by simply clicking and dragging it.

After you’ve dropped the anchor, you can navigate freely using arrows, etc. Any command that uses the anchor, raises it.

The anchored range is displayed with another color.

When you exit from IDA, the anchor value is lost.

Undo

This command reverts the database to the state before executing the last user action. It is possible to apply Undo multiple times, in this case multiple user actions will be reverted.

Please note the entire database is reverted, including all modifications that were made to the database after executing the user action and including the ones that are not connected to the user action. For example, if a third party plugin modified the database during or after the user action, this modification will be reverted. In theory it is possible to go back in time to the very beginning and revert the database to the state that was present immediately after performing the very first user action. However, in practice the undo buffers overflow because of the changes made by autoanalysis.

Autoanalysis (Options → General… → Analysis) generates copious amounts of undo data. Also, please note that maintaining undo data during autoanalysis slows it down a bit. In practice, it is not a big deal because the limit on the undo data is reached quite quickly (in a matter of minutes). Therefore, if during analysis the user does not perform any actions that modify the database, the undo feature will turn itself off temporarily.

However, if you prefer not to collect undo data at all during the initial autoanalysis, just turn off the UNDO_DURING_AA parameter in ida.cfg.

The configuration file ida.cfg has 2 more undo-related parameters:

ParameterDescriptionDefault
UNDO_MAXSIZEMax size of undo buffers. Once this limit is reached, the undo info about the oldest user action will be forgotten.128MB
UNDO_DEPTHMax number of user actions to remember. If set to 0, the undo feature will be unavailable.1000000

Since there is a limit on the size of undo buffers, any action, even the tiniest, may become non-undoable after some time. This is true because the analysis or plugins may continue to modify the database and overflow the buffers. Some massive actions, like deleting a segment, may be non-undoable just because of the sheer amount of undo data they generate.

Please note that Undo does not affect the state of IDC or Python scripts. Script variables will not change their values because of Undo. Also nothing external to the database can be changed: created files will not be deleted, etc.

Some actions cannot be undone. For example, launching a debugger or resuming from a breakpoint cannot be undone.

Redo

This command reverts the previously issued Undo command. It is possible to use Redo multiple times.

This command also reverts all changes that were done to the database after the last Undo command, including the eventual useful modifications made by the autoanalysis. In other words, the entire database is modified to get to the exact state that it had before executing the last Undo command.

Code

Convert to instruction. This command converts the current unexplored bytes to instruction(s). IDA will warn you if it is not possible.

If you have selected a range using the Anchor action, all the bytes from this range will be converted to instructions.

If you apply this command to an instruction, it will be reanalyzed.

Data

Convert to data. This command converts the current unexplored bytes to data. If it is not possible, IDA will warn you.

Multiple using of this command will change the data type:

 db -> dw -> dd -> float -> dq -> double -> dt -> packreal -> octa \;
 ^                                                                 |;
 \---------<----------------<--------------<-----------------------/;

You may remove some items from this list using the Setup data types… command (action SetupData).

If the target assembler (Options → General… → Analysis) does not support double words or another data type, it will be skipped. To create a structure variable, use the Struct var… command (action DeclareStructVar). To create an array, use the Array… command (action MakeArray). To convert back, use the Undefine command (action MakeUnknown).

Struct var…

Declare a structure variable. IDA will ask you to choose a structure type. You must have some structure types defined in order to use this command. If the target assembler supports it, IDA will display the structure in terse form (using just one line). To uncollapse a terse structure variable use the Unhide command. You can also use this command to declare a structure field in another structure (i.e., nested structures are supported too).

String

Convert to string. This command converts the current unexplored bytes to a string. The set of allowed characters is specified in the configuration file, parameter StrlitChars. Character ‘\0’ is not allowed in any case. If the current assembler (Options → General → Analysis → Target assembler) does not allow characters above 0x7F, characters with high bit set are not allowed. If the anchor has been dropped, IDA will take for the string all characters between the current cursor position and the anchor. Use the anchor if the string starts a disallowed character.

This command also generates a name for the string. In the configuration file, you can specify the characters allowed in names (NameChars). You can change the literal string length using Array… command (action MakeArray). The GUI version allows you to assign a special hotkey to create Unicode strings. To do so, change the value of the StringUnicode parameter in the IDAGUI.CFG file.

Array…

Convert to array. This command allows you to create arrays and change their sizes.

The arrays are created in 2 simple steps:

  1. Create the first element of array using the data definition commands (data, string, structs)

  2. Apply the array command to the created data item. Enter array size in current array elements (not bytes). The suggested array size is the minimum of the following values:

  • the address of the next item with a cross reference
  • the address of the next user-defined name For string literals, you can use this command to change the length of the string.

The dialog box contains the following fields:

  • Items on a line (meaningless for string literals):

    • 0 - place maximal number of items on a line
    • other value - number of items on a line Please note that the margin parameter affects the number of items on a line too.
  • Alignment (meaningless for string literals):

    • -1 - do not align items
    • 0 - align automatically
    • other value - width of each item
  • Signed elements: if checked, IDA treats all elements as signed numbers. Only meaningful for numbers (not for offsets and segments and strings)

  • Display indexes: if checked, IDA will display the indexes of array elements in the form of comments (0,1,2…)

  • Create as array: if not checked, IDA will create a separate item for each array element. Useful for creating huge arrays. If the box is unchecked when this command is applied to string literals, IDA will create many string literals instead of one big string.

If applied to a variable-sized structure, this command is used to specify the overall size of the structure. You cannot create arrays of variable-sized structures.

Undefine

Convert to undefined. This command deletes the current instruction or data, converting it to ‘unexplored’ bytes. IDA will delete the subsequent instructions if there are no more references to them (functions are never deleted).

If you have selected a range using the Anchor action, all the bytes in this range will be converted into ‘unexplored’ bytes. In this case, IDA will not delete any other instructions even if there are no references to them after the deletion.

Rename

Rename the current location. This command gives name/renames/deletes name for the current item.

To delete a name, simply give an empty name.

If the current item is referenced, you cannot delete its name. Even if you try, IDA will generate a dummy name (See Options → Name representation…).

List of available options:

  • Local name: The name is considered to be defined only in the current function. Please note that IDA does not check the uniqueness of the local names in the whole program. However, it does verify that the name is unique for the function.

  • Include in name list: Here you can also include/remove the name from the name list (see the Jump by name… command; action JumpName). If the name is hidden, you will not see it in the names window.

  • Public name: You can declare a name as a public (global) name. If the current assembler supports the “public” directive, IDA will use it. Otherwise, the publicness of the name will be displayed as a comment.

  • Autogenerated name: An autogenerated name will appear in a different color. If the item is indefined, it will disappear automatically.

  • Weak name: You can declare a name as a weak name. If the current assembler supports the “weak” directive, IDA will use it. Otherwise, the weakness of the name will be displayed as a comment.

  • Create name anyway: If this flag is on, and if the specified name already exists, IDA will try to variate the specified name by appending a suffix to it.

Offset (data segment)

Convert the current operand to an offset in the data segment. This command converts the immediate operand of the current instruction/data to an offset from the current data segment (DS). If the current DS value is unknown (or equal 0xFFFF) IDA will warn you - it will beep. In this case, you have to define DS register value for the current byte. The best way to do it is:

  • jump to segment register change point (the Jump to segment register… command; action JumpSegmentRegister),
  • change value of DS (the Change segment register value… command; action SetSegmentRegister)
  • return (the Jump back command; action Return) or you can change default value of DS for the current segment (the Set default segment register value… command; action SetSegmentRegisterDefault).

If you want to delete offset definition, you can use this command again - it works as trigger. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset (current segment)

Convert the current operand to an offset in the current segment. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise, it will be left unmodified. If this command is applied to a structure member in the Local types window, then IDA will create an “automatic offset”. An automatic offset is an offset with the base equal to 0xFFFFFFFF. This base value means that the actual value of the base will be calculated by IDA when a structure instance is created. To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset by (any segment)…

Convert the current operand to an offset in any segment. This command converts the immediate operand of the current instruction/data to an offset from any segment. IDA will ask to choose a base segment for the offset. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. To create offsets to structure members use Offset (struct)… command (action OpStructOffset).

Offset (user-defined)…

Convert the current operand to an offset with any base. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If the offset base is specified as 0xFFFFFFFF, then IDA will create “an automatic offset”. Automatic offsets mean that the actual value of the base will be calculated by IDA.

The following offset attributes are available:

OptionDescription
Treat the base address as a plain numberif checked, IDA will treat the base address as a number. In this case, IDA will not create a cross-reference to it and the base address will be printed as a number, not as an offset expression.
Offset points past the main objectOffsets of this type point past an object end. They do not cause an object created/deletion.
Use image base as offset baseThese offsets are based on the image base. There is no need to explicitly specify the offset base. These offsets are displayed in a concise form: rva func instead of offset func - imagebase. If you intend to reassemble the output file, execute the following IDC statement: set_inf_attr(INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) & ~INFFL_ALLASM);
Subtract operand valueUse this option when the operand value should be substracted from the base to get the target address. In this case the displayed expression will be displayed as offset base - target instead of the usual offset target - base
Signed operandUse this option if the operand should be interpreted as a signed value. This option is only available for OFF_REF8, OFF_REF16, OFF_REF32 and OFF_REF64 offset types.
Operand value of 0 is invalidIf the operand value is 0, the value will be highlighted in red.
Operand value of NOT 0 is invalidIf the operand value is zero’s complement (i.e. all bits are set), the value will be highlighted in red. For example a OFF_REF16 with an operand value of 0xFFFF would be invalid.
Use the current address as the offset baseThe offset base is dynamically calculated and is equal to the address of the current element: - for standalone items: their start address - for arrays: the start of the array element - for structures: the start of the structure field

The offset expression is displayed in the following concise form: offset target - $ where “$” denotes the start of the element (and is assembler-dependent).

To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset (struct)…

Convert the current operand to a structure offset. This command permits to convert all immediate operands of instructions in a range selection to a path of offsets through a structure and its possible sub unions. If no selection is active, IDA will simply permit to convert the current operand. In this case, it will display a simple dialog box the same way as the text version (see below). You can select the desired register in the drop-down list: all operands relative to this register will be added to the ‘Offsets’ list. A special empty line in the drop-down list is used to directly work on immediate values. Checkboxes in the ‘Offsets’ list allow you to select which operand you indeed want to modify. By default, IDA will select only undefined operands, to avoid overwriting previous type definitions. This list is sorted by operand value, by instruction address and finally by operand number. You can easily see the instructions related to the operand by moving the mouse over it, and wait for a hint to be displayed. The ‘Structures and Unions’ tree will contain all selectable structures, and sub unions. Once you select or move over a structure, the ‘Offsets’ list updates itself for each checked offset: the computed name of the operand is displayed, according to the selected structure in the tree. An icon is also drawn, to easily know if a specific structure matches the offset or not, or if the offset is too big for the selected structure. The structures who match the most offsets will be near the top of the tree. You can also move your mouse over structures in the tree to obtain an interesting hint. A ‘?’ icon can also appear, if the offset can be specialized by selecting an union member. In this case, if you expand the structure in the tree, you can select the adequate union member simply by checking the desired radio button. IDA automatically corrects the related name in the ‘Offsets’ list. The ‘Offset delta’ value represents the difference between the structure start and the pointer value. For example, if you have an operand 4 and want to convert in into an expression like “mystruct.field_6-2”, then you have to enter 2 as the delta. Usually the delta is zero, i.e. the pointer points to the start of the structure. The ‘Hide sub structures without sub unions’ option (checked by default) avoids to add unnecessary sub structures to the tree, to keep it as small as possible. If you uncheck this option, all sub structures will be added to the tree. By default, IDA displays the structure member at offset 0. To change this behavior, you can directly disable the ‘Force zero offset field’ in the ‘Options’ frame. Later zero offsets can be forced using Edit → Structs → Force zero offset menu item.

Text version

This command converts immediate operand(s) type of the current instruction/data to an offset within the specified structure. Before using this command, you have to define a structure type. First of all, IDA will ask a so-called “struct offset delta”. This value represents the difference between the structure start and the pointer value. For example, if you have an operand 4 and want to convert in into an expression like “mystruct.field_6-2”, then you have to enter 2 as the delta. Usually the delta is zero, i.e. the pointer points to the start of the structure. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the an operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. When you use this command, IDA deletes the manually entered operand. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. By default IDA doesn’t display the structure member at offset 0. To change this behavior, use the Force zero offset field command. Moreover, if there are several possible representations (this can happen if unions are used), select the desired representation using the Select union member… command.

Number (default)

Convert the current operand to a number. That way, you can delete suspicious mark of the item. The number is represented in the default radix for the current processor (usually hex, but octal for PDP-11, for example). When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Hexadecimal

Convert the current operand to a hexadecimal number. This command converts the immediate operand(s) type of the current instruction/data to a hex number, so that you can delete the suspicious mark of the item. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Decimal

Convert the current operand to a decimal number. This command converts the immediate operand(s) type of the current instruction/data to decimal. Therefore, it becomes a ‘number’. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Octal

Convert the current operand to a octal number. IDA always uses 123o notation for octal numbers even if the current assembler does not support octal numbers. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Binary

Convert the current operand to a binary number. This command makes the current instruction or data operand type binary. IDA always uses 123b notation for binary numbers even if the current assembler does not support binary numbers. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Floating point

Convert to floating point. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Toggle leading zeroes

Toggle leading zeroes.

This command displays or hides the leading zeroes of the current operand. Example: if the instruction looked like this:

    and     ecx, 40h

then after applying the command it will look like this:

    and     ecx, 00000040h

If you prefer to see leading zeroes in all cases, then open the calculator and enter the following expression: set_inf_attr (INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) | INFFL_LZERO); This will toggle the default for the current database and all numbers without leading zeroes will become numbers with leading zeroes, and vice versa. See also Edit|Operand types submenu.

Manual…

Enter the current operand manually. You may specify any string instead of an operand if IDA does not represent the operand in the desired form. In this case, IDA will simply display the specified string in the instruction instead of the default operand.

The current operand (under the cursor) will be affected.

You can use this command not only with instructions but with data items too.

IDA proposes the previous manual operand as the default value in the input form.

To delete the manual operand and revert back to the default text, specify an empty string.

IDA automatically deletes manually entered operands when you change operand representation using Edit → Operand types submenu.

{% hint style=“info” %} A text offset reference is generated if you use a label in the program as the operand string. In other cases no cross-references are generated. {% endhint %}

Enter comment…

Enter a regular comment. If you stand at the function start and your cursor is on a function name, IDA will ask you to enter a function comment. If you stand at the segment start and your cursor is on a segment name, IDA will ask you to enter a segment comment. If this command is issued in the Local types window, it allows you to change the comment of a structure/enum, or structure/enum member. If the cursor is on the structure/enum name, the structure/enum comment will be changed, otherwise the member comment will be changed. Otherwise, this command allows you to enter a normal indented comment for the current item. You can show/hide all comments in Options → General → Disassembly → Display disassembly line parts: Comments.

Enter repeatable comment…

Enter repeatable comment. A repeatable comment will appear attached to the current item and all other items referencing it. If you stand at the function start, IDA will ask you to enter a function comment. If this command is issued in the Local types window, it allows you to change the comment of a structure/enum, or structure/enum member. If the cursor is on the structure/enum name, the structure/enum comment will be changed, otherwise the member comment will be changed. Otherwise, this command allows you to enter a repeatable comment for the current item.

{% hint style=“info” %} You cannot enter repeatable segment comments. {% endhint %}

All items that refer to the current item will have this comment by default. Note that if you have defined both comment types (regular and repeatable), the regular comment will be displayed for the current item and the repeatable comment will be displayed for all items that refer to the current item, if they do not have their own comments. The repeatable comments may be used to describe subroutines, data items, etc., because all calls to the subroutine will have the repeatable comment. You can show/hide all comments in Options → General → Disassembly → Display disassembly line parts: Comments.

Enter anterior lines…

Enter lines preceding the generated lines. If you want to enter multi-line comments or additional instructions, you can use this feature of IDA.

There are two kinds of extra lines: the ones generated before the instruction line and the ones generated after the instruction line.

Do not forget that the maximal number of lines for an item is 500.

IDA does not insert a comment symbol at the beginning of the lines.

Create segment…

This command allows you to create a new segment.

If you select a range using the anchor, IDA will propose the start address and the end address of the selection as defaults for the segment bounds.

You need to specify at least:

  • the segment start address
  • the segment end address (excluded from the range)
  • the segment base

Click here to learn about addressing model used in IDA.

If “sparse storage” is set, IDA will use special sparse storage method for the segment. This method is recommended for huge segments. Later, it is possible to change the storage method of any region using set_storage_type IDC function.

If another segment already exists at the specified address, the existing segment is truncated and the new segment lasts from the specified start address to the next segment (or specified end address, whichever is lower). If the old and the new segments have the same base address, instructions/data will not be discarded by IDA. Otherwise, IDA will discard all instructions/data of the new segment.

An additional segment may be created by IDA to cover the range after the end of the new segment.

Edit segment…

Edit segment attributes. This command opens the Change segment attributes dialog.

Change segment attributes dialog

Change segment attributes options

{% hint style=“info” %} Changing the segment class may change the segment type. {% endhint %}

  • Move Adjacent Segments: means that the previous and next segments will be shrunk or expanded to fill gaps between segments. Click here for more information.

  • Disable Addresses: if set, when a segment is shrunk, all information about bytes going out of the segment will be completely removed.. Otherwise, IDA will discard information about instructions/data, comments etc, but will retain byte values so that another segment can be created later and it will use the existing byte values.

If IDA creates 2 segments where only one segment must exist, you may try the following sequence:

  • Delete one segment (action KillSegment). Choose one with bad segment base value. Do not disable addresses occupied by the segment being deleted.
  • Change bounds of another segment. Note that the Create segment… command (action CreateSegment) changes the boundaries of the overlapping segment automatically.

Segments with the “debugger” attribute are the segments whose memory contents are not saved in the database. Usually, these segments are created by the debugger to reflect the current memory state of the program.

However, the user can modify this attribute.

If it is cleared, then the segment will permanently stay in the database after closing the debugger session. The database will reflect the state of the segment which was at the time when the status is changed.

If it is set, then the segment will become a temporary segment and will be deleted at the end of the debugging session.

The debugger segment checbkox is available only during debugging sessions.

The “loader” segments are the segment created by the file loader. The segment having this attribute are considered to be part of the input file.

A segment with the “debugger” attribute set and the “loader” attribute not set is considered to be an ephemeral segment. Such segments are not analyzed automatically by IDA.

“Segment permissions” group box can be used to modify Segment access permissions (Read/Write/Execute)

Segment Name

Enter a new name for the segment. A segment name is up to 8 characters long. IDA does check if the length is ok. Try to give mnemonic names for the segments.

Class Name

The segment class name identifies the segment with a class name (such as CODE, FAR_DATA, or STACK). The linker places segments with the same class name into a contiguous range of memory in the runtime memory map.

Changing the segment class changes only the segment definition on the screen. There are the following predefined segment class names:

Segment classDescription
CODEPure code
DATAPure data
CONSTPure data
BSSUninitialized data
STACKUninitialized data
XTRNExtern definitions segment

If you change segment class and the segment type is “Regular”, then the segment type will be changed accordingly.

In order to set the segment type “Regular”, you should change the segment class to “UNK”.

{% hint style=“info” %} Segment class names are never deleted. Once you define a segment class name, you cannot reuse it as a name of another object. {% endhint %}

Segment bitness

You can choose between 16-bit and 32-bit segment addressing.

IDA will delete all instructions and data in the segment if the segment address is changed.

Never do it if you are not sure. It may have irreversible consequences, all instructions/data will be converted to undefined bytes.

Segment Alignment

You can specify the segment alignment for the selected segment. By default, IDA assumes ‘byte’ alignment.

Changing the alignment changes only the segment definition on the screen. Nothing else will happen.

Segment Combination

A field that describes how the linker can combine the segment with other segments. Under MS-DOS, segments with the same name and class can be combined in two ways: they can be concatenated to form one logical segment, or they can be overlapped. In the latter case, they have either the same start address or the same end address, and they describe a common range in memory. Values for the field are:

  • Private: Do not combine with any other program segment.
  • Public: Combine by appending at an offset that meets the alignment requirement.
  • Stack: Combine as for Public. This combine type forces byte alignment.
  • Common: Combine by overlay using maximum size.

Changing segment combination changes only the segment definition on the screen. Nothing else will happen.

Delete segment…

Delete segment. IDA will ask your the permission to disable the addresses occupied by the segment. If you allow this operation, all information about the segment will be deleted. In other words, IDA will discard the information about instructions or data, comments etc.

If you check the “disable addresses” checkbox, IDA will mark the addresses occupied by the segment as “nonexistent” in the program. You will lose ALL information, including byte values.

It is impossible to disassemble the content of addresses not located in any segment, therefore you must create a new segment if you want to resume the disassembly of that part of the code.

You can also edit an adjacent segment to expand it to those addresses (Edit → Segments → Edit segment…).

IDA will ask your the permission to disable addresses occupied by the segment. If you give your permission, information about the segment will be deleted, otherwise IDA will discard information about instruction/data, comments etc, but retain byte values so that you will be able to create another segment afterwards. To disassemble the addresses occupied by the segment, you need to create a new segment again (i.e. you cannot disassemble bytes without a segment). You can also expand another adjacent segment to these addresses.

Move current segment…

Change the current segment boundaries. This command open the Move segment dialog and allows you to move segment(s) to another address. Use it if the segment(s) are loaded at a wrong address. This command shifts (moves) the selected segments in the memory to the target address. There must be enough free space at the target address for the segments. All information in the segment will be moved to the new address, but since the addresses change, the disassembly might be not valid anymore (especially if the program is moved to the wrong addresses and the relocation information is not available).

Fix up the relocated segment

This option allows IDA to modify the references to/from the relocated segment(s). If it is turned off, the references might be wrong after the move.

Rebase program…

Rebase program. The whole program will be shifted by the specified amount of bytes in the memory. The following options are available (we strongly recommend to leave them turned on):

  • Fix up relocations: This option allows IDA to modify the references to/from the relocated segment(s). If it is turned off, the references might be wrong after the move.
  • Rebase the whole image: This option is accessible only if the whole program is selected. It allows IDA to adjust internal variables on the whole program.

Please note rebasing the program might remove user-defined xrefs.

Change segment register value…

Change segment register value. Relevant only for processors with the segment registers. Currently this command works for IBM PC, TMS320C2, Intel80196, and PowerPC processors. This command creates or updates a segment register change point. See also the Jump to segment register… command (action JumpSegmentRegister) for more info.

Set default segment register value…

Set default segment register value. Relevant only for processors with the segment registers. You can specify a default value of a segment register for the current segment. When you change the default value, IDA will reanalyze the segment, taking the default value when it cannot determine the actual value of the register. This takes time, so do not be surprised if references are not corrected immediately.

To specify a value other than the default value of a segment register, you can use the Change segment register value… command (action SetSegmentRegister).

Struct var…

Declare a structure variable. IDA will ask you to choose a structure type. You must have some structure types defined in order to use this command. If the target assembler supports it, IDA will display the structure in terse form (using just one line). To uncollapse a terse structure variable use the Unhide command. You can also use this command to declare a structure field in another structure (i.e., nested structures are supported too).

Force zero offset field

Toggle display of the first field of a structure in an offset expression. This command forces IDA to display a full structure member name even if the offset of the member is equal to zero.

If used twice, the command cancels itself.

Example: Suppose we have the following structure:

    xxx     struc
    a       db ?
    b       db ?
    c       db ?
    xxx     ends

    dloc    xxx ?

Normally IDA displays references to it like this:

    mov     eax, offset dloc
    mov     eax, offset dloc.b

If you force IDA, then it displays member ‘a’:

    mov     eax, offset dloc.a
    mov     eax, offset dloc.b

Select union member…

Choose the representation of a union member. This command tells IDA how to display references to a union from the current cursor location.

Example: Suppose we have the following union:

        xxx     union
        a       db ?
        b       dw ?
        c       dd ?
        ends   xxx
        dloc    xxx ?

Normally, IDA displays references to “dloc” like this:

        mov     al,  byte ptr dloc
        mov     eax, word ptr dloc

After using this command, IDA can display the union members:

        mov     al,  dloc.b
        mov     eax, dloc.d 

Create struct from selection

This command defines a new structure from data already defined. The new structure is created with adequate data types, and each member uses the current data name if it is available.

This command is available only in the graphical version of IDA.

Copy field info to pointers

Copy field info to pointed addresses. This command scans the current struct variable and renames the locations pointed by offset expressions unless they already have a non-dummy name.

It also copies the type info from the struct members to pointed locations.

Create function…

Create a new function in the disassembly. You can specify function boundaries using the anchor. If you don’t specify any, IDA will try to find the boundaries automatically:

  • function start point is equal to the current cursor position;
  • function end point is calculated by IDA.

A function cannot contain references to undefined instructions. If a function has already been defined at the specified addresses, IDA will jump to its start address, showing you a warning message. A function must start with an instruction.

Edit function…

Edit function attributes - change function properties, including bounds, name, flags, and stack frame parameters. This command opens an Edit Function dialog, and allows you to modify function characteristics and stack frame structure. If the current address does not belong to any function, IDA will beep.

Edit function dialog

To change only the function end address, use the FunctionEnd command instead. This command allows you to change the function frame parameters too. You can change sizes of some parts of frame structure.

Stack Frame Structure

IDA represents the stack using the following structure:

Stack SectionPointer
function arguments-
return address-
saved registers (SI, DI, etc)← BP
local variables← SP

{% hint style=“info” %} For some processors or functions, BP may equal SP, meaning it points to the bottom of the stack frame. {% endhint %}

You may specify the number of bytes in each part of the stack frame. The size of the return address is calculated by IDA (possibly depending on the far function flag).

           push    ebp
           lea     ebp, [esp-78h]
           sub     esp, 588h
           push    ebx
           push    esi
           lea     eax, [ebp+74h]

      +------------------------------+
      | function arguments           |
      +------------------------------+
      | return address               |
      +------------------------------+
      | saved registers (SI,DI,etc)  |
      +------------------------------+  <- typical BP
      |                              |
      |                              |
      |                              |  <- actual BP
      | local variables              |
      |                              |
      |                              |
      |                              |
      +------------------------------+  <- SP

In our example, the saved registers area is empty (since EBP has been initialized before saving EBX and ESI). The difference between the ‘typical BP’ and ‘actual BP’ is 0x78 and this is the value of FPD.

After specifying FPD=0x78 the last instruction of the example becomes

           lea     eax, [ebp+78h+var_4]

where var_4 = -4

Most of the time, IDA calculates the FPD value automatically. If it fails, the user can specify the value manually.

If the value of the stack pointer is modified in an unpredictable way, (e.g. “and esp, -16”), then IDA marks the function as “fuzzy-sp”.

If this command is invoked for an imported function, then a simplified dialog box will appear on the screen.

See also:

Configurable Parameters

  • Stack Frame Sizes: You can specify the number of bytes in each part of the stack frame. The return address size is calculated automatically by IDA (may depend on the far function flag).
  • Purged Bytes: Specifies the number of bytes added to SP upon function return. This value calculates SP changes at call sites (used in calling conventions such as __stdcall in Windows 32-bit programs).
  • BP Based Frame: Enables IDA to automatically convert [BP+xxx] operands to stack variables.
  • BP Equal to SP: Indicates that the frame pointer points to the bottom of the stack. Commonly used for processors that set up the stack frame with EBP and ESP both pointing to the bottom (e.g., MC6816, M32R).
  • Reanalysis: Pressing Enter without changing any parameter will cause IDA to reanalyze the function.

Append function tail…

This command appends an arbitrary range of the program to a function definition. A range must be selected before applying this command. This range must not intersect with other function chunks (however, an existing tail can be added to multiple functions).

IDA will ask to select the parent function for the selection and will append the range to the function definition.

Remove function tail…

Remove function tail. This command removes the function tail at the cursor from a function definition. If there are several parent functions for the current function tail range, IDA will ask to select the parent function(s) to remove the tail from. After the confirmation, the current function tail range will be removed from the selected function definition. If the parent was the only owner of the current tail, then the tail will be destroyed. Otherwise it will still be present in the database. If the removed parent was the owner of the tail, then another function will be selected as the owner.

Change stack pointer…

Change stack pointer. This command allows you to specify how the stack pointer (SP) is modified by the current instruction.

You cannot use this command if the current instruction does not belong to any function.

You will need to use this command only if IDA was not able to trace the value of the SP register. Usually IDA can handle it but in some special cases it fails. An example of such a situation is an indirect call of a function that purges its parameters from the stack. In this case, IDA has no information about the function and cannot properly trace the value of SP.

Please note that you need to specify the difference between the old and new values of SP.

The value of SP is used if the current function accesses local variables by [ESP+xxx] notation.

See also how to convert to stack variable (Action OpStackVariable).

Rename register…

Rename a general processor register. This command allows you to rename a processor general register to some meaningful name. While this is not used very often on IBM PCs, it is especially useful on RISC processors with lots of registers. For example, a general register R9 is not very meaningful and a name like ‘CurrentTime’ is much better.

This command can be used to define a new register name as well as to remove it. Just move the cursor on the register name and press enter. If you enter the new register name as an empty string, then the definition will be deleted.

If you have selected a range before using this command, then the definition will be restricted to the selected range. But in any case, the definition cannot cross the function boundaries.

You cannot use this command if the current instruction does not belong to any function.

Set type…

Set type information for an item or current function. This command allows you to specify the type of the current item. If the cursor is located on a name, the type of the named item will be edited. Otherwise, the current function type (if there is a function) or the current item type (if it has a name) will be edited.

The function type must be entered as a C declaration. Hidden arguments (like ‘this’ pointer in C++) should be specified explicitly. IDA will use the type information to comment the disassembly with the information about function arguments. It can also be used by the Hex-Rays decompiler plugin for better decompilation. Here is an example of a function declaration:

    int main(int argc, const char *argv[]);

It is also possible to specify a function name coming from a type library. For example, if entering “LoadLibraryW” would yield its prototype:

    HMODULE __stdcall LoadLibraryW(LPCWSTR lpLibFileName);

provided that the corresponding type library is in memory. To delete a type declaration, just enter an empty string. IDA supports the user-defined calling convention. In this calling convention, the user can explicitly specify the locations of arguments and the return value. For example:

    int __usercall func@<ebx>(int x, int y@<esi>);

denotes a function with 2 arguments: the first argument is passed on the stack (IDA automatically calculates its offset) and the second argument is passed in the ESI register and the return value is stored in the EBX register. Stack locations can be specified explicitly:

    int __usercall runtime_memhash@<^12.4>(void *p@<^0.4>, int q@<^4.4>, int r@<^8.4>)

There is a restriction for a __usercall function type: all stack locations should be specified explicitly or all are automatically calculated by IDA. General rules for the user defined prototypes are:

  • the return value must be in a register. Exception: stack locations are accepted for the __golang and __usercall calling conventions.

  • if the return type is ‘void’, the return location must not be specified

  • if the argument location is not specified, it is assumed to be on the stack; consequent stack locations are allocated for such arguments

  • it is allowed to declare nested declarations, for example: int **__usercall func16@(int *(__usercall *x)@ (int, long@, int)@);

    Here the pointer “x” is passed in the ESI register; The pointed function is a usercall function and expects its second argument in the ECX register, its return value is in the EBX register. The rule of thumb to apply in such complex cases is to specify the the registers just before the opening brace for the parameter list.

  • registers used for the location names must be valid for the current processor; some registers are unsupported (if the register name is generated on the fly, it is unsupported; inform us about such cases; we might improve the processor module if it is easy)

  • register pairs can be specified with a colon like edx:eax

  • for really complicated cases this syntax can be used. IDA also understands the “__userpurge” calling convention. It is the same thing as __usercall, the only difference is that the callee cleans the stack.

The name used in the declaration is ignored by IDA. If the default calling convention is __golang then explicit specification of stack offsets is permitted. For example:

  __attribute__((format(printf,2,3)))
  int myprnt(int id, const char *format, ...);

This declaration means that myprnt is a print-like function; the format string is the second argument and the variadic argument list starts at the third argument.

Below is the full list of attributes that can be handled by IDA.

AttributeDescription
packedpack structure/union fields tightly, without gaps
alignedspecify the alignment
noreturndeclare as not returning function
ms_structuse microsoft layout for the structure/union
formatpossible formats: printf, scanf, strftime, strfmon

Data Declaration Keywords

For data declarations, the following custom __attribute((annotate(X))) keywords have been added. The control the representation of numbers in the output:

KeywordDescription
__binunsigned binary number
__octunsigned octal number
__hexunsigned hexadecimal number
__decsigned decimal number
__sbinsigned binary number
__soctsigned octal number
__shexsigned hexadecimal number
__udecunsigned decimal number
__floatfloating point
__charcharacter
__segmsegment name
__enum()enumeration member (symbolic constant)
__offoffset expression (a simpler version of __offset)
__offset()offset expression
__strlit()string
__stroff()structure offset
__custom()custom data type and format
__invsigninverted sign
__invbitsinverted bitwise
__lzeroadd leading zeroes
__tabform()tabular form

Type Declaration Keywords

The following additional keywords can be used in type declarations:

KeywordDescription
_BOOL1a boolean type with explicit size specification (1 byte)
_BOOL2a boolean type with explicit size specification (2 bytes)
_BOOL4a boolean type with explicit size specification (4 bytes)
__int8a integer with explicit size specification (1 byte)
__int16a integer with explicit size specification (2 bytes)
__int32a integer with explicit size specification (4 bytes)
__int64a integer with explicit size specification (8 bytes)
__int128a integer with explicit size specification (16 bytes)
_BYTEan unknown type; the only known info is its size: 1 byte
_WORDan unknown type; the only known info is its size: 2 bytes
_DWORDan unknown type; the only known info is its size: 4 bytes
_QWORDan unknown type; the only known info is its size: 8 bytes
_OWORDan unknown type; the only known info is its size: 16 bytes
_TBYTE10-byte floating point value
_UNKNOWNno info is available
__purepure function: always returns the same value and does not modify memory in a visible way
__noreturnfunction does not return
__usercalluser-defined calling convention; see above
__userpurgeuser-defined calling convention; see above
__golanggolang calling convention
__swiftcallswift calling convention
__spoilsexplicit spoiled-reg specification; see above
__hiddenhidden function argument; this argument was hidden in the source code (e.g. ‘this’ argument in c++ methods is hidden)
__return_ptrpointer to return value; implies hidden
__struct_ptrwas initially a structure value
__array_ptrwas initially an array
__unusedunused function argument
__cppobja c++ style struct; the struct layout depends on this keyword
__ptr32explicit pointer size specification (32 bits)
__ptr64explicit pointer size specification (64 bits)
__shiftedshifted pointer declaration
__highhigh level prototype (does not explicitly specify hidden arguments like ‘this’, for example) this keyword may not be specified by the user but IDA may use it to describe high level prototypes
__bitmaska bitmask enum, a collection of bit groups
__tuplea tuple, a special kind of struct. tuples behave like structs but have more relaxed comparison rules: the field names and alignments are ignored.

Change byte…

Change program bytes. You can modify the executable file and eventually generate a new file (the Create EXE file… command; action ProduceExe). If you patch bytes, then you may enter multiple bytes (see also Binary string format). If this command is invoked when the debugger is active, then IDA will modify the memory and the database. If the database does not contain the patched bytes, then only the process memory will be modified. You can create a difference file too (the Create DIFF file… command; action ProduceDiff). See also How to Enter a Number.

Assemble…

This command allows you to assemble instructions. Currently, only the IBM PC processors provide an assembler, nonetheless, plugin writers can extend or totally replace the built-in assembler by writing their own.

The assembler requires to enclose all memory references into square brackets. For example:

        mov ax, [counter]

Also, the keyword ‘offset’ must not be used. Instead of

        mov eax, offset name

you must write

        mov eax, name

See also How to Enter a Number.

Patched bytes

Open the Patched bytes window. The Patched bytes view shows the list of the patched locations in the database. It also allows you to revert modifications selectively.

Patched bytes view

Reverting changes

Select location(s) and click Revert… from the context menu to revert this modification.

Patching bytes

You can change individual bytes via Edit → Patch program → Change byte….

Apply patches to input file…

Apply previously patched bytes back to the input file. If the “Restore” option is selected, then the original bytes will be applied to the input file.

See also ProduceDiff action.

Create alignment directive…

Create alignment directive. The alignment directive will replace a number of useless bytes inserted by the linker to align code and data to paragraph boundary or any other address which is equal to a power of two. You can select a range to be converted to an alignment directive. If you have selected a range, IDA will try to determine a correct alignment automatically.

There are at least two requirements for this command to work:

  • There must be enough unexplored bytes at the current address.
  • An alignment directive must always end at an address which is divisible by a power or two.

Manual instruction…

Specify alternate representation of the current instruction. Use it if IDA cannot represent the current instruction as desired. If the instruction itself is ok and only one operand is misrepresented, then use Manual… command (action ManualOperand). To delete the manual representation, specify an empty string.

Color instruction…

This command allows you to specify the background color for the current instruction or data item. Only GUI version supports different background colors. Specifying a non-defined custom color will reset the instruction color.

Toggle border

Toggle the display of a border between code and data. This command allows you to hide a thin border which is like the one generated automatically by IDA between instructions and data. If the border was already hidden, then it is displayed again.

Edit menu actions for Hex View

{% hint style=“info” %} The options below appear when the Edit menu is opened from the Hex View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
CopyEditCopyCopy
Begin selectionAnchorBegin selection. Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor. More…
Select allSelectAllSelect all
Select identifierSelectIdentifierSelect identifier
UndoUndoActionThis command reverts the database to the state before executing the last user action. More…
RedoRedoActionThis command reverts the previously issued Undo command. More…
Export dataExportDataExport data
CodeMakeCodeConvert to instruction. More…
DataMakeDataConvert to data. More…
Struct var…DeclareStructVarDeclare a structure variable. More…
Strings``
StringMakeStrlitConvert to string. More…
C-style (0 terminated)StringCC-style (0 terminated)
DOS style ($ terminated)StringDOSDOS style ($ terminated)
Pascal style (1 byte length)StringPascal1Pascal style (1 byte length)
Wide pascal (2 byte length)StringPascal2Wide pascal (2 byte length)
Delphi (4 byte length)StringDelphiDelphi (4 byte length)
UnicodeStringUnicodeUnicode
Unicode pascal (2 byte length)StringUnicodePascal2Unicode pascal (2 byte length)
Unicode wide pascal (4 byte length)StringUnicodePascal4Unicode wide pascal (4 byte length)
Array…MakeArrayConvert to array. More…
UndefineMakeUnknownConvert to undefined. More…
RenameMakeNameRename the current location. More…
Operand type``
Offset``
Offset (data segment)OpOffsetConvert the current operand to an offset in the data segment. More…
Offset (current segment)OpOffsetCsConvert the current operand to an offset in the current segment. More…
Offset by (any segment)…OpAnyOffsetConvert the current operand to an offset in any segment. More…
Offset (user-defined)…OpUserOffsetConvert the current operand to an offset with any base. More…
Offset (struct)…OpStructOffsetConvert the current operand to a structure offset. More…
Number``
Number (default)OpNumberConvert the current operand to a number. More…
HexadecimalOpHexConvert the current operand to a hexadecimal number. More…
DecimalOpDecimalConvert the current operand to a decimal number. More…
OctalOpOctalConvert the current operand to a octal number. More…
BinaryOpBinaryConvert the current operand to a binary number. More…
Floating pointOpFloatConvert to floating point. More…
Toggle leading zeroesToggleLeadingZeroesToggle leading zeroes. More…
CharacterOpCharConvert the current operand to a character constant
SegmentOpSegmentConvert the current operand to a segment base
Enum member…OpEnumConvert the current operand to a symbolic constant
Stack variableOpStackVariableConvert the current operand to a stack variable
Change signChangeSignChange the sign of the current operand
Bitwise negateBitwiseNegatePerform bitwise negation of the current operand
Manual…ManualOperandEnter the current operand manually. More…
Set operand type…SetOpTypeSet the current operand’s type
Comments``
Copy pseudocode to disassemblyhx:EditCmtEdit func comment
Add pseudocode comments…hx:AddPseudoCmtAdd pseudocode comments
Delete pseudocode comments…hx:DelPseudoCmtDelete pseudocode comments
Enter comment…MakeCommentEnter a regular comment. More…
Enter repeatable comment…MakeRptCmtEnter repeatable comment. More…
Enter anterior lines…MakeExtraLineAEnter lines preceding the generated lines. More…
Enter posterior lines…MakeExtraLineBEnter lines following the generated lines
Edit block comment…mv:EditBlockCmtEdit block comment of microcode line
Edit comment…mv:EditCmtEdit comment of microcode line
Segments``
Create segment…CreateSegmentThis command allows you to create a new segment. More…
Edit segment…EditSegmentEdit segment attributes. More…
Delete segment…KillSegmentDelete segment. More…
Move current segment…MoveSegmentChange the current segment boundaries. More…
Rebase program…RebaseProgramRebase program. More…
Change segment translation…SegmentTranslationChange the current segment translation table
Change segment register value…SetSegmentRegisterChange segment register value. More…
Set default segment register value…SetSegmentRegisterDefaultSet default segment register value. More…
Structs``
Struct var…DeclareStructVarDeclare a structure variable. More…
Force zero offset fieldZeroStructOffsetToggle display of the first field of a structure in an offset expression. More…
Select union member…SelectUnionMemberChoose the representation of a union member. More…
Create struct from selectionCreateStructFromDataThis command defines a new structure from data already defined. The new structure is created with adequate data types, and each member uses the current data name if it is available. More…
Copy field info to pointersCopyFieldsToPointersCopy field info to pointed addresses. This command scans the current struct variable and renames the locations pointed by offset expressions unless they already have a non-dummy name. More…
Functions``
Create function…MakeFunctionCreate a new function in the disassembly. More…
Edit function…EditFunctionEdit function attributes - change function properties, including bounds, name, flags, and stack frame parameters. More…
Append function tail…AppendFunctionTailThis command appends an arbitrary range of the program to a function definition. A range must be selected before applying this command. This range must not intersect with other function chunks (however, an existing tail can be added to multiple functions). More…
Remove function tail…RemoveFunctionTailRemove function tail. More…
Delete functionDelFunctionDelete function. Deleting a function deletes only information about a function, such as information about stack variables, comments, function type, etc. The instructions composing the function will remain intact.
Set function endFunctionEndChange the function end address. This command changes the current or previous function bounds so that its end will be set at the cursor. If it is not possible, IDA beeps.
Stack variables…OpenStackVariablesOpen the stack variables window. See subviews for more.
Change stack pointer…ChangeStackPointerChange stack pointer. This command allows you to specify how the stack pointer (SP) is modified by the current instruction. More…
Rename register…RenameRegisterRename a general processor register. More…
Set type…SetTypeSet type information for an item or current function. More…
Patch program``
Change byte…PatchByteChange program bytes. More…
Change word…PatchWordChange program words
Assemble…AssembleThis command allows you to assemble instructions. Currently, only the IBM PC processors provide an assembler, nonetheless, plugin writers can extend or totally replace the built-in assembler by writing their own. More…
Patched bytesPatchedBytesOpen the Patched bytes window. More…
Apply patches to input file…ApplyPatchesApply previously patched bytes back to the input file. If the “Restore” option is selected, then the original bytes will be applied to the input file. More…
Other``
Specify switch idiom…uiswitch:SpecSwitchIdiomSpecify switch idiom
Create alignment directive…MakeAlignmentCreate alignment directive. More…
Manual instruction…ManualInstructionSpecify alternate representation of the current instruction. More…
Color instruction…ColorInstructionThis command allows you to specify the background color for the current instruction or data item. More…
Reset decompiler information…hx:ResTypeInfoReset decompiler information
Toggle skippable instructions…hx:ToggleSkippableInsnToggle skippable instructions
Decompile as call…hx:UserDefinedCallDecompile as call
Toggle borderToggleBorderToggle the display of a border between code and data. More…
detect and parse golang metadatagolang:detect_and_parsedetect and parse golang metadata
Open picture in default viewerpicture_search:open_in_viewerOpen picture in default viewer
Save picturepicture_search:save_pictureSave picture
Plugins``
Quick run pluginsQuickRunPluginsQuickly run a plugin

Begin selection

Begin selection. Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor.

To drop the anchor, you can either use the Alt + L key or the Shift + , , , combination, which is more convenient. You can also drop the anchor with the mouse by simply clicking and dragging it.

After you’ve dropped the anchor, you can navigate freely using arrows, etc. Any command that uses the anchor, raises it.

The anchored range is displayed with another color.

When you exit from IDA, the anchor value is lost.

Undo

This command reverts the database to the state before executing the last user action. It is possible to apply Undo multiple times, in this case multiple user actions will be reverted.

Please note the entire database is reverted, including all modifications that were made to the database after executing the user action and including the ones that are not connected to the user action. For example, if a third party plugin modified the database during or after the user action, this modification will be reverted. In theory it is possible to go back in time to the very beginning and revert the database to the state that was present immediately after performing the very first user action. However, in practice the undo buffers overflow because of the changes made by autoanalysis.

Autoanalysis (Options → General… → Analysis) generates copious amounts of undo data. Also, please note that maintaining undo data during autoanalysis slows it down a bit. In practice, it is not a big deal because the limit on the undo data is reached quite quickly (in a matter of minutes). Therefore, if during analysis the user does not perform any actions that modify the database, the undo feature will turn itself off temporarily.

However, if you prefer not to collect undo data at all during the initial autoanalysis, just turn off the UNDO_DURING_AA parameter in ida.cfg.

The configuration file ida.cfg has 2 more undo-related parameters:

ParameterDescriptionDefault
UNDO_MAXSIZEMax size of undo buffers. Once this limit is reached, the undo info about the oldest user action will be forgotten.128MB
UNDO_DEPTHMax number of user actions to remember. If set to 0, the undo feature will be unavailable.1000000

Since there is a limit on the size of undo buffers, any action, even the tiniest, may become non-undoable after some time. This is true because the analysis or plugins may continue to modify the database and overflow the buffers. Some massive actions, like deleting a segment, may be non-undoable just because of the sheer amount of undo data they generate.

Please note that Undo does not affect the state of IDC or Python scripts. Script variables will not change their values because of Undo. Also nothing external to the database can be changed: created files will not be deleted, etc.

Some actions cannot be undone. For example, launching a debugger or resuming from a breakpoint cannot be undone.

Redo

This command reverts the previously issued Undo command. It is possible to use Redo multiple times.

This command also reverts all changes that were done to the database after the last Undo command, including the eventual useful modifications made by the autoanalysis. In other words, the entire database is modified to get to the exact state that it had before executing the last Undo command.

Code

Convert to instruction. This command converts the current unexplored bytes to instruction(s). IDA will warn you if it is not possible.

If you have selected a range using the Anchor action, all the bytes from this range will be converted to instructions.

If you apply this command to an instruction, it will be reanalyzed.

Data

Convert to data. This command converts the current unexplored bytes to data. If it is not possible, IDA will warn you.

Multiple using of this command will change the data type:

 db -> dw -> dd -> float -> dq -> double -> dt -> packreal -> octa \;
 ^                                                                 |;
 \---------<----------------<--------------<-----------------------/;

You may remove some items from this list using the Setup data types… command (action SetupData).

If the target assembler (Options → General… → Analysis) does not support double words or another data type, it will be skipped. To create a structure variable, use the Struct var… command (action DeclareStructVar). To create an array, use the Array… command (action MakeArray). To convert back, use the Undefine command (action MakeUnknown).

Struct var…

Declare a structure variable. IDA will ask you to choose a structure type. You must have some structure types defined in order to use this command. If the target assembler supports it, IDA will display the structure in terse form (using just one line). To uncollapse a terse structure variable use the Unhide command. You can also use this command to declare a structure field in another structure (i.e., nested structures are supported too).

String

Convert to string. This command converts the current unexplored bytes to a string. The set of allowed characters is specified in the configuration file, parameter StrlitChars. Character ‘\0’ is not allowed in any case. If the current assembler (Options → General → Analysis → Target assembler) does not allow characters above 0x7F, characters with high bit set are not allowed. If the anchor has been dropped, IDA will take for the string all characters between the current cursor position and the anchor. Use the anchor if the string starts a disallowed character.

This command also generates a name for the string. In the configuration file, you can specify the characters allowed in names (NameChars). You can change the literal string length using Array… command (action MakeArray). The GUI version allows you to assign a special hotkey to create Unicode strings. To do so, change the value of the StringUnicode parameter in the IDAGUI.CFG file.

Array…

Convert to array. This command allows you to create arrays and change their sizes.

The arrays are created in 2 simple steps:

  1. Create the first element of array using the data definition commands (data, string, structs)

  2. Apply the array command to the created data item. Enter array size in current array elements (not bytes). The suggested array size is the minimum of the following values:

  • the address of the next item with a cross reference
  • the address of the next user-defined name For string literals, you can use this command to change the length of the string.

The dialog box contains the following fields:

  • Items on a line (meaningless for string literals):

    • 0 - place maximal number of items on a line
    • other value - number of items on a line Please note that the margin parameter affects the number of items on a line too.
  • Alignment (meaningless for string literals):

    • -1 - do not align items
    • 0 - align automatically
    • other value - width of each item
  • Signed elements: if checked, IDA treats all elements as signed numbers. Only meaningful for numbers (not for offsets and segments and strings)

  • Display indexes: if checked, IDA will display the indexes of array elements in the form of comments (0,1,2…)

  • Create as array: if not checked, IDA will create a separate item for each array element. Useful for creating huge arrays. If the box is unchecked when this command is applied to string literals, IDA will create many string literals instead of one big string.

If applied to a variable-sized structure, this command is used to specify the overall size of the structure. You cannot create arrays of variable-sized structures.

Undefine

Convert to undefined. This command deletes the current instruction or data, converting it to ‘unexplored’ bytes. IDA will delete the subsequent instructions if there are no more references to them (functions are never deleted).

If you have selected a range using the Anchor action, all the bytes in this range will be converted into ‘unexplored’ bytes. In this case, IDA will not delete any other instructions even if there are no references to them after the deletion.

Rename

Rename the current location. This command gives name/renames/deletes name for the current item.

To delete a name, simply give an empty name.

If the current item is referenced, you cannot delete its name. Even if you try, IDA will generate a dummy name (See Options → Name representation…).

List of available options:

  • Local name: The name is considered to be defined only in the current function. Please note that IDA does not check the uniqueness of the local names in the whole program. However, it does verify that the name is unique for the function.

  • Include in name list: Here you can also include/remove the name from the name list (see the Jump by name… command; action JumpName). If the name is hidden, you will not see it in the names window.

  • Public name: You can declare a name as a public (global) name. If the current assembler supports the “public” directive, IDA will use it. Otherwise, the publicness of the name will be displayed as a comment.

  • Autogenerated name: An autogenerated name will appear in a different color. If the item is indefined, it will disappear automatically.

  • Weak name: You can declare a name as a weak name. If the current assembler supports the “weak” directive, IDA will use it. Otherwise, the weakness of the name will be displayed as a comment.

  • Create name anyway: If this flag is on, and if the specified name already exists, IDA will try to variate the specified name by appending a suffix to it.

Offset (data segment)

Convert the current operand to an offset in the data segment. This command converts the immediate operand of the current instruction/data to an offset from the current data segment (DS). If the current DS value is unknown (or equal 0xFFFF) IDA will warn you - it will beep. In this case, you have to define DS register value for the current byte. The best way to do it is:

  • jump to segment register change point (the Jump to segment register… command; action JumpSegmentRegister),
  • change value of DS (the Change segment register value… command; action SetSegmentRegister)
  • return (the Jump back command; action Return) or you can change default value of DS for the current segment (the Set default segment register value… command; action SetSegmentRegisterDefault).

If you want to delete offset definition, you can use this command again - it works as trigger. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset (current segment)

Convert the current operand to an offset in the current segment. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise, it will be left unmodified. If this command is applied to a structure member in the Local types window, then IDA will create an “automatic offset”. An automatic offset is an offset with the base equal to 0xFFFFFFFF. This base value means that the actual value of the base will be calculated by IDA when a structure instance is created. To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset by (any segment)…

Convert the current operand to an offset in any segment. This command converts the immediate operand of the current instruction/data to an offset from any segment. IDA will ask to choose a base segment for the offset. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. To create offsets to structure members use Offset (struct)… command (action OpStructOffset).

Offset (user-defined)…

Convert the current operand to an offset with any base. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. If the offset base is specified as 0xFFFFFFFF, then IDA will create “an automatic offset”. Automatic offsets mean that the actual value of the base will be calculated by IDA.

The following offset attributes are available:

OptionDescription
Treat the base address as a plain numberif checked, IDA will treat the base address as a number. In this case, IDA will not create a cross-reference to it and the base address will be printed as a number, not as an offset expression.
Offset points past the main objectOffsets of this type point past an object end. They do not cause an object created/deletion.
Use image base as offset baseThese offsets are based on the image base. There is no need to explicitly specify the offset base. These offsets are displayed in a concise form: rva func instead of offset func - imagebase. If you intend to reassemble the output file, execute the following IDC statement: set_inf_attr(INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) & ~INFFL_ALLASM);
Subtract operand valueUse this option when the operand value should be substracted from the base to get the target address. In this case the displayed expression will be displayed as offset base - target instead of the usual offset target - base
Signed operandUse this option if the operand should be interpreted as a signed value. This option is only available for OFF_REF8, OFF_REF16, OFF_REF32 and OFF_REF64 offset types.
Operand value of 0 is invalidIf the operand value is 0, the value will be highlighted in red.
Operand value of NOT 0 is invalidIf the operand value is zero’s complement (i.e. all bits are set), the value will be highlighted in red. For example a OFF_REF16 with an operand value of 0xFFFF would be invalid.
Use the current address as the offset baseThe offset base is dynamically calculated and is equal to the address of the current element: - for standalone items: their start address - for arrays: the start of the array element - for structures: the start of the structure field

The offset expression is displayed in the following concise form: offset target - $ where “$” denotes the start of the element (and is assembler-dependent).

To create offsets to structure members use the Offset (struct)… command (action OpStructOffset).

Offset (struct)…

Convert the current operand to a structure offset. This command permits to convert all immediate operands of instructions in a range selection to a path of offsets through a structure and its possible sub unions. If no selection is active, IDA will simply permit to convert the current operand. In this case, it will display a simple dialog box the same way as the text version (see below). You can select the desired register in the drop-down list: all operands relative to this register will be added to the ‘Offsets’ list. A special empty line in the drop-down list is used to directly work on immediate values. Checkboxes in the ‘Offsets’ list allow you to select which operand you indeed want to modify. By default, IDA will select only undefined operands, to avoid overwriting previous type definitions. This list is sorted by operand value, by instruction address and finally by operand number. You can easily see the instructions related to the operand by moving the mouse over it, and wait for a hint to be displayed. The ‘Structures and Unions’ tree will contain all selectable structures, and sub unions. Once you select or move over a structure, the ‘Offsets’ list updates itself for each checked offset: the computed name of the operand is displayed, according to the selected structure in the tree. An icon is also drawn, to easily know if a specific structure matches the offset or not, or if the offset is too big for the selected structure. The structures who match the most offsets will be near the top of the tree. You can also move your mouse over structures in the tree to obtain an interesting hint. A ‘?’ icon can also appear, if the offset can be specialized by selecting an union member. In this case, if you expand the structure in the tree, you can select the adequate union member simply by checking the desired radio button. IDA automatically corrects the related name in the ‘Offsets’ list. The ‘Offset delta’ value represents the difference between the structure start and the pointer value. For example, if you have an operand 4 and want to convert in into an expression like “mystruct.field_6-2”, then you have to enter 2 as the delta. Usually the delta is zero, i.e. the pointer points to the start of the structure. The ‘Hide sub structures without sub unions’ option (checked by default) avoids to add unnecessary sub structures to the tree, to keep it as small as possible. If you uncheck this option, all sub structures will be added to the tree. By default, IDA displays the structure member at offset 0. To change this behavior, you can directly disable the ‘Force zero offset field’ in the ‘Options’ frame. Later zero offsets can be forced using Edit → Structs → Force zero offset menu item.

Text version

This command converts immediate operand(s) type of the current instruction/data to an offset within the specified structure. Before using this command, you have to define a structure type. First of all, IDA will ask a so-called “struct offset delta”. This value represents the difference between the structure start and the pointer value. For example, if you have an operand 4 and want to convert in into an expression like “mystruct.field_6-2”, then you have to enter 2 as the delta. Usually the delta is zero, i.e. the pointer points to the start of the structure. If a range is selected using the anchor, IDA will perform ‘en masse’ conversion. It will convert immediate operands of all instructions in the selected range to offsets. However, IDA will ask you first the lower and upper limits of immediate operand value. If the an operand value is >= lower limit and <= upper limit then the operand will be converted to offset, otherwise it will be left unmodified. When you use this command, IDA deletes the manually entered operand. If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected. By default IDA doesn’t display the structure member at offset 0. To change this behavior, use the Force zero offset field command. Moreover, if there are several possible representations (this can happen if unions are used), select the desired representation using the Select union member… command.

Number (default)

Convert the current operand to a number. That way, you can delete suspicious mark of the item. The number is represented in the default radix for the current processor (usually hex, but octal for PDP-11, for example). When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Hexadecimal

Convert the current operand to a hexadecimal number. This command converts the immediate operand(s) type of the current instruction/data to a hex number, so that you can delete the suspicious mark of the item. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Decimal

Convert the current operand to a decimal number. This command converts the immediate operand(s) type of the current instruction/data to decimal. Therefore, it becomes a ‘number’. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Octal

Convert the current operand to a octal number. IDA always uses 123o notation for octal numbers even if the current assembler does not support octal numbers. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Binary

Convert the current operand to a binary number. This command makes the current instruction or data operand type binary. IDA always uses 123b notation for binary numbers even if the current assembler does not support binary numbers. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Floating point

Convert to floating point. When you use this command, IDA deletes the manually entered operand (via the Manual… command; action ManualOperand). If the cursor is on the first operand (the cursor is before ‘,’) then the first operand will be affected; otherwise, all other operands will be affected.

Toggle leading zeroes

Toggle leading zeroes.

This command displays or hides the leading zeroes of the current operand. Example: if the instruction looked like this:

    and     ecx, 40h

then after applying the command it will look like this:

    and     ecx, 00000040h

If you prefer to see leading zeroes in all cases, then open the calculator and enter the following expression: set_inf_attr (INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) | INFFL_LZERO); This will toggle the default for the current database and all numbers without leading zeroes will become numbers with leading zeroes, and vice versa. See also Edit|Operand types submenu.

Manual…

Enter the current operand manually. You may specify any string instead of an operand if IDA does not represent the operand in the desired form. In this case, IDA will simply display the specified string in the instruction instead of the default operand.

The current operand (under the cursor) will be affected.

You can use this command not only with instructions but with data items too.

IDA proposes the previous manual operand as the default value in the input form.

To delete the manual operand and revert back to the default text, specify an empty string.

IDA automatically deletes manually entered operands when you change operand representation using Edit → Operand types submenu.

{% hint style=“info” %} A text offset reference is generated if you use a label in the program as the operand string. In other cases no cross-references are generated. {% endhint %}

Enter comment…

Enter a regular comment. If you stand at the function start and your cursor is on a function name, IDA will ask you to enter a function comment. If you stand at the segment start and your cursor is on a segment name, IDA will ask you to enter a segment comment. If this command is issued in the Local types window, it allows you to change the comment of a structure/enum, or structure/enum member. If the cursor is on the structure/enum name, the structure/enum comment will be changed, otherwise the member comment will be changed. Otherwise, this command allows you to enter a normal indented comment for the current item. You can show/hide all comments in Options → General → Disassembly → Display disassembly line parts: Comments.

Enter repeatable comment…

Enter repeatable comment. A repeatable comment will appear attached to the current item and all other items referencing it. If you stand at the function start, IDA will ask you to enter a function comment. If this command is issued in the Local types window, it allows you to change the comment of a structure/enum, or structure/enum member. If the cursor is on the structure/enum name, the structure/enum comment will be changed, otherwise the member comment will be changed. Otherwise, this command allows you to enter a repeatable comment for the current item.

{% hint style=“info” %} You cannot enter repeatable segment comments. {% endhint %}

All items that refer to the current item will have this comment by default. Note that if you have defined both comment types (regular and repeatable), the regular comment will be displayed for the current item and the repeatable comment will be displayed for all items that refer to the current item, if they do not have their own comments. The repeatable comments may be used to describe subroutines, data items, etc., because all calls to the subroutine will have the repeatable comment. You can show/hide all comments in Options → General → Disassembly → Display disassembly line parts: Comments.

Enter anterior lines…

Enter lines preceding the generated lines. If you want to enter multi-line comments or additional instructions, you can use this feature of IDA.

There are two kinds of extra lines: the ones generated before the instruction line and the ones generated after the instruction line.

Do not forget that the maximal number of lines for an item is 500.

IDA does not insert a comment symbol at the beginning of the lines.

Create segment…

This command allows you to create a new segment.

If you select a range using the anchor, IDA will propose the start address and the end address of the selection as defaults for the segment bounds.

You need to specify at least:

  • the segment start address
  • the segment end address (excluded from the range)
  • the segment base

Click here to learn about addressing model used in IDA.

If “sparse storage” is set, IDA will use special sparse storage method for the segment. This method is recommended for huge segments. Later, it is possible to change the storage method of any region using set_storage_type IDC function.

If another segment already exists at the specified address, the existing segment is truncated and the new segment lasts from the specified start address to the next segment (or specified end address, whichever is lower). If the old and the new segments have the same base address, instructions/data will not be discarded by IDA. Otherwise, IDA will discard all instructions/data of the new segment.

An additional segment may be created by IDA to cover the range after the end of the new segment.

Edit segment…

Edit segment attributes. This command opens the Change segment attributes dialog.

Change segment attributes dialog

Change segment attributes options

{% hint style=“info” %} Changing the segment class may change the segment type. {% endhint %}

  • Move Adjacent Segments: means that the previous and next segments will be shrunk or expanded to fill gaps between segments. Click here for more information.

  • Disable Addresses: if set, when a segment is shrunk, all information about bytes going out of the segment will be completely removed.. Otherwise, IDA will discard information about instructions/data, comments etc, but will retain byte values so that another segment can be created later and it will use the existing byte values.

If IDA creates 2 segments where only one segment must exist, you may try the following sequence:

  • Delete one segment (action KillSegment). Choose one with bad segment base value. Do not disable addresses occupied by the segment being deleted.
  • Change bounds of another segment. Note that the Create segment… command (action CreateSegment) changes the boundaries of the overlapping segment automatically.

Segments with the “debugger” attribute are the segments whose memory contents are not saved in the database. Usually, these segments are created by the debugger to reflect the current memory state of the program.

However, the user can modify this attribute.

If it is cleared, then the segment will permanently stay in the database after closing the debugger session. The database will reflect the state of the segment which was at the time when the status is changed.

If it is set, then the segment will become a temporary segment and will be deleted at the end of the debugging session.

The debugger segment checbkox is available only during debugging sessions.

The “loader” segments are the segment created by the file loader. The segment having this attribute are considered to be part of the input file.

A segment with the “debugger” attribute set and the “loader” attribute not set is considered to be an ephemeral segment. Such segments are not analyzed automatically by IDA.

“Segment permissions” group box can be used to modify Segment access permissions (Read/Write/Execute)

Segment Name

Enter a new name for the segment. A segment name is up to 8 characters long. IDA does check if the length is ok. Try to give mnemonic names for the segments.

Class Name

The segment class name identifies the segment with a class name (such as CODE, FAR_DATA, or STACK). The linker places segments with the same class name into a contiguous range of memory in the runtime memory map.

Changing the segment class changes only the segment definition on the screen. There are the following predefined segment class names:

Segment classDescription
CODEPure code
DATAPure data
CONSTPure data
BSSUninitialized data
STACKUninitialized data
XTRNExtern definitions segment

If you change segment class and the segment type is “Regular”, then the segment type will be changed accordingly.

In order to set the segment type “Regular”, you should change the segment class to “UNK”.

{% hint style=“info” %} Segment class names are never deleted. Once you define a segment class name, you cannot reuse it as a name of another object. {% endhint %}

Segment bitness

You can choose between 16-bit and 32-bit segment addressing.

IDA will delete all instructions and data in the segment if the segment address is changed.

Never do it if you are not sure. It may have irreversible consequences, all instructions/data will be converted to undefined bytes.

Segment Alignment

You can specify the segment alignment for the selected segment. By default, IDA assumes ‘byte’ alignment.

Changing the alignment changes only the segment definition on the screen. Nothing else will happen.

Segment Combination

A field that describes how the linker can combine the segment with other segments. Under MS-DOS, segments with the same name and class can be combined in two ways: they can be concatenated to form one logical segment, or they can be overlapped. In the latter case, they have either the same start address or the same end address, and they describe a common range in memory. Values for the field are:

  • Private: Do not combine with any other program segment.
  • Public: Combine by appending at an offset that meets the alignment requirement.
  • Stack: Combine as for Public. This combine type forces byte alignment.
  • Common: Combine by overlay using maximum size.

Changing segment combination changes only the segment definition on the screen. Nothing else will happen.

Delete segment…

Delete segment. IDA will ask your the permission to disable the addresses occupied by the segment. If you allow this operation, all information about the segment will be deleted. In other words, IDA will discard the information about instructions or data, comments etc.

If you check the “disable addresses” checkbox, IDA will mark the addresses occupied by the segment as “nonexistent” in the program. You will lose ALL information, including byte values.

It is impossible to disassemble the content of addresses not located in any segment, therefore you must create a new segment if you want to resume the disassembly of that part of the code.

You can also edit an adjacent segment to expand it to those addresses (Edit → Segments → Edit segment…).

IDA will ask your the permission to disable addresses occupied by the segment. If you give your permission, information about the segment will be deleted, otherwise IDA will discard information about instruction/data, comments etc, but retain byte values so that you will be able to create another segment afterwards. To disassemble the addresses occupied by the segment, you need to create a new segment again (i.e. you cannot disassemble bytes without a segment). You can also expand another adjacent segment to these addresses.

Move current segment…

Change the current segment boundaries. This command open the Move segment dialog and allows you to move segment(s) to another address. Use it if the segment(s) are loaded at a wrong address. This command shifts (moves) the selected segments in the memory to the target address. There must be enough free space at the target address for the segments. All information in the segment will be moved to the new address, but since the addresses change, the disassembly might be not valid anymore (especially if the program is moved to the wrong addresses and the relocation information is not available).

Fix up the relocated segment

This option allows IDA to modify the references to/from the relocated segment(s). If it is turned off, the references might be wrong after the move.

Rebase program…

Rebase program. The whole program will be shifted by the specified amount of bytes in the memory. The following options are available (we strongly recommend to leave them turned on):

  • Fix up relocations: This option allows IDA to modify the references to/from the relocated segment(s). If it is turned off, the references might be wrong after the move.
  • Rebase the whole image: This option is accessible only if the whole program is selected. It allows IDA to adjust internal variables on the whole program.

Please note rebasing the program might remove user-defined xrefs.

Change segment register value…

Change segment register value. Relevant only for processors with the segment registers. Currently this command works for IBM PC, TMS320C2, Intel80196, and PowerPC processors. This command creates or updates a segment register change point. See also the Jump to segment register… command (action JumpSegmentRegister) for more info.

Set default segment register value…

Set default segment register value. Relevant only for processors with the segment registers. You can specify a default value of a segment register for the current segment. When you change the default value, IDA will reanalyze the segment, taking the default value when it cannot determine the actual value of the register. This takes time, so do not be surprised if references are not corrected immediately.

To specify a value other than the default value of a segment register, you can use the Change segment register value… command (action SetSegmentRegister).

Struct var…

Declare a structure variable. IDA will ask you to choose a structure type. You must have some structure types defined in order to use this command. If the target assembler supports it, IDA will display the structure in terse form (using just one line). To uncollapse a terse structure variable use the Unhide command. You can also use this command to declare a structure field in another structure (i.e., nested structures are supported too).

Force zero offset field

Toggle display of the first field of a structure in an offset expression. This command forces IDA to display a full structure member name even if the offset of the member is equal to zero.

If used twice, the command cancels itself.

Example: Suppose we have the following structure:

    xxx     struc
    a       db ?
    b       db ?
    c       db ?
    xxx     ends

    dloc    xxx ?

Normally IDA displays references to it like this:

    mov     eax, offset dloc
    mov     eax, offset dloc.b

If you force IDA, then it displays member ‘a’:

    mov     eax, offset dloc.a
    mov     eax, offset dloc.b

Select union member…

Choose the representation of a union member. This command tells IDA how to display references to a union from the current cursor location.

Example: Suppose we have the following union:

        xxx     union
        a       db ?
        b       dw ?
        c       dd ?
        ends   xxx
        dloc    xxx ?

Normally, IDA displays references to “dloc” like this:

        mov     al,  byte ptr dloc
        mov     eax, word ptr dloc

After using this command, IDA can display the union members:

        mov     al,  dloc.b
        mov     eax, dloc.d 

Create struct from selection

This command defines a new structure from data already defined. The new structure is created with adequate data types, and each member uses the current data name if it is available.

This command is available only in the graphical version of IDA.

Copy field info to pointers

Copy field info to pointed addresses. This command scans the current struct variable and renames the locations pointed by offset expressions unless they already have a non-dummy name.

It also copies the type info from the struct members to pointed locations.

Create function…

Create a new function in the disassembly. You can specify function boundaries using the anchor. If you don’t specify any, IDA will try to find the boundaries automatically:

  • function start point is equal to the current cursor position;
  • function end point is calculated by IDA.

A function cannot contain references to undefined instructions. If a function has already been defined at the specified addresses, IDA will jump to its start address, showing you a warning message. A function must start with an instruction.

Edit function…

Edit function attributes - change function properties, including bounds, name, flags, and stack frame parameters. This command opens an Edit Function dialog, and allows you to modify function characteristics and stack frame structure. If the current address does not belong to any function, IDA will beep.

Edit function dialog

To change only the function end address, use the FunctionEnd command instead. This command allows you to change the function frame parameters too. You can change sizes of some parts of frame structure.

Stack Frame Structure

IDA represents the stack using the following structure:

Stack SectionPointer
function arguments-
return address-
saved registers (SI, DI, etc)← BP
local variables← SP

{% hint style=“info” %} For some processors or functions, BP may equal SP, meaning it points to the bottom of the stack frame. {% endhint %}

You may specify the number of bytes in each part of the stack frame. The size of the return address is calculated by IDA (possibly depending on the far function flag).

           push    ebp
           lea     ebp, [esp-78h]
           sub     esp, 588h
           push    ebx
           push    esi
           lea     eax, [ebp+74h]

      +------------------------------+
      | function arguments           |
      +------------------------------+
      | return address               |
      +------------------------------+
      | saved registers (SI,DI,etc)  |
      +------------------------------+  <- typical BP
      |                              |
      |                              |
      |                              |  <- actual BP
      | local variables              |
      |                              |
      |                              |
      |                              |
      +------------------------------+  <- SP

In our example, the saved registers area is empty (since EBP has been initialized before saving EBX and ESI). The difference between the ‘typical BP’ and ‘actual BP’ is 0x78 and this is the value of FPD.

After specifying FPD=0x78 the last instruction of the example becomes

           lea     eax, [ebp+78h+var_4]

where var_4 = -4

Most of the time, IDA calculates the FPD value automatically. If it fails, the user can specify the value manually.

If the value of the stack pointer is modified in an unpredictable way, (e.g. “and esp, -16”), then IDA marks the function as “fuzzy-sp”.

If this command is invoked for an imported function, then a simplified dialog box will appear on the screen.

See also:

Configurable Parameters

  • Stack Frame Sizes: You can specify the number of bytes in each part of the stack frame. The return address size is calculated automatically by IDA (may depend on the far function flag).
  • Purged Bytes: Specifies the number of bytes added to SP upon function return. This value calculates SP changes at call sites (used in calling conventions such as __stdcall in Windows 32-bit programs).
  • BP Based Frame: Enables IDA to automatically convert [BP+xxx] operands to stack variables.
  • BP Equal to SP: Indicates that the frame pointer points to the bottom of the stack. Commonly used for processors that set up the stack frame with EBP and ESP both pointing to the bottom (e.g., MC6816, M32R).
  • Reanalysis: Pressing Enter without changing any parameter will cause IDA to reanalyze the function.

Append function tail…

This command appends an arbitrary range of the program to a function definition. A range must be selected before applying this command. This range must not intersect with other function chunks (however, an existing tail can be added to multiple functions).

IDA will ask to select the parent function for the selection and will append the range to the function definition.

Remove function tail…

Remove function tail. This command removes the function tail at the cursor from a function definition. If there are several parent functions for the current function tail range, IDA will ask to select the parent function(s) to remove the tail from. After the confirmation, the current function tail range will be removed from the selected function definition. If the parent was the only owner of the current tail, then the tail will be destroyed. Otherwise it will still be present in the database. If the removed parent was the owner of the tail, then another function will be selected as the owner.

Change stack pointer…

Change stack pointer. This command allows you to specify how the stack pointer (SP) is modified by the current instruction.

You cannot use this command if the current instruction does not belong to any function.

You will need to use this command only if IDA was not able to trace the value of the SP register. Usually IDA can handle it but in some special cases it fails. An example of such a situation is an indirect call of a function that purges its parameters from the stack. In this case, IDA has no information about the function and cannot properly trace the value of SP.

Please note that you need to specify the difference between the old and new values of SP.

The value of SP is used if the current function accesses local variables by [ESP+xxx] notation.

See also how to convert to stack variable (Action OpStackVariable).

Rename register…

Rename a general processor register. This command allows you to rename a processor general register to some meaningful name. While this is not used very often on IBM PCs, it is especially useful on RISC processors with lots of registers. For example, a general register R9 is not very meaningful and a name like ‘CurrentTime’ is much better.

This command can be used to define a new register name as well as to remove it. Just move the cursor on the register name and press enter. If you enter the new register name as an empty string, then the definition will be deleted.

If you have selected a range before using this command, then the definition will be restricted to the selected range. But in any case, the definition cannot cross the function boundaries.

You cannot use this command if the current instruction does not belong to any function.

Set type…

Set type information for an item or current function. This command allows you to specify the type of the current item. If the cursor is located on a name, the type of the named item will be edited. Otherwise, the current function type (if there is a function) or the current item type (if it has a name) will be edited.

The function type must be entered as a C declaration. Hidden arguments (like ‘this’ pointer in C++) should be specified explicitly. IDA will use the type information to comment the disassembly with the information about function arguments. It can also be used by the Hex-Rays decompiler plugin for better decompilation. Here is an example of a function declaration:

    int main(int argc, const char *argv[]);

It is also possible to specify a function name coming from a type library. For example, if entering “LoadLibraryW” would yield its prototype:

    HMODULE __stdcall LoadLibraryW(LPCWSTR lpLibFileName);

provided that the corresponding type library is in memory. To delete a type declaration, just enter an empty string. IDA supports the user-defined calling convention. In this calling convention, the user can explicitly specify the locations of arguments and the return value. For example:

    int __usercall func@<ebx>(int x, int y@<esi>);

denotes a function with 2 arguments: the first argument is passed on the stack (IDA automatically calculates its offset) and the second argument is passed in the ESI register and the return value is stored in the EBX register. Stack locations can be specified explicitly:

    int __usercall runtime_memhash@<^12.4>(void *p@<^0.4>, int q@<^4.4>, int r@<^8.4>)

There is a restriction for a __usercall function type: all stack locations should be specified explicitly or all are automatically calculated by IDA. General rules for the user defined prototypes are:

  • the return value must be in a register. Exception: stack locations are accepted for the __golang and __usercall calling conventions.

  • if the return type is ‘void’, the return location must not be specified

  • if the argument location is not specified, it is assumed to be on the stack; consequent stack locations are allocated for such arguments

  • it is allowed to declare nested declarations, for example: int **__usercall func16@(int *(__usercall *x)@ (int, long@, int)@);

    Here the pointer “x” is passed in the ESI register; The pointed function is a usercall function and expects its second argument in the ECX register, its return value is in the EBX register. The rule of thumb to apply in such complex cases is to specify the the registers just before the opening brace for the parameter list.

  • registers used for the location names must be valid for the current processor; some registers are unsupported (if the register name is generated on the fly, it is unsupported; inform us about such cases; we might improve the processor module if it is easy)

  • register pairs can be specified with a colon like edx:eax

  • for really complicated cases this syntax can be used. IDA also understands the “__userpurge” calling convention. It is the same thing as __usercall, the only difference is that the callee cleans the stack.

The name used in the declaration is ignored by IDA. If the default calling convention is __golang then explicit specification of stack offsets is permitted. For example:

  __attribute__((format(printf,2,3)))
  int myprnt(int id, const char *format, ...);

This declaration means that myprnt is a print-like function; the format string is the second argument and the variadic argument list starts at the third argument.

Below is the full list of attributes that can be handled by IDA.

AttributeDescription
packedpack structure/union fields tightly, without gaps
alignedspecify the alignment
noreturndeclare as not returning function
ms_structuse microsoft layout for the structure/union
formatpossible formats: printf, scanf, strftime, strfmon

Data Declaration Keywords

For data declarations, the following custom __attribute((annotate(X))) keywords have been added. The control the representation of numbers in the output:

KeywordDescription
__binunsigned binary number
__octunsigned octal number
__hexunsigned hexadecimal number
__decsigned decimal number
__sbinsigned binary number
__soctsigned octal number
__shexsigned hexadecimal number
__udecunsigned decimal number
__floatfloating point
__charcharacter
__segmsegment name
__enum()enumeration member (symbolic constant)
__offoffset expression (a simpler version of __offset)
__offset()offset expression
__strlit()string
__stroff()structure offset
__custom()custom data type and format
__invsigninverted sign
__invbitsinverted bitwise
__lzeroadd leading zeroes
__tabform()tabular form

Type Declaration Keywords

The following additional keywords can be used in type declarations:

KeywordDescription
_BOOL1a boolean type with explicit size specification (1 byte)
_BOOL2a boolean type with explicit size specification (2 bytes)
_BOOL4a boolean type with explicit size specification (4 bytes)
__int8a integer with explicit size specification (1 byte)
__int16a integer with explicit size specification (2 bytes)
__int32a integer with explicit size specification (4 bytes)
__int64a integer with explicit size specification (8 bytes)
__int128a integer with explicit size specification (16 bytes)
_BYTEan unknown type; the only known info is its size: 1 byte
_WORDan unknown type; the only known info is its size: 2 bytes
_DWORDan unknown type; the only known info is its size: 4 bytes
_QWORDan unknown type; the only known info is its size: 8 bytes
_OWORDan unknown type; the only known info is its size: 16 bytes
_TBYTE10-byte floating point value
_UNKNOWNno info is available
__purepure function: always returns the same value and does not modify memory in a visible way
__noreturnfunction does not return
__usercalluser-defined calling convention; see above
__userpurgeuser-defined calling convention; see above
__golanggolang calling convention
__swiftcallswift calling convention
__spoilsexplicit spoiled-reg specification; see above
__hiddenhidden function argument; this argument was hidden in the source code (e.g. ‘this’ argument in c++ methods is hidden)
__return_ptrpointer to return value; implies hidden
__struct_ptrwas initially a structure value
__array_ptrwas initially an array
__unusedunused function argument
__cppobja c++ style struct; the struct layout depends on this keyword
__ptr32explicit pointer size specification (32 bits)
__ptr64explicit pointer size specification (64 bits)
__shiftedshifted pointer declaration
__highhigh level prototype (does not explicitly specify hidden arguments like ‘this’, for example) this keyword may not be specified by the user but IDA may use it to describe high level prototypes
__bitmaska bitmask enum, a collection of bit groups
__tuplea tuple, a special kind of struct. tuples behave like structs but have more relaxed comparison rules: the field names and alignments are ignored.

Change byte…

Change program bytes. You can modify the executable file and eventually generate a new file (the Create EXE file… command; action ProduceExe). If you patch bytes, then you may enter multiple bytes (see also Binary string format). If this command is invoked when the debugger is active, then IDA will modify the memory and the database. If the database does not contain the patched bytes, then only the process memory will be modified. You can create a difference file too (the Create DIFF file… command; action ProduceDiff). See also How to Enter a Number.

Assemble…

This command allows you to assemble instructions. Currently, only the IBM PC processors provide an assembler, nonetheless, plugin writers can extend or totally replace the built-in assembler by writing their own.

The assembler requires to enclose all memory references into square brackets. For example:

        mov ax, [counter]

Also, the keyword ‘offset’ must not be used. Instead of

        mov eax, offset name

you must write

        mov eax, name

See also How to Enter a Number.

Patched bytes

Open the Patched bytes window. The Patched bytes view shows the list of the patched locations in the database. It also allows you to revert modifications selectively.

Patched bytes view

Reverting changes

Select location(s) and click Revert… from the context menu to revert this modification.

Patching bytes

You can change individual bytes via Edit → Patch program → Change byte….

Apply patches to input file…

Apply previously patched bytes back to the input file. If the “Restore” option is selected, then the original bytes will be applied to the input file.

See also ProduceDiff action.

Create alignment directive…

Create alignment directive. The alignment directive will replace a number of useless bytes inserted by the linker to align code and data to paragraph boundary or any other address which is equal to a power of two. You can select a range to be converted to an alignment directive. If you have selected a range, IDA will try to determine a correct alignment automatically.

There are at least two requirements for this command to work:

  • There must be enough unexplored bytes at the current address.
  • An alignment directive must always end at an address which is divisible by a power or two.

Manual instruction…

Specify alternate representation of the current instruction. Use it if IDA cannot represent the current instruction as desired. If the instruction itself is ok and only one operand is misrepresented, then use Manual… command (action ManualOperand). To delete the manual representation, specify an empty string.

Color instruction…

This command allows you to specify the background color for the current instruction or data item. Only GUI version supports different background colors. Specifying a non-defined custom color will reset the instruction color.

Toggle border

Toggle the display of a border between code and data. This command allows you to hide a thin border which is like the one generated automatically by IDA between instructions and data. If the border was already hidden, then it is displayed again.

Edit menu actions for Functions View

{% hint style=“info” %} The options below appear when the Edit menu is opened from the Functions View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Create folder…DirTreeCreateFolderCreate folder with items
Insert…DirTreeInsertCreate a structure, union, or enumeration
Delete function(s)…DirTreeDeleteDelete a type
Edit function…DirTreeEditOpen type editor for type
UndoUndoActionThis command reverts the database to the state before executing the last user action. More…
RedoRedoActionThis command reverts the previously issued Undo command. More…
CopyDirTreeCopyCopy
Copy allDirTreeCopyAllCopy all
UnsortDirTreeUnsortUnsort
Quick filterDirTreeQuickFilterQuick filter
Modify filters…DirTreeModifyFiltersModify filters
Reset filtersDirTreeResetFiltersReset filters

Undo

This command reverts the database to the state before executing the last user action. It is possible to apply Undo multiple times, in this case multiple user actions will be reverted.

Please note the entire database is reverted, including all modifications that were made to the database after executing the user action and including the ones that are not connected to the user action. For example, if a third party plugin modified the database during or after the user action, this modification will be reverted. In theory it is possible to go back in time to the very beginning and revert the database to the state that was present immediately after performing the very first user action. However, in practice the undo buffers overflow because of the changes made by autoanalysis.

Autoanalysis (Options → General… → Analysis) generates copious amounts of undo data. Also, please note that maintaining undo data during autoanalysis slows it down a bit. In practice, it is not a big deal because the limit on the undo data is reached quite quickly (in a matter of minutes). Therefore, if during analysis the user does not perform any actions that modify the database, the undo feature will turn itself off temporarily.

However, if you prefer not to collect undo data at all during the initial autoanalysis, just turn off the UNDO_DURING_AA parameter in ida.cfg.

The configuration file ida.cfg has 2 more undo-related parameters:

ParameterDescriptionDefault
UNDO_MAXSIZEMax size of undo buffers. Once this limit is reached, the undo info about the oldest user action will be forgotten.128MB
UNDO_DEPTHMax number of user actions to remember. If set to 0, the undo feature will be unavailable.1000000

Since there is a limit on the size of undo buffers, any action, even the tiniest, may become non-undoable after some time. This is true because the analysis or plugins may continue to modify the database and overflow the buffers. Some massive actions, like deleting a segment, may be non-undoable just because of the sheer amount of undo data they generate.

Please note that Undo does not affect the state of IDC or Python scripts. Script variables will not change their values because of Undo. Also nothing external to the database can be changed: created files will not be deleted, etc.

Some actions cannot be undone. For example, launching a debugger or resuming from a breakpoint cannot be undone.

Redo

This command reverts the previously issued Undo command. It is possible to use Redo multiple times.

This command also reverts all changes that were done to the database after the last Undo command, including the eventual useful modifications made by the autoanalysis. In other words, the entire database is modified to get to the exact state that it had before executing the last Undo command.

Edit menu actions for Local Types View

{% hint style=“info” %} The options below appear when the Edit menu is opened from the Local Types View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameApplies toDescription
CopyEditCopyEnum, Structure, TypedefCopy
Copy full type(s)CopyFullTypeEnum, Structure, TypedefCopies the full type(s) and its dependencies
UndoUndoActionEnum, Structure, TypedefThis command reverts the database to the state before executing the last user action. More…
RedoRedoActionEnum, Structure, TypedefThis command reverts the previously issued Undo command. More…
Add type…TilAddTypeEnum, Structure, TypedefCreate a structure, union, or enumeration
Delete type…TilDelTypeEnum, Structure, TypedefDelete a type
Edit type…TilEditTypeEnum, Structure, TypedefOpen type editor for type
Add enum member…MakeDataEnum, StructureConvert to data. More…
Delete type memberTilDelTypeMemberEnum, StructureDelete a type member
Change calling convention…FuncChangeCCEnumChange calling convention
RenameMakeNameEnum, Structure, TypedefRename the current location. More…
Edit enum member…TilEditConstEnumEdit a symbolic constant
Edit location…EditArglocEnumEdit argument location
Show arguments locationToggleArglocEnumShow arguments location
Enter comment…TilMakeCommentEnum, Structure, TypedefEnter a comment
Toggle leading zeroesToggleLeadingZeroesEnum, StructureToggle leading zeroes. More…
C-like formatTilCSyntaxEnum, Structure, TypedefToggle between assembly & C-like representation

Undo

This command reverts the database to the state before executing the last user action. It is possible to apply Undo multiple times, in this case multiple user actions will be reverted.

Please note the entire database is reverted, including all modifications that were made to the database after executing the user action and including the ones that are not connected to the user action. For example, if a third party plugin modified the database during or after the user action, this modification will be reverted. In theory it is possible to go back in time to the very beginning and revert the database to the state that was present immediately after performing the very first user action. However, in practice the undo buffers overflow because of the changes made by autoanalysis.

Autoanalysis (Options → General… → Analysis) generates copious amounts of undo data. Also, please note that maintaining undo data during autoanalysis slows it down a bit. In practice, it is not a big deal because the limit on the undo data is reached quite quickly (in a matter of minutes). Therefore, if during analysis the user does not perform any actions that modify the database, the undo feature will turn itself off temporarily.

However, if you prefer not to collect undo data at all during the initial autoanalysis, just turn off the UNDO_DURING_AA parameter in ida.cfg.

The configuration file ida.cfg has 2 more undo-related parameters:

ParameterDescriptionDefault
UNDO_MAXSIZEMax size of undo buffers. Once this limit is reached, the undo info about the oldest user action will be forgotten.128MB
UNDO_DEPTHMax number of user actions to remember. If set to 0, the undo feature will be unavailable.1000000

Since there is a limit on the size of undo buffers, any action, even the tiniest, may become non-undoable after some time. This is true because the analysis or plugins may continue to modify the database and overflow the buffers. Some massive actions, like deleting a segment, may be non-undoable just because of the sheer amount of undo data they generate.

Please note that Undo does not affect the state of IDC or Python scripts. Script variables will not change their values because of Undo. Also nothing external to the database can be changed: created files will not be deleted, etc.

Some actions cannot be undone. For example, launching a debugger or resuming from a breakpoint cannot be undone.

Redo

This command reverts the previously issued Undo command. It is possible to use Redo multiple times.

This command also reverts all changes that were done to the database after the last Undo command, including the eventual useful modifications made by the autoanalysis. In other words, the entire database is modified to get to the exact state that it had before executing the last Undo command.

Add enum member…

Convert to data. This command converts the current unexplored bytes to data. If it is not possible, IDA will warn you.

Multiple using of this command will change the data type:

 db -> dw -> dd -> float -> dq -> double -> dt -> packreal -> octa \;
 ^                                                                 |;
 \---------<----------------<--------------<-----------------------/;

You may remove some items from this list using the Setup data types… command (action SetupData).

If the target assembler (Options → General… → Analysis) does not support double words or another data type, it will be skipped. To create a structure variable, use the Struct var… command (action DeclareStructVar). To create an array, use the Array… command (action MakeArray). To convert back, use the Undefine command (action MakeUnknown).

Rename

Rename the current location. This command gives name/renames/deletes name for the current item.

To delete a name, simply give an empty name.

If the current item is referenced, you cannot delete its name. Even if you try, IDA will generate a dummy name (See Options → Name representation…).

List of available options:

  • Local name: The name is considered to be defined only in the current function. Please note that IDA does not check the uniqueness of the local names in the whole program. However, it does verify that the name is unique for the function.

  • Include in name list: Here you can also include/remove the name from the name list (see the Jump by name… command; action JumpName). If the name is hidden, you will not see it in the names window.

  • Public name: You can declare a name as a public (global) name. If the current assembler supports the “public” directive, IDA will use it. Otherwise, the publicness of the name will be displayed as a comment.

  • Autogenerated name: An autogenerated name will appear in a different color. If the item is indefined, it will disappear automatically.

  • Weak name: You can declare a name as a weak name. If the current assembler supports the “weak” directive, IDA will use it. Otherwise, the weakness of the name will be displayed as a comment.

  • Create name anyway: If this flag is on, and if the specified name already exists, IDA will try to variate the specified name by appending a suffix to it.

Toggle leading zeroes

Toggle leading zeroes.

This command displays or hides the leading zeroes of the current operand. Example: if the instruction looked like this:

    and     ecx, 40h

then after applying the command it will look like this:

    and     ecx, 00000040h

If you prefer to see leading zeroes in all cases, then open the calculator and enter the following expression: set_inf_attr (INF_GENFLAGS, get_inf_attr(INF_GENFLAGS) | INFFL_LZERO); This will toggle the default for the current database and all numbers without leading zeroes will become numbers with leading zeroes, and vice versa. See also Edit|Operand types submenu.

Jump

Jump menu actions for IDA View

{% hint style=“info” %} The options below appear when the Jump menu is opened from the IDA View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Jump to operandJumpEnterJump to the specified address. More…
Jump in a new windowJumpEnterNewJump in a new window
Jump to previous positionReturnReturn to the previous saved position. More…
Jump to next positionUndoReturnGo to the next saved position. More…
Empty navigation stackEmptyStackRemove everything from the jumps stack
Jump to pseudocodehx:JumpPseudoJump to pseudocode
Jump to address…JumpAskJump to the specified address. More…
Jump by name…JumpNameJump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. More…
Jump to function…JumpFunctionJump to the selected function. This command shows you a list of functions: you can jump to the selected one by pressing Enter.
Jump to segment…JumpSegmentJump to the selected segment. More…
Jump to segment register…JumpSegmentRegisterJump to the selected segment register change point. More…
Jump to problem…JumpQJump to the selected problematic location. More…
List cross references to…JumpXrefJump to the selected cross reference
List cross references from…JumpXrefFromJump to a cross reference from current location
Jump to xref to operand…JumpOpXrefJump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. More…
Jump to entry point…JumpEntryPointThis command shows you a list of entry points: you can jump to the selected one by pressing Enter. More…
Jump to file offset…JumpFileOffsetJump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: More…
Mark position…MarkPositionRemember the current position in the disassembly. More…
Jump to marked position…JumpPositionJump to the selected marked position. More…
Clear mark…ClearMarkClear mark

Jump to operand

Jump to the specified address. By pressing Enter you navigate in the program in the same way as in a hypertext (the way the web browsers and help screens use). This is the easiest way to explore the program: just position the cursor at the desired name and press JumpEnter. Your current address is saved in the jump stack. The Jump to previous position command (action Return, usually Esc) will return you back. If the cursor is at a stack variable, a window with stack variables is opened and the definition of the stack variable is displayed.

Jump to previous position

Return to the previous saved position. It takes positions from Jumps Stack.

Jump to next position

Go to the next saved position. This command cancels the last Jump to previous position command.

Jump to address…

Jump to the specified address. This command jumps to the specified address in the program. IDA will ask you for the target address. You can enter a name or an address as a hexadecimal number with or without a segment. If you enter a valid address then:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

The Jump to previous position command ( action Return, usually Esc) will return you back. In the structure and enum views, the cursor will be moved to the corresponding offset in the current type.

See also How to enter an address

Jump by name…

Jump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. IDA will display the list of the names (sorted by addresses) and you can choose a name. Dummy names (generated by IDA) are not listed. Hidden names are not listed either. You can control which names are listed in the Names representation dialog box (Action SetNameType, Options → Name representation…).

See also How to use the lister.

Jump to segment…

Jump to the selected segment. IDA will ask you to select the target segment. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. See also: How to choose a segment.

Jump to segment register…

Jump to the selected segment register change point. IDA will ask you to select a target change point, and after:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

Jump to problem…

Jump to the selected problematic location. IDA will display the Problems List and will allow you to select a problem. The Jump to previous position command (action Return, usually Esc)(usually Esc) will return you back.

Jump to xref to operand…

Jump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. See also the description of the cross references window.

Jump to entry point…

This command shows you a list of entry points: you can jump to the selected one by pressing Enter.

The list of entry points is created at the database creation time. It is not modified after that (for example, renaming an exported function does not change the list of entry points).

Jump to file offset…

Jump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: the current address is saved in the jump stack. the cursor is positioned to the corresponding address. The Jump to previous position command (action Return, usually Esc) will return you back.

Mark position…

Remember the current position in the disassembly. You can mark certain locations of the file to be able to jump to them quickly (use the Jump to marked position… command). Text description of the location may help to find a desired location easily. First select a slot for the mark, then enter a description for the location.

Jump to marked position…

Jump to the selected marked position.

IDA will ask you to select a target position. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. You can mark the position using the Jump to marked position… command (action JumpPosition).

Jump menu actions for Pseudocode View

{% hint style=“info” %} The options below appear when the Jump menu is opened from the Pseudocode View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Jump to operandJumpEnterJump to the specified address. More…
Jump in a new windowJumpEnterNewJump in a new window
Jump to previous positionReturnReturn to the previous saved position. More…
Jump to next positionUndoReturnGo to the next saved position. More…
Empty navigation stackEmptyStackRemove everything from the jumps stack
Jump to pseudocodehx:JumpPseudoJump to pseudocode
Jump to address…JumpAskJump to the specified address. More…
Jump by name…JumpNameJump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. More…
Jump to function…JumpFunctionJump to the selected function. This command shows you a list of functions: you can jump to the selected one by pressing Enter.
Jump to segment…JumpSegmentJump to the selected segment. More…
Jump to segment register…JumpSegmentRegisterJump to the selected segment register change point. More…
Jump to problem…JumpQJump to the selected problematic location. More…
List cross references to…JumpXrefJump to the selected cross reference
List cross references from…JumpXrefFromJump to a cross reference from current location
Jump to xref to operand…JumpOpXrefJump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. More…
Jump to entry point…JumpEntryPointThis command shows you a list of entry points: you can jump to the selected one by pressing Enter. More…
Jump to file offset…JumpFileOffsetJump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: More…
Mark position…MarkPositionRemember the current position in the disassembly. More…
Jump to marked position…JumpPositionJump to the selected marked position. More…
Clear mark…ClearMarkClear mark

Jump to operand

Jump to the specified address. By pressing Enter you navigate in the program in the same way as in a hypertext (the way the web browsers and help screens use). This is the easiest way to explore the program: just position the cursor at the desired name and press JumpEnter. Your current address is saved in the jump stack. The Jump to previous position command (action Return, usually Esc) will return you back. If the cursor is at a stack variable, a window with stack variables is opened and the definition of the stack variable is displayed.

Jump to previous position

Return to the previous saved position. It takes positions from Jumps Stack.

Jump to next position

Go to the next saved position. This command cancels the last Jump to previous position command.

Jump to address…

Jump to the specified address. This command jumps to the specified address in the program. IDA will ask you for the target address. You can enter a name or an address as a hexadecimal number with or without a segment. If you enter a valid address then:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

The Jump to previous position command ( action Return, usually Esc) will return you back. In the structure and enum views, the cursor will be moved to the corresponding offset in the current type.

See also How to enter an address

Jump by name…

Jump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. IDA will display the list of the names (sorted by addresses) and you can choose a name. Dummy names (generated by IDA) are not listed. Hidden names are not listed either. You can control which names are listed in the Names representation dialog box (Action SetNameType, Options → Name representation…).

See also How to use the lister.

Jump to segment…

Jump to the selected segment. IDA will ask you to select the target segment. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. See also: How to choose a segment.

Jump to segment register…

Jump to the selected segment register change point. IDA will ask you to select a target change point, and after:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

Jump to problem…

Jump to the selected problematic location. IDA will display the Problems List and will allow you to select a problem. The Jump to previous position command (action Return, usually Esc)(usually Esc) will return you back.

Jump to xref to operand…

Jump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. See also the description of the cross references window.

Jump to entry point…

This command shows you a list of entry points: you can jump to the selected one by pressing Enter.

The list of entry points is created at the database creation time. It is not modified after that (for example, renaming an exported function does not change the list of entry points).

Jump to file offset…

Jump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: the current address is saved in the jump stack. the cursor is positioned to the corresponding address. The Jump to previous position command (action Return, usually Esc) will return you back.

Mark position…

Remember the current position in the disassembly. You can mark certain locations of the file to be able to jump to them quickly (use the Jump to marked position… command). Text description of the location may help to find a desired location easily. First select a slot for the mark, then enter a description for the location.

Jump to marked position…

Jump to the selected marked position.

IDA will ask you to select a target position. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. You can mark the position using the Jump to marked position… command (action JumpPosition).

Jump menu actions for Hex View

{% hint style=“info” %} The options below appear when the Jump menu is opened from the Hex View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Jump to operandJumpEnterJump to the specified address. More…
Jump in a new windowJumpEnterNewJump in a new window
Jump to previous positionReturnReturn to the previous saved position. More…
Jump to next positionUndoReturnGo to the next saved position. More…
Empty navigation stackEmptyStackRemove everything from the jumps stack
Jump to pseudocodehx:JumpPseudoJump to pseudocode
Jump to address…JumpAskJump to the specified address. More…
Jump by name…JumpNameJump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. More…
Jump to function…JumpFunctionJump to the selected function. This command shows you a list of functions: you can jump to the selected one by pressing Enter.
Jump to segment…JumpSegmentJump to the selected segment. More…
Jump to segment register…JumpSegmentRegisterJump to the selected segment register change point. More…
Jump to problem…JumpQJump to the selected problematic location. More…
List cross references to…JumpXrefJump to the selected cross reference
List cross references from…JumpXrefFromJump to a cross reference from current location
Jump to xref to operand…JumpOpXrefJump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. More…
Jump to entry point…JumpEntryPointThis command shows you a list of entry points: you can jump to the selected one by pressing Enter. More…
Jump to file offset…JumpFileOffsetJump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: More…
Mark position…MarkPositionRemember the current position in the disassembly. More…
Jump to marked position…JumpPositionJump to the selected marked position. More…
Clear mark…ClearMarkClear mark

Jump to operand

Jump to the specified address. By pressing Enter you navigate in the program in the same way as in a hypertext (the way the web browsers and help screens use). This is the easiest way to explore the program: just position the cursor at the desired name and press JumpEnter. Your current address is saved in the jump stack. The Jump to previous position command (action Return, usually Esc) will return you back. If the cursor is at a stack variable, a window with stack variables is opened and the definition of the stack variable is displayed.

Jump to previous position

Return to the previous saved position. It takes positions from Jumps Stack.

Jump to next position

Go to the next saved position. This command cancels the last Jump to previous position command.

Jump to address…

Jump to the specified address. This command jumps to the specified address in the program. IDA will ask you for the target address. You can enter a name or an address as a hexadecimal number with or without a segment. If you enter a valid address then:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

The Jump to previous position command ( action Return, usually Esc) will return you back. In the structure and enum views, the cursor will be moved to the corresponding offset in the current type.

See also How to enter an address

Jump by name…

Jump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. IDA will display the list of the names (sorted by addresses) and you can choose a name. Dummy names (generated by IDA) are not listed. Hidden names are not listed either. You can control which names are listed in the Names representation dialog box (Action SetNameType, Options → Name representation…).

See also How to use the lister.

Jump to segment…

Jump to the selected segment. IDA will ask you to select the target segment. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. See also: How to choose a segment.

Jump to segment register…

Jump to the selected segment register change point. IDA will ask you to select a target change point, and after:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

Jump to problem…

Jump to the selected problematic location. IDA will display the Problems List and will allow you to select a problem. The Jump to previous position command (action Return, usually Esc)(usually Esc) will return you back.

Jump to xref to operand…

Jump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. See also the description of the cross references window.

Jump to entry point…

This command shows you a list of entry points: you can jump to the selected one by pressing Enter.

The list of entry points is created at the database creation time. It is not modified after that (for example, renaming an exported function does not change the list of entry points).

Jump to file offset…

Jump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: the current address is saved in the jump stack. the cursor is positioned to the corresponding address. The Jump to previous position command (action Return, usually Esc) will return you back.

Mark position…

Remember the current position in the disassembly. You can mark certain locations of the file to be able to jump to them quickly (use the Jump to marked position… command). Text description of the location may help to find a desired location easily. First select a slot for the mark, then enter a description for the location.

Jump to marked position…

Jump to the selected marked position.

IDA will ask you to select a target position. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. You can mark the position using the Jump to marked position… command (action JumpPosition).

Jump menu actions for Functions View

{% hint style=“info” %} The options below appear when the Jump menu is opened from the Functions View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Jump to operandJumpEnterJump to the specified address. More…
Jump in a new windowJumpEnterNewJump in a new window
Jump to previous positionReturnReturn to the previous saved position. More…
Jump to next positionUndoReturnGo to the next saved position. More…
Empty navigation stackEmptyStackRemove everything from the jumps stack
Jump to pseudocodehx:JumpPseudoJump to pseudocode
Jump to address…JumpAskJump to the specified address. More…
Jump by name…JumpNameJump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. More…
Jump to function…JumpFunctionJump to the selected function. This command shows you a list of functions: you can jump to the selected one by pressing Enter.
Jump to segment…JumpSegmentJump to the selected segment. More…
Jump to segment register…JumpSegmentRegisterJump to the selected segment register change point. More…
Jump to problem…JumpQJump to the selected problematic location. More…
List cross references to…JumpXrefJump to the selected cross reference
List cross references from…JumpXrefFromJump to a cross reference from current location
Jump to xref to operand…JumpOpXrefJump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. More…
Jump to entry point…JumpEntryPointThis command shows you a list of entry points: you can jump to the selected one by pressing Enter. More…
Jump to file offset…JumpFileOffsetJump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: More…
Mark position…MarkPositionRemember the current position in the disassembly. More…
Jump to marked position…JumpPositionJump to the selected marked position. More…
Clear mark…ClearMarkClear mark

Jump to operand

Jump to the specified address. By pressing Enter you navigate in the program in the same way as in a hypertext (the way the web browsers and help screens use). This is the easiest way to explore the program: just position the cursor at the desired name and press JumpEnter. Your current address is saved in the jump stack. The Jump to previous position command (action Return, usually Esc) will return you back. If the cursor is at a stack variable, a window with stack variables is opened and the definition of the stack variable is displayed.

Jump to previous position

Return to the previous saved position. It takes positions from Jumps Stack.

Jump to next position

Go to the next saved position. This command cancels the last Jump to previous position command.

Jump to address…

Jump to the specified address. This command jumps to the specified address in the program. IDA will ask you for the target address. You can enter a name or an address as a hexadecimal number with or without a segment. If you enter a valid address then:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

The Jump to previous position command ( action Return, usually Esc) will return you back. In the structure and enum views, the cursor will be moved to the corresponding offset in the current type.

See also How to enter an address

Jump by name…

Jump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. IDA will display the list of the names (sorted by addresses) and you can choose a name. Dummy names (generated by IDA) are not listed. Hidden names are not listed either. You can control which names are listed in the Names representation dialog box (Action SetNameType, Options → Name representation…).

See also How to use the lister.

Jump to segment…

Jump to the selected segment. IDA will ask you to select the target segment. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. See also: How to choose a segment.

Jump to segment register…

Jump to the selected segment register change point. IDA will ask you to select a target change point, and after:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address.

Jump to problem…

Jump to the selected problematic location. IDA will display the Problems List and will allow you to select a problem. The Jump to previous position command (action Return, usually Esc)(usually Esc) will return you back.

Jump to xref to operand…

Jump to the selected cross reference to operand. This command shows you a list of cross-references to the current operand: you can jump to the selected one by pressing Enter. See also the description of the cross references window.

Jump to entry point…

This command shows you a list of entry points: you can jump to the selected one by pressing Enter.

The list of entry points is created at the database creation time. It is not modified after that (for example, renaming an exported function does not change the list of entry points).

Jump to file offset…

Jump to file offset. IDA will ask you for a target file offset. This command jumps to the address corresponding to this specified file offset. If this file offset corresponds to a valid address then: the current address is saved in the jump stack. the cursor is positioned to the corresponding address. The Jump to previous position command (action Return, usually Esc) will return you back.

Mark position…

Remember the current position in the disassembly. You can mark certain locations of the file to be able to jump to them quickly (use the Jump to marked position… command). Text description of the location may help to find a desired location easily. First select a slot for the mark, then enter a description for the location.

Jump to marked position…

Jump to the selected marked position.

IDA will ask you to select a target position. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. You can mark the position using the Jump to marked position… command (action JumpPosition).

Jump menu actions for Local Types View

{% hint style=“info” %} The options below appear when the Jump menu is opened from the Local Types View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameApplies toDescription
Jump by name…JumpNameEnum, StructureJump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. More…
Mark position…MarkPositionEnum, Structure, TypedefRemember the current position in the disassembly. More…
Jump to marked position…JumpPositionEnum, Structure, TypedefJump to the selected marked position. More…
Clear mark…ClearMarkEnum, Structure, TypedefClear mark

Jump by name…

Jump to the selected name. This command allows you to jump to a name definition by selecting it from the list of the names. IDA will display the list of the names (sorted by addresses) and you can choose a name. Dummy names (generated by IDA) are not listed. Hidden names are not listed either. You can control which names are listed in the Names representation dialog box (Action SetNameType, Options → Name representation…).

See also How to use the lister.

Mark position…

Remember the current position in the disassembly. You can mark certain locations of the file to be able to jump to them quickly (use the Jump to marked position… command). Text description of the location may help to find a desired location easily. First select a slot for the mark, then enter a description for the location.

Jump to marked position…

Jump to the selected marked position.

IDA will ask you to select a target position. After:

  • the current address is saved in the jump stack.
  • the cursor is positioned to the specified address. The Jump to previous position command (action Return, usually Esc) will return you back. You can mark the position using the Jump to marked position… command (action JumpPosition).

Search

Search menu actions for IDA View

{% hint style=“info” %} The options below appear when the Search menu is opened from the IDA View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Next codeJumpCodeSearch for the next instruction in the current direction
Next dataJumpDataSearch for the next defined data item in the current direction
Next exploredJumpExploredSearch for the next instruction or data (first defined byte) in the current direction
Next unexploredJumpUnknownSearch for the next unexplored byte
Immediate value…AskNextImmediateThis command searches for the first instruction or data byte that contains the specified immediate value. More…
Next immediate valueJumpImmediateRepeat search for immediate value
Text…AskNextTextThis command searches for the specified substring in the text representation of the disassembly. More…
Next textJumpTextRepeat search for text
Sequence of bytes…AskBinaryText
Next sequence of bytesJumpBinaryTextRepeat search for sequence of bytes. This command repeats search for text in core command.
Not functionJumpNotFunctionSearch for instruction not belonging to any function
Next voidJumpSuspiciousSearch for the next instruction with void operand. More…
Error operandJumpErrorThis command searches for the ‘error’ operands. Usually, these operands are displayed with a red color. More…
All void operandsFindAllSuspiciousAll void operands. This command searches for all suspicious operands and presents a list of them. You may use this list to examine the operands and modify them as needed. More…
All error operandsFindAllErrorsAll error operands. This command searches for all strings containing any error and presents a list of them. You may use this list to examine errors and correct them as needed. More…
Search for picturespicture_search:search_for_picturesSearch for pictures
Search directionSetDirectionChange the search direction. More…
Search highlight upSearchHighlightUpSearch highlight up
Search highlight downSearchHighlightDownSearch highlight down
Lock highlight``
… (unassigned)LockHighlight_0Lock/unlock highlight color 1
… (unassigned)LockHighlight_1Lock/unlock highlight color 2
… (unassigned)LockHighlight_2Lock/unlock highlight color 3
… (unassigned)LockHighlight_3Lock/unlock highlight color 4
… (unassigned)LockHighlight_4Lock/unlock highlight color 5
… (unassigned)LockHighlight_5Lock/unlock highlight color 6
… (unassigned)LockHighlight_6Lock/unlock highlight color 7
… (unassigned)LockHighlight_7Lock highlight color 8
Find register definitionFindRegisterDefinitionFind register definition
Find register useFindRegisterUseFind register use

Immediate value…

This command searches for the first instruction or data byte that contains the specified immediate value. The command is relatively slow (but much faster than the text search), because it disassembles each instruction to find the operand values.

If the immediate value in an instruction has been logically or bitwise negated, then this command will check against the modified value. Example:

        mov al, -2

will be found if the user searches for the immediate value 2 but not when he searches for 0xFE.

If the checkbox “any untyped value” is checked, then the “value” field is ignored. IDA will look for all immediate values without type in this case.

Text…

This command searches for the specified substring in the text representation of the disassembly. This command is a slow command, because it disassembles each instruction to get the text representation. IDA will show its progress on the indicator (Options → General → Analysis). You can interrupt this command pressing Ctrl-Break.

You may search for regular expressions too.

If a range is selected using anchor (action Anchor), IDA will search for the specified substring in the range.

Note that this command searches the same as what you see on your screen (and not in binary image).

For binary search, look at AskBinaryText action.

Next void

Search for the next instruction with void operand. Suspicious operands are the operands that need your attention because they contain an immediate value that could be a number or an offset. IDA does not know about it, so it marks these instructions as ‘suspicious’. You can change the suspiciousness of the operands using set lower limit of suspicious operands and set upper limit of suspicious operands commands (Options → General → Disassembly). Data arrays are considered to be suspicious if the first element of the data array is within the lower and upper suspicious limits. Values of other elements are not examined.

{% hint style=“info” %} We strongly recommend that before producing an ASM file you go through all ‘suspicious’ marks and get rid of them. After this, you have a certain level of confidence that the file has been disassembled correctly. {% endhint %}

Error operand

This command searches for the ‘error’ operands. Usually, these operands are displayed with a red color. Below is the list of probable causes of error operands:

  • reference to an unexisting address
  • illegal offset base
  • unprintable character constant
  • invalid structure or enum reference
  • and so on…

All void operands

All void operands. This command searches for all suspicious operands and presents a list of them. You may use this list to examine the operands and modify them as needed.

See also JumpSuspicious action.

All error operands

All error operands. This command searches for all strings containing any error and presents a list of them. You may use this list to examine errors and correct them as needed.

See also JumpError action.

Search direction

Change the search direction. The current direction for searches is displayed in the right upper corner of the screen. Using this command, you can toggle the display. See also Options top menu.

Search menu actions for Pseudocode View

{% hint style=“info” %} The options below appear when the Search menu is opened from the Pseudocode View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Next codeJumpCodeSearch for the next instruction in the current direction
Next dataJumpDataSearch for the next defined data item in the current direction
Next exploredJumpExploredSearch for the next instruction or data (first defined byte) in the current direction
Next unexploredJumpUnknownSearch for the next unexplored byte
Immediate value…AskNextImmediateThis command searches for the first instruction or data byte that contains the specified immediate value. More…
Next immediate valueJumpImmediateRepeat search for immediate value
Text…AskNextTextThis command searches for the specified substring in the text representation of the disassembly. More…
Next textJumpTextRepeat search for text
Sequence of bytes…AskBinaryText
Next sequence of bytesJumpBinaryTextRepeat search for sequence of bytes. This command repeats search for text in core command.
Not functionJumpNotFunctionSearch for instruction not belonging to any function
Next voidJumpSuspiciousSearch for the next instruction with void operand. More…
Error operandJumpErrorThis command searches for the ‘error’ operands. Usually, these operands are displayed with a red color. More…
All void operandsFindAllSuspiciousAll void operands. This command searches for all suspicious operands and presents a list of them. You may use this list to examine the operands and modify them as needed. More…
All error operandsFindAllErrorsAll error operands. This command searches for all strings containing any error and presents a list of them. You may use this list to examine errors and correct them as needed. More…
Search for picturespicture_search:search_for_picturesSearch for pictures
Search directionSetDirectionChange the search direction. More…
Search highlight upSearchHighlightUpSearch highlight up
Search highlight downSearchHighlightDownSearch highlight down
Lock highlight``
… (unassigned)LockHighlight_0Lock/unlock highlight color 1
… (unassigned)LockHighlight_1Lock/unlock highlight color 2
… (unassigned)LockHighlight_2Lock/unlock highlight color 3
… (unassigned)LockHighlight_3Lock/unlock highlight color 4
… (unassigned)LockHighlight_4Lock/unlock highlight color 5
… (unassigned)LockHighlight_5Lock/unlock highlight color 6
… (unassigned)LockHighlight_6Lock/unlock highlight color 7
… (unassigned)LockHighlight_7Lock highlight color 8
Find register definitionFindRegisterDefinitionFind register definition
Find register useFindRegisterUseFind register use

Immediate value…

This command searches for the first instruction or data byte that contains the specified immediate value. The command is relatively slow (but much faster than the text search), because it disassembles each instruction to find the operand values.

If the immediate value in an instruction has been logically or bitwise negated, then this command will check against the modified value. Example:

        mov al, -2

will be found if the user searches for the immediate value 2 but not when he searches for 0xFE.

If the checkbox “any untyped value” is checked, then the “value” field is ignored. IDA will look for all immediate values without type in this case.

Text…

This command searches for the specified substring in the text representation of the disassembly. This command is a slow command, because it disassembles each instruction to get the text representation. IDA will show its progress on the indicator (Options → General → Analysis). You can interrupt this command pressing Ctrl-Break.

You may search for regular expressions too.

If a range is selected using anchor (action Anchor), IDA will search for the specified substring in the range.

Note that this command searches the same as what you see on your screen (and not in binary image).

For binary search, look at AskBinaryText action.

Next void

Search for the next instruction with void operand. Suspicious operands are the operands that need your attention because they contain an immediate value that could be a number or an offset. IDA does not know about it, so it marks these instructions as ‘suspicious’. You can change the suspiciousness of the operands using set lower limit of suspicious operands and set upper limit of suspicious operands commands (Options → General → Disassembly). Data arrays are considered to be suspicious if the first element of the data array is within the lower and upper suspicious limits. Values of other elements are not examined.

{% hint style=“info” %} We strongly recommend that before producing an ASM file you go through all ‘suspicious’ marks and get rid of them. After this, you have a certain level of confidence that the file has been disassembled correctly. {% endhint %}

Error operand

This command searches for the ‘error’ operands. Usually, these operands are displayed with a red color. Below is the list of probable causes of error operands:

  • reference to an unexisting address
  • illegal offset base
  • unprintable character constant
  • invalid structure or enum reference
  • and so on…

All void operands

All void operands. This command searches for all suspicious operands and presents a list of them. You may use this list to examine the operands and modify them as needed.

See also JumpSuspicious action.

All error operands

All error operands. This command searches for all strings containing any error and presents a list of them. You may use this list to examine errors and correct them as needed.

See also JumpError action.

Search direction

Change the search direction. The current direction for searches is displayed in the right upper corner of the screen. Using this command, you can toggle the display. See also Options top menu.

Search menu actions for Hex View

{% hint style=“info” %} The options below appear when the Search menu is opened from the Hex View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Next codeJumpCodeSearch for the next instruction in the current direction
Next dataJumpDataSearch for the next defined data item in the current direction
Next exploredJumpExploredSearch for the next instruction or data (first defined byte) in the current direction
Next unexploredJumpUnknownSearch for the next unexplored byte
Immediate value…AskNextImmediateThis command searches for the first instruction or data byte that contains the specified immediate value. More…
Next immediate valueJumpImmediateRepeat search for immediate value
Text…AskNextTextThis command searches for the specified substring in the text representation of the disassembly. More…
Next textJumpTextRepeat search for text
Sequence of bytes…AskBinaryText
Next sequence of bytesJumpBinaryTextRepeat search for sequence of bytes. This command repeats search for text in core command.
Not functionJumpNotFunctionSearch for instruction not belonging to any function
Next voidJumpSuspiciousSearch for the next instruction with void operand. More…
Error operandJumpErrorThis command searches for the ‘error’ operands. Usually, these operands are displayed with a red color. More…
All void operandsFindAllSuspiciousAll void operands. This command searches for all suspicious operands and presents a list of them. You may use this list to examine the operands and modify them as needed. More…
All error operandsFindAllErrorsAll error operands. This command searches for all strings containing any error and presents a list of them. You may use this list to examine errors and correct them as needed. More…
Search for picturespicture_search:search_for_picturesSearch for pictures
Search directionSetDirectionChange the search direction. More…
Search highlight upSearchHighlightUpSearch highlight up
Search highlight downSearchHighlightDownSearch highlight down
Lock highlight``
… (unassigned)LockHighlight_0Lock/unlock highlight color 1
… (unassigned)LockHighlight_1Lock/unlock highlight color 2
… (unassigned)LockHighlight_2Lock/unlock highlight color 3
… (unassigned)LockHighlight_3Lock/unlock highlight color 4
… (unassigned)LockHighlight_4Lock/unlock highlight color 5
… (unassigned)LockHighlight_5Lock/unlock highlight color 6
… (unassigned)LockHighlight_6Lock/unlock highlight color 7
… (unassigned)LockHighlight_7Lock highlight color 8
Find register definitionFindRegisterDefinitionFind register definition
Find register useFindRegisterUseFind register use

Immediate value…

This command searches for the first instruction or data byte that contains the specified immediate value. The command is relatively slow (but much faster than the text search), because it disassembles each instruction to find the operand values.

If the immediate value in an instruction has been logically or bitwise negated, then this command will check against the modified value. Example:

        mov al, -2

will be found if the user searches for the immediate value 2 but not when he searches for 0xFE.

If the checkbox “any untyped value” is checked, then the “value” field is ignored. IDA will look for all immediate values without type in this case.

Text…

This command searches for the specified substring in the text representation of the disassembly. This command is a slow command, because it disassembles each instruction to get the text representation. IDA will show its progress on the indicator (Options → General → Analysis). You can interrupt this command pressing Ctrl-Break.

You may search for regular expressions too.

If a range is selected using anchor (action Anchor), IDA will search for the specified substring in the range.

Note that this command searches the same as what you see on your screen (and not in binary image).

For binary search, look at AskBinaryText action.

Next void

Search for the next instruction with void operand. Suspicious operands are the operands that need your attention because they contain an immediate value that could be a number or an offset. IDA does not know about it, so it marks these instructions as ‘suspicious’. You can change the suspiciousness of the operands using set lower limit of suspicious operands and set upper limit of suspicious operands commands (Options → General → Disassembly). Data arrays are considered to be suspicious if the first element of the data array is within the lower and upper suspicious limits. Values of other elements are not examined.

{% hint style=“info” %} We strongly recommend that before producing an ASM file you go through all ‘suspicious’ marks and get rid of them. After this, you have a certain level of confidence that the file has been disassembled correctly. {% endhint %}

Error operand

This command searches for the ‘error’ operands. Usually, these operands are displayed with a red color. Below is the list of probable causes of error operands:

  • reference to an unexisting address
  • illegal offset base
  • unprintable character constant
  • invalid structure or enum reference
  • and so on…

All void operands

All void operands. This command searches for all suspicious operands and presents a list of them. You may use this list to examine the operands and modify them as needed.

See also JumpSuspicious action.

All error operands

All error operands. This command searches for all strings containing any error and presents a list of them. You may use this list to examine errors and correct them as needed.

See also JumpError action.

Search direction

Change the search direction. The current direction for searches is displayed in the right upper corner of the screen. Using this command, you can toggle the display. See also Options top menu.

Search menu actions for Functions View

{% hint style=“info” %} The options below appear when the Search menu is opened from the Functions View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Search…DirTreeSearchSearch
Search againDirTreeSearchAgainSearch again

Search menu actions for Local Types View

{% hint style=“info” %} The options below appear when the Search menu is opened from the Local Types View. In other views, the menu adapts dynamically and may show a different set of options. {% endhint %}

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameApplies toDescription
Text…AskNextTextEnum, Structure, TypedefThis command searches for the specified substring in the text representation of the disassembly. More…
Next textJumpTextEnum, Structure, TypedefRepeat search for text
Search directionSetDirectionEnum, Structure, TypedefChange the search direction. More…

Text…

This command searches for the specified substring in the text representation of the disassembly. This command is a slow command, because it disassembles each instruction to get the text representation. IDA will show its progress on the indicator (Options → General → Analysis). You can interrupt this command pressing Ctrl-Break.

You may search for regular expressions too.

If a range is selected using anchor (action Anchor), IDA will search for the specified substring in the range.

Note that this command searches the same as what you see on your screen (and not in binary image).

For binary search, look at AskBinaryText action.

Search direction

Change the search direction. The current direction for searches is displayed in the right upper corner of the screen. Using this command, you can toggle the display. See also Options top menu.

View menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Open subviews``
Quick viewQuickViewQuickly open a view
DisassemblyWindowOpenOpen disassembly view
Proximity browserGraphNewProximityViewOpen new proximity browser
Generate microcodemv:GenMicro
Generate pseudocodehx:GenPseudo
Hex dumpToggleDumpOpen hexadecimal view
Address detailsAddressDetailsAddress details
ExportsOpenExportsOpen exports window. See subviews for more.
ImportsOpenImportsOpen imports window. See subviews for more.
NamesOpenNamesOpen names window. See subviews for more.
FunctionsOpenFunctionsOpen functions window. See subviews for more.
StringsOpenStringsOpen string window. See subviews for more.
SegmentsOpenSegmentsOpen segments window. See subviews for more.
Segment registersOpenSegmentRegistersOpen segment registers window. See subviews for more.
SelectorsOpenSelectorsOpen selectors window. See subviews for more.
SignaturesOpenSignaturesOpen signatures window. See subviews for more.
Type librariesOpenTypeLibrariesOpen types window. See subviews for more.
Local typesOpenLocalTypesOpen local type definitions window. See subviews for more.
Cross referencesOpenXrefsOpen cross references window. See subviews for more.
Cross references treeOpenXrefsTreeOpen cross references tree. See subviews for more.
BookmarksOpenBookmarksOpen bookmarks window. See subviews for more.
Open picturepicture_search:open_picture
NotepadOpenNotepadOpen notepad window to create general notes about the current database. See subviews for more.
ProblemsOpenProblemsOpen problems window. See subviews for more.
Patched bytesPatchedBytesOpen the Patched bytes window. More…
Misc. tools``
Navigation historyShowViewNavigationHistoryNavigation history
Undo historyShowUndoHistoryUndo history
Graphs``
Xrefs toChartXrefsToDisplay chart of xrefs to current identifier
Xrefs fromChartXrefsFromDisplay graph of xrefs from current identifier
Function callsxref_graph:FuncCallXrefGraph
Toolbars``
Calculator…CalculateOpen calculator. More…
Full screenFullScreenDisplay the current view in full screen
Graph OverviewGraphOverviewDisplay the graph overview if hidden
Recent scriptsRecentScriptsRecent scripts
Database snapshot manager…ShowSnapManShow the database snapshot manager. More…
Increase Font SizeFontSizeIncreaseIncrease Font Size
Decrease Font SizeFontSizeDecreaseDecrease Font Size
Reset Font SizeFontSizeResetReset Font Size
Print segment registersShowRegistersPrint segment registers in the messages window. More…
Print internal flagsShowFlagsPrint internal flags in the messages window
Print register valueFindRegisterValuePrint register value
HideHideHide the current function, segment, structure, enumeration or create a hidden range. More…
UnhideUnHideUnhide the current function, segment, structure, enumeration or hidden range. More…
Hide allHideAllHide all functions, structs or enums. More…
Unhide allUnHideAllUnhide all functions, structs or enums
Delete hidden rangeDelHiddenRangeDelete the current hidden range, or all hidden ranges in a range. More…
Setup hidden items…SetupHiddenSetup hidden items

Patched bytes

Open the Patched bytes window. The Patched bytes view shows the list of the patched locations in the database. It also allows you to revert modifications selectively.

Patched bytes view

Reverting changes

Select location(s) and click Revert… from the context menu to revert this modification.

Patching bytes

You can change individual bytes via Edit → Patch program → Change byte….

Calculator…

Open calculator. A simple calculator is provided. You can enter constant C-style expressions. Syntax of the expressions is the same is the syntax of IDC expressions. The result is displayed in the message window in three forms: hexadecimal, decimal and character. All the names created during a disassembly may be used in these expressions. IDA can also pick up the name or number under the cursor and to store it into the input line.

Database snapshot manager…

Show the database snapshot manager. This command shows the database snapshot manager. In this dialog, it is possible to restore previously saved snapshots, rename or delete them.

The database snapshot manager dialog

{% hint style=“info” %} Snapshots work only with regular databases. Unpacked databases do not support them. {% endhint %}

Print segment registers in the messages window. This command displays segment register contents in the output window. You may use this command to refresh the disassembly window too.

Hide

Hide the current function, segment, structure, enumeration or create a hidden range. This command allows you to hide a part of disassembly. You can hide a function, a segment, or create a special hidden range.

If a range is specified, a special hidden range is created on this range.

If the cursor is on the segment name at the start of the segment, the segment will be hidden. IDA will display only the header of the hidden segment.

If the cursor is on a structure variable and if the target assembler has the ‘can display terse structures or the INFFL_ALLASM’ bit on, then the structure will be collapsed into one line and displayed in the terse form.

Otherwise, the current function will be hidden. IDA will display only the header of the hidden function.

If there is no current function then IDA will beep.

If you want to see hidden items on the screen, you may use Unhide command or Setup hidden items… (action SetupHidden) command to display the hidden items. If you want to delete a previously created hidden range, you may use the Delete hidden range command (action DelHiddenRange).

Unhide

Unhide the current function, segment, structure, enumeration or hidden range. This command allows you to unhide a hidden part of disassembly.

This command unhides the element located under the cursor, following these rules:

  • If the cursor is on the hidden function name, the function will be unhidden.
  • If the cursor is on the terse structure variable, the structure will be uncollapsed and displayed in the regular form.
  • If the cursor is on the hidden range, the hidden range will be unhidden.
  • If the cursor is on the hidden segment name, the segment will be unhidden.

Hide all

Hide all functions, structs or enums. This command allows you to hide all functions and hidden ranges if invoked in the disassembly window. IDA will display only the header of the hidden items.

If you want to see hidden items on the screen, you may use the Unhide command or Setup hidden items… (action SetupHidden) command.

Delete hidden range

Delete the current hidden range, or all hidden ranges in a range. This command allows you to delete a hidden range of disassembly (previously defined by using the Hide command).

Debugger menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Quick debug viewQuickDbgViewQuickly open a debug view
Debugger windows``
Debugger windowDebuggerOpen debugging window. More…
Thread listThreadsOpen threads window. More…
Module listModulesOpen modules window. More…
LocalsLocalsOpen local variables window
Stack viewStackViewStack view
Stack traceStackTraceOpen the stack trace window. More…
Watch viewWatchViewOpen a new watch window
Breakpoints``
Breakpoint listBreakpointsOpen breakpoints window. In this window, you can view information related to existing breakpoints. Breakpoints are saved in the database, and restored as soon as possible (once the memory becomes writeable). More…
Add breakpointBreakpointAddAdd a breakpoint to the current address. More…
Delete breakpointBreakpointDelDelete the breakpoint at the current address
Watches``
Watch listWatchListOpen the watch list window. More…
Add watchAddWatchAdd a variable to watch. This command adds a watch at the current address. The watch is visible in the Watch list window (accessible via the WatchList action).
Delete watchDelWatchDelete an existing watch.
Tracing``
Tracing windowTracingWindowOpen tracing window. More…
Clear traceClearTraceThis command removes all trace events from the Tracing window. It also removes any loaded trace file used for diffing against the currently loaded trace.
Instruction tracingToggleTraceInstructionsToggle instruction tracing. More…
Basic block tracingToggleTraceBasicBlocksToggle basic block tracing. More…
Function tracingToggleTraceFunctionsToggle function tracing. More…
Add write traceWriteTraceAddAdd a write trace to the current address. More…
Add read/write traceReadWriteTraceAddAdd a read/write trace to the current address. More…
Add execution traceExecTraceAddAdd an execution trace to the current address. More…
Tracing options…SetupTracingThis command opens a dialog box that allows you to specify different settings related to the tracing features. More…
Start processProcessStartStart a new process in the debugger or continue a debugged process.
Attach to process…ProcessAttachAttach the debugger to a running process
Process options…SetupProcessOpen the Process options dialog. More…
Pause processProcessPausePause or continue the debugged process
Terminate processProcessExitTerminate the debugged process
Detach from processProcessDetachDetach the debugger from the debugged process
Refresh memoryRefreshMemcfgRefresh memory. More…
Take memory snapshotTakeSnapshotTake memory snapshot. More…
Step intoThreadStepIntoExecute each instruction
Step overThreadStepOverExecute instructions without entering into functions
Run until returnThreadRunUntilReturnRun until execution returns from the current function. More…
Run to cursorThreadRunToCursorExecute instructions until instruction under the cursor is reached
Continue backwardsProcessGoBackwardsContinue execution backwards in a trace (with supported debuggers)
Step into (backwards)ThreadStepIntoBackwardsExecute each instruction backwards
Step over (backwards)ThreadStepOverBackwardsExecute instructions backwards without entering into functions. More…
Run to cursor (backwards)ThreadRunToCursorBackwardsExecute instructions backwards until instruction under the cursor is reached
Switch to sourceSwitchToSourceSwitch from disassembly to source view
Use source-level debuggingToggleSourceDebugUse source-level debugging
Open source file…OpenSourceFileOpen a source file
Debugger options…SetupDebuggerOpen Debugger setup dialog. More…
Switch debugger…SwitchDebuggerSelect debugger. More…

Debugger window

Open debugging window. In this window, you can view the register values for the selected thread. The debugger always selects the thread where the latest debugging event occurred.

For most registers, we have two different boxes:

  • the first box (on the left) indicates the current value of the register. Blue indicates that the value has changed since the last debugging event. Purple indicates that the value has been modified by the user. A popup menu is available on this control, offering different commands.
  • the second box (on the right) shows the current value of the register, interpreted like an address (if possible).

For a segment register, we only have one box indicating the current value.

For the flags register, we have one box indicating the current value, and small boxes indicating the status of the most important flags.

A popup menu is accessible everywhere in the window, which allows the user to show or hide different parts of the window: toolbar, thread list and available register classes.

Thread list

Open threads window. In this window, you can view all the threads of the debugged process. Double clicking on a thread jumps to its current instruction (available only if the process has been suspended). Double clicking also changes the current thread for the CPU window.

The right click brings a popup menu, where you can suspend or resume threads. The following thread states are possible:

  • Running: the thread is running
  • Ready: the thread is ready to run but the application has been suspended
  • Suspended: the thread has been suspended by the user

Module list

Open modules window. Opens the modules window. This window lists all the modules loaded by the debugged process. Double click on a module to see the list of its exported names.

The right click menu allows for loading debug information for the current module. For that, select the “Load debug symbols” command from the popup menu. If IDA manages to find and load the corresponding debug information file, it will import all symbols from it into the database. Currently, only PDB files are supported. The operation result is displayed in the message window.

Stack trace

Open the stack trace window. This window displays the function calls that brought the current instruction.

The top of the Stack Trace window lists the last function called by the program. Below this is the listing for the previously called functions. Each line indicates the name of the function which called the function represented by the previous line. Double clicking on a line jumps to the exact address of the instruction realizing this call.

Currently, IDA uses the EBP frame pointer values to gather the stack trace information. It will fail for functions using other methods for the frame.

Breakpoint list

Open breakpoints window. In this window, you can view information related to existing breakpoints. Breakpoints are saved in the database, and restored as soon as possible (once the memory becomes writeable).

Breakpoints view

The “Pass count” column indicates how many times the program needs to hit the breakpoint before being suspended (0 means “always suspend”).

Add breakpoint

Add a breakpoint to the current address. If an instruction exists at this address, an instruction breakpoint is created. Otherwise, IDA offers to create a hardware breakpoint and allows the user to edit breakpoint settings (Action BreakpointEdit). Hardware breakpoints can be either real hardware breakpoints or page breakpoints.

Watch list

Open the watch list window. Opens the assembler level watch list window. In this window you can view memorized watches. A watch allows the user to continuously see the value of a defined item.

Tracing window

Open tracing window. In this window, you can view some information related to all traced events. The tracing events are the information saved during the execution of a program. Different type of trace events are available:

Tracing window

During the execution, the list of traced events is disabled, as it couldn’t be continuously synchronized with the execution without rendering the whole tracing very slow. If a ‘=’ character is displayed in the ‘Thread’ and ‘Address’ columns, it indicates that the trace event occurred in the same thread and at the same address as the previous trace event.

Instruction tracing

Toggle instruction tracing. This command starts instruction tracing. You can then use all the debugger commands as usual: the debugger will save all the modified register values for each instruction.

When you click on an instruction trace event in the Tracing window, IDA displays the corresponding register values preceding the execution of this instruction. In the ‘Result’ column of the Tracing window, you can also see which registers were modified by this instruction. By using this information, you can for example quickly determine which instruction modified a specific register, or you can even backtrace the execution flow. Note that the IP register is never printed in the ‘Result’ column, although it is usually modified by almost any instruction (except perhaps some prefixed instructions like REP MOVSB, …).

Internally, the debugger runs the current thread step by step to properly obtain all the required register values. This explains why instruction tracing is slower than a normal execution.

Basic block tracing

Toggle basic block tracing. This command starts basic block tracing. You can then use all debugger commands as usual: the debugger will save all addresses where a temporary basic block breakpoint was reached.

Internally, the debugger runs the current thread normally, setting temporary breakpoints in the last instruction of every basic block of every function referenced from the current function and also at any call instruction in the middle of the traced basic blocks.

Basic block tracing is slower than normal execution but faster than instruction or function tracing.

Function tracing

Toggle function tracing. This command starts function tracing. You can then use all debugger commands as usual: the debugger will save all addresses where a call to a function or a return from a function occurred.

Internally, the debugger runs the current thread step by step to properly detect all function calls and returns. This explains why functions tracing is slower than a normal execution.

Add write trace

Add a write trace to the current address. Each time the given address will be accessed in write mode, the debugger will add a trace event to the Tracing window. In fact, write traces are nothing more than breakpoints with special properties: they don’t stop and they simply add a trace event when the breakpoints are reached.

Internally, the debugger will add a hardware breakpoint on the given address, so all the restrictions for hardware breakpoints are also valid for write traces.

Add read/write trace

Add a read/write trace to the current address. This command adds a read/write trace to the current address. Each time the given address will be accessed in read or write mode, the debugger will add a trace event to the Tracing window. In fact, read/write traces are nothing more than breakpoints with special properties: they don’t stop and they simply add a trace event when the breakpoints are reached. Internally, the debugger will add a hardware breakpoint on the given address, so all the restrictions for hardware breakpoints are also valid for read/write traces.

Add execution trace

Add an execution trace to the current address. Each time the instruction at the given address will be run, the debugger will add a trace event to the Tracing window.

In fact, execution traces are nothing more than breakpoints with special properties: they don’t stop and they simply add a trace event when the breakpoints are reached.

Internally, the debugger will add a breakpoint instruction at the given address.

Tracing options…

This command opens a dialog box that allows you to specify different settings related to the tracing features.

Tracing options dialog

  • Trace buffer size: This setting indicates how many tracing events can fit in the trace buffer. If the debugger must insert a new event and the buffer is full, the oldest tracing event will be removed. However, if you specify a size of 0, the buffer size isn’t limited. Notice that, for example, in the case of an instructions trace, all executed instructions could be logged, which would quickly fill up the memory!

  • Trace file: If a filename is specified, all future traced events will be appended to it.

  • Trace directory: The directory were trace files for the current database will be saved. If not specified, the IDB directory will be used.

  • Stop condition: This IDC expression will be evaluated before the execution of each instruction. If the expression returns true, the debugger will suspend the execution. Please note that you can use register names in the condition.

Tracing:

  • Trace over debugger segments: If selected, the debugger will not go step by step in debugger segments (segments not available in the database).
  • Trace over library functions: If selected, the debugger will not go step by step in library functions.

{% hint style=“info” %} Enabling these options will speed up the execution, as many instructions (from debugger segments and/or library functions) will not be traced. Disabling these options can quickly fill the Tracing window, as all instructions in DLLs and system functions will be executed step by step. Notice that both options influence the way instruction and function tracings will work. {% endhint %}

Internally, the debugger proceeds like this:

  • Memorize the return address associated with the last executed call instruction in database segments (the previously saved one is overwritten).

  • Setup a temporary breakpoint on this address once the IP is in a debugger segment or library function, disable step by step, and run the thread.

  • Reenable step by step once this temporary breakpoint is reached.

  • Do not log already logged IP: If selected, already executed instructions will not be logged if they are executed again.

  • Skip loops: If selected, tracing will be temporarily disabled for some loops constructs.

Highlight:

  • Highlight instructions in IDA views: If selected, recorded instructions will be displayed in IDA views (disassembly views) with a different background color.

Instruction tracing:

  • Log if same IP: If selected, the debugger will also log all register modifications occurring during the execution of prefixed instructions like REP MOVSB, …

Function tracing:

  • Log return instructions: If selected, the debugger will also log function returns. If disabled, only function calls are logged.

Basic block and function tracing:

  • Log internal instructions: If selected, all instructions from the current basic block will be logged and displayed in the ‘Tracing’ window, instead of only the last instruction of the basic block.

Process options…

Open the Process options dialog. It allows to specify different settings related to the process being debugged.

ApplicationHost application to launch. When the debugging target (== 'input file') is an executable file, this field is equal to the 'input file'. If this field is wrong, IDA will not be able to launch the program. For remoting debugging, this field denotes a remote file.
Input fileThe input file used to create the database. For remoting debugging, this field denotes a remote file.
DirectoryDirectory to start the application. If empty, then the current directory will be used. For remoting debugging, this field denotes a remote directory.
ParametersOptional parameters to pass to the debugged application (or the host application) when it starts. This field may be empty. The standard input/output/error channels can be redirected using the bash shell notations. For example: >output 2>&1
HostnameIf entered, denotes the name of the remote host with the application to debug. In this case, a remote IDA server on this host must be launched. Click here to see the list of remote servers.
PortThe port number of the remote server
PasswordOptional password to protect your server from strangers connecting to it and running arbitrary commands. The same password switch must be specified on the remote server.

The hostname, port, and password are not available for debuggers connected locally to the computer.

See also How to launch remote debugging

Refresh memory

Refresh memory. This command refreshes the segments and memory contents in IDA. It is available only during a debugging session. NOTE: this command is currently hidden from the user interface because IDA does synchronize with the process memory automatically.

Please note that IDA itself tries to keep the program segments in sync with the debugged process. However, in order to accelerate the debugger, the synchronization is done only at major events, for example when dynamic library gets loaded or unloaded or a thread is created or deleted. If the memory configuration is changed because of a simple system call (think of VirtualAlloc), IDA might miss it. Use the “refresh memory” command in these cases.

{% hint style=“info” %} When IDA detects a discrepancy in the segments, it will automatically synchronize with the process. {% endhint %}

Take memory snapshot

Take memory snapshot. This command copies the contents of the process memory to the database. It is available during a debugging session.

The memory contents will be copied to the database. The user may specify that only the segments with the ‘loader’ attribute will be saved in the database.

The segments with the loader attribute are created by the input file loader and usually contain information from the input file. However, in some cases (like attaching to an existing process), there will not be any loader segments because the input file was not loaded by IDA.

To be able to make a partial snapshot in this case and other similar cases, the user can set or clear the ‘loader’ attribute of the desired segments using the Edit segment… (action EditSegment) command.

After applying this command, the user can terminate the debugging process and continue to analyze the program in the database.

Please note that it is possible to save the database without taking a memory snapshot. Such a database might be used to keep global information about the program like the breakpoint information, notes, etc. However, we recommend to take a memory snapshot of at least the ‘loader’ segments because it will allow to save also information about the program functions, names, comments, etc.

Run until return

Run until execution returns from the current function. This command executes assembler instructions and stops on the instruction immediately following the instruction that called the current function.

Internally, IDA executes each instruction in the current function until a ‘return from function’ instruction is reached.

Step over (backwards)

Execute instructions backwards without entering into functions. This command backward-executes one assembler instruction at a time, stepping over procedures while executing them as a single unit. Internally, in the case of a function call, IDA setups a temporary breakpoint on the instruction preceding this function call.

Debugger options…

Open Debugger setup dialog. This dialog box allows to specify different settings related to the debugger.

Events

  • Suspend on debugging start

    If selected, the debugger will suspend directly once the debugging starts.

  • Evaluate event condition on exit

    If selected, the debugger will evaluate the event condition immediately before closing the debugging session (once we receive PROCESS_EXITED or PROCESS_DETACHED event)

  • Suspend on process entry point

    If selected, the debugger will insert a temporary breakpoint at the main entry point of the debugged application.

  • Suspend on thread start/exit

    If selected, the debugger will suspend if a new thread starts or if an existing thread terminates.

  • Suspend on library load/unload

    If selected, the debugger will suspend if a new library is loaded or if a previously loaded library is unloaded.

  • Suspend on debugging message

    If selected, the debugger will suspend if the debugged application generates a message destined to the debugger.

Event condition

When one or more debug events (see above) are checked, then this option is used to specify a condition. In the following example, the debugger will suspend the process whenever a module with the name test.dll is loaded:

    get_event_id() == LIB_LOADED && strstr(get_event_module_name(), "test.dll") != -1

Log

  • Segment modifications

    If selected, the debugger will print information regarding segment modifications (creation, deletion, or resizing of segments) since the last event. Note that the debugger doesn’t continuously track segment modifications, but detects those only if a debugging event occurs.

  • Thread start/exit

    If selected, the debugger will print a message if a new thread starts or if an existing thread terminates.

  • Library load/unload

    If selected, the debugger will print a message if a new library is loaded or if a previously loaded library is unloaded.

  • Breakpoint

    If selected, the debugger will print a message if the debugged process reaches a breakpoint.

  • Debugging message

    If selected, the debugger will print debugging messages from the application.

Options

  • Reconstruct the stack

    If selected, the debugger will try to reconstruct the chain of stack frames, based on information available on the stack and in the function stack variables.

  • Show debugger breakpoint instructions

    If selected, the debugger will show breakpoint instructions inserted by the debugger itself. This function is mainly useful if the user wants to see the real content of the memory.

  • Use hardware temporary breakpoints

    If selected, IDA will try to use hardware breakpoints for the temporary breakpoints used to implement the “step over” and “run to” functionality. This feature is useful when debugging read-only or self-modifying code, since it does not change the contents of the memory. IDA will fall back to software breakpoints if the attempt to set a hardware breakpoint fails.

  • Autoload PDB files

    If selected, IDA will invoke the PDB plugin to try to load PDB symbols for every new module loaded into process.

  • Optimize single-stepping

    Prevent debugger memory refreshes when single-stepping. See debugger_t::DBG_FLAG_FAST_STEP

  • Disable ASLR

    Disable Address space layout randomization (ASLR). Optional, valid if debugger declares this option is supported, see debugger_t::DBG_FLAG_DISABLE_ASLR

  • Set as just-in-time debugger

    If changed from off to on, IDA will try to register itself as a just-in-time debugger (invoked by the system in case of application crashes) on dialog close. Optional, valid only for Windows OS.

Buttons

  • Edit exceptions

    This button allows the user to setup exceptions (#exceptions) how the debugger will react to specific exceptions.

  • Reload exceptions

    This button reloads the exception table from the exceptions.cfg file.

  • Set specific options

    Set debugger options (parameters that are specific to the debugger module). Optional, valid if debugger has the additional specific options. See debugger_t::ev_set_dbg_options

Exceptions

This dialog box allows to setup how the debugger will react to specific exceptions. For each exception, two settings can be specified, simply by selecting the desired exception, and clicking the ‘Edit’ button in the popup menu.

  • Suspend program: Specify whether the debugger will suspend when the exception occurs. If ‘Passed to’ == application and the application handles the exception successfully, the execution will not be suspended regardless of the ‘Suspend’ value.

  • Passed to: Specify whether the exception will be passed to the application itself or handled by the debugger. If the debugged program contains exception handling code, it is better to select ‘Application’.

Report:

  • Warn: Show a warning message with the exception information.
  • Log: Instead of displaying a warning message, log to the output window the exception information.
  • Silent: Do not show a warning message nor log to the output window.

For new exceptions being added by the “Insert” command, you have to specify the exception name and code. These values must be unique, the name cannot be empty, and the code cannot be zero.

Switch debugger…

Select debugger. This command allows the user to select a debugger if there are several debuggers available for the current database. For example, Window32 program can be debugged with a remote or a local debugger.

Lumina menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Pull allLuminaPullAllMdsPull all metadata from the primary server. More…
Push allLuminaPushAllMdsPush all metadata to the primary server. More…
View allLuminaViewAllMdsView all metadata from the primary server. More…
Pull function mainLuminaPullMdPull function metadata from the primary server
Push function mainLuminaPushMdPush function metadata to the primary server
Secondary server``
Pull allLuminaSecondaryPullAllMdsPull all metadata from the secondary server
Push allLuminaSecondaryPushAllMdsPush all metadata to the secondary server
View allLuminaSecondaryViewAllMdsView all metadata from the secondary server
Pull function mainLuminaSecondaryPullMdPull function metadata from the secondary server
Push function mainLuminaSecondaryPushMdPush function metadata to the secondary server
Revert function mainLuminaRevertMdRevert function metadata

Pull all

Pull all metadata from the primary server. This commands retrieves metadata about the current database from Lumina.

IDA will calculate checksums for all non-trivial functions in the database and send it to Lumina. This information will be used to match and retrieve metadata, which will be automatically applied.

Please note that this may overwrite your changes, so taking a database snapshot and saving the database before invoking this command is a good idea.

By non-trivial functions we mean:

  • long enough functions (>=16 bytes)
  • non-library functions
  • non-imported functions (functions with real body)

Lumina Metadata

Metadata currently consists of the following information:

  • function address, name, prototype
  • function frame layout
  • stack variables
  • user-defined sp change points
  • representation of instruction operands
  • function and instruction comments

Push all

Push all metadata to the primary server. This commands sends metadata about the current database to Lumina.

IDA will calculate checksums for all non-trivial functions in the database, extract metadata about them, and send it to Lumina. The metadata includes function names and types, user comments, operand types, etc.

If Lumina already has metadata about the involved functions, it will be replaced only if the new metadata is better and more complete.

Only functions with non-trivial names are pushed by this command.

View all

View all metadata from the primary server. This commands retrieves metadata about the current database from Lumina.

IDA will calculate checksums for all non-trivial functions in the database and send it to Lumina. This information will be used to match and retrieve metadata. After that IDA will display list of matched functions.

The user can then select the desired metadata and apply it to the database. If the result is not satisfactory, it is possible to revert the changes.

Once the window is closed, it is not possible to revert the changes anymore.

At the bottom of the window there are convenience buttons to apply or revert all available metadata.

Options menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
General…OptionsOpen the General IDA Options dialog, where settings are organized thematically across multiple tabs. More…
Colors…SetColorsSetup colors. More…
Font…SetFontSetup font. More…
Feature Flags…ShowFeatureFlagsConfigure feature flags. More…
Shortcuts…ShortcutEditorEdit shortcuts. More…
Show command palette…CommandPaletteShow command palette. This command opens a dialog, that provides quick access to all available IDA actions with shortcuts and descriptions. More…
Repeat last palette commandRepeatLastPaletteCommandRepeat last palette command
Disable undoUndoToggleDisable undo
Reset undo historyResetUndoHistoryReset undo history. More…
Assembler directives…SetDirectivesSetup assembler directive generation. More…
Name representation…SetNameTypeSetup name representation. More…
Demangled names…SetDemangledNamesSetup C++ demangled name representation. More…
Compiler…SetupCompilerSetup target compiler and its parameters. More…
String literals…SetStrlitStyleSetup string literal style. More…
Setup data types…SetupDataSetup data types. More…
Source paths…SetupSrcPathsSetup source paths. More…

General…

Open the General IDA Options dialog, where settings are organized thematically across multiple tabs.

Disassembly options

This tab configures the appearance of the disassembly.

Disassembly options

The checkboxes/input fields are organized into several categories:

Display disassembly line parts

Line prefixes (non-graph)

This checkbox enables or disables line prefixes display. Line prefix is the address of the current byte:

         3000:1000      mov ax, bx
         ^^^^^^^^^

IDA.CFG parameter: SHOW_LINEPREFIXES

Stack pointer

If this option is set, IDA will display the value of the stack pointer in the line prefix.

IDA.CFG parameter: SHOW_SP

Number of opcode bytes (non-graph)

The opcode is the operation code of the current instruction. For the data items, the opcodes are elements of data directives. Sometimes there is not enough place to display all bytes of an item (of a large array, for example). In this case, IDA will display just the few first bytes of the item. For the code items, IDA will try to display all bytes of the instruction, even if it requires adding more lines just for the opcode bytes. If this behavior is not desired, the number of opcode bytes can be specified as a negative value. A negative value -N means to display N opcode bytes on a line but never display empty lines just for the opcode bytes. By default, IDA does not display the opcodes.

Opcode bytes are shown below:

        3000:1000 55           push    bp
                  ^^^^^^^^^

IDA.CFG parameter: OPCODE_BYTES

Comments-related options:

OptionIDA.CFG Parameter
Commentsn/a
Repeatable commentsSHOW_REPEATABLE_COMMENTS
Auto commentsSHOW_AUTOCOMMENTS

{% hint style=“info” %} Auto comments are predefined comments for all instructions. If you forgot the meaning of a certain instruction, you can use this command to get comments for all lines on the screen. IDA does not give comments to very simple instructions, such as the ‘mov’ instruction, and does not override existing comments. {% endhint %}

Address representation

OptionDescriptionEnabledDisabledIDA.CFG Parameter
Function offsetsThis option controls the appearance of the line prefixes. If it is enabled, the addresses will be displayed as offsets from a function beginning.somefunc+0x44cseg:0x4544SHOW_SEGMENTS
Include segment addressesMarking this checkbox, you can enable segment addresses in the disassembly. IDA will show only offsets.codeseg:00340034SHOW_SEGMENTS
Use segment namesThis option controls the appearance of the segment names in the addresses. (codeseg has base 3000)codeseg:00343000:0034USE_SEGMENT_NAMES

Display disassembly lines

Empty lines

This option enables or disables the presence of the autogenerated empty lines in the disassembly. It could be useful to decrease the number of the blank lines on the screen increasing amount of information on it.

IDA.CFG parameter: SHOW_EMPTYLINES

Borders between data/code (non-graph)

This command enables or disables the presence of the autogenerated border lines in the disassembly. It could be useful to decrease the number of the blank lines on the screen increasing amount of information on it. A border line looks like this:

         ;---------------------------------------------------------

Note that you can hide a particular border by using the Toggle border command (action ToggleBorder).

IDA.CFG parameter: SHOW_BORDERS

Basic block boundaries (non-graph)

This option enables or disables the presence of the autogenerated empty lines at the end of basic blocks in the disassembly.

IDA.CFG(../../configuration/configuration-files.md) parameter: SHOW_BASIC_BLOCKS

Source line numbers

This options controls the presence of the source line number information in the disassembly. Some object files have this information.

IDA.CFG parameter: SHOW_SOURCE_LINNUM

Try block lines

This option controls the display of the try block information in the disassembly.

IDA.CFG parameter: SHOW_TRYBLOCKS

Other text formatting options

Instruction identation (non-graph)

You can change indention of disassembled instructions:


                         mov ax, bx
         <-------------->
            indention

IDA.CFG parameter: INDENTION

Comments identation (non-graph)

You can change indention of comments:

                mov ax, bx                      ; this is a comment
        <-------------------------------------->
                       indention

IDA.CFG parameter: COMMENTS_INDENTION

Right margin (non-graph)

This option controls the length of disassembly lines for data directives.

IDA.CFG parameter: MAX_DATALINE_LENGTH

Low and high suspiciousness limit

If IDA suspects that an operand can be represented as something different from a plain number, it will mark the operand as “suspicious” and display it in red/orange.

Two values control the definition of suspiciousness. An operand is ‘suspicious’ if it has an immediate value between low and high ‘suspicious’ limits. The comparison is always unsigned, i.e., in the instruction:

        mov ax,[bp-2]

the immediate operand is 0xFFFE, not -2.

IDA uses a simple heuristic to determine initial suspiciousness limits. You may change these limits any time you want.

Analysis options

This tab allows you to configure analysis settings and processor-specific options.

  • Target processor: Change the processor type (if multiple types are supported by the current processor module)
  • Target assembler: Select the assembler style

Additional options (buttons):

  • Kernel options
  • Processor specific analysis options: Configure processor-specific settings (available when the current processor supports additional options)
  • Memory mapping: Define memory mapping ranges (available when the current processor supports memory mapping)
  • Reanalyze program

Analysis options

Analysis section

The checkboxes:

  • Enabled
  • Indicator enabled

allows you to disable and enable the autoanalysis and its indicator.

By default, the auto analysis and indicator are enabled. Disable them only if you are sure it will help.

 Action    name: SetAuto
 

The analysis indicator is located in the bottom left corner of the main IDA window (upper right corner in text version). Possible values of the indicator:

IndicatorDescription
(empty)Indicator is turned off
AU: idleAutoanalysis is finished
AU:disabledAutoanalysis is disabled
FL:<address>Execution flow is being traced
PR:<address>A function is being created
TL:<address>A function tail is being created
SP:<address>The stack pointer is being traced
AC:<address>The address is being analyzed
LL:<number>A signature file is being loaded
L1:<address>The first pass of FLIRT
L2:<address>The second pass of FLIRT
L3:<address>The third pass of FLIRT
TP:<address>Type information is being applied
FI:<address>The final pass of autoanalysis
WF:<address>Weak execution flow is being traced
??:<address>The address becomes unexplored
@:<number>Indication of various activity

{% hint style=“success” %} Hint: you can right-click the analysis indicator to quickly disable or enable it, or to reanalyze the program. {% endhint %}

See also auto analysis explanation.

Processor Type

TypeDescriptionFamily
8086Intel 8086IBM PC family
80286rIntel 80286 real modeIBM PC family
80286pIntel 80286 protected modeIBM PC family
80386rIntel 80386 real modeIBM PC family
80386pIntel 80386 protected modeIBM PC family
80486rIntel 80486 real modeIBM PC family
80486pIntel 80486 protected modeIBM PC family
80586rIntel Pentium & MMX real modeIBM PC family
80586pIntel Pentium & MMX prot modeIBM PC family
80686pIntel Pentium Pro & MMXIBM PC family
k62AMD K6-2 with 3DNow!IBM PC family
p2Intel Pentium IIIBM PC family
p3Intel Pentium IIIIBM PC family
athlonAMD K7IBM PC family
p4Intel Pentium 4IBM PC family
metapcDisassemble all IBMPC opcodesIBM PC family
8085Intel 8085Zilog 80 family
z80Zilog 80Zilog 80 family
z180Zilog 180Zilog 80 family
z380Zilog 380Zilog 80 family
64180Hitachi HD64180Zilog 80 family
gbGameboyZilog 80 family
z8Zilog 8Zilog 8 family
860xrIntel 860 XRIntel 860 family
860xpIntel 860 XPIntel 860 family
8051Intel 8051Intel 51 family
80196Intel 80196Intel 80196 family
80196NPIntel 80196NP, NUIntel 80196 family
m6502MOS 6502MOS Technology 65xx family
m65c02MOS 65c02MOS Technology 65xx family
pdp11DEC PDP/11PDP family
68000Motorola MC68000Motorola 680x0 family
68010Motorola MC68010Motorola 680x0 family
68020Motorola MC68020Motorola 680x0 family
68030Motorola MC68030Motorola 680x0 family
68040Motorola MC68040Motorola 680x0 family
68330Motorola CPU32 (68330)Motorola 680x0 family
68882Motorola MC68020 with MC68882Motorola 680x0 family
68851Motorola MC68020 with MC68851Motorola 680x0 family
68020EXMotorola MC68020 with bothMotorola 680x0 family
colfireMotorola ColdFireMotorola 680x0 family
68KMotorola MC680x0 all opcodesMotorola 680x0 family
6800Motorola MC68HC00Motorola 8bit family
6801Motorola MC68HC01Motorola 8bit family
6803Motorola MC68HC03Motorola 8bit family
6301Hitachi HD 6301Motorola 8bit family
6303Hitachi HD 6303Motorola 8bit family
6805Motorola MC68HC05Motorola 8bit family
6808Motorola MC68HC08Motorola 8bit family
6809Motorola MC68HC09Motorola 8bit family
6811Motorola MC68HC11Motorola 8bit family
6812Motorola MC68HC12
hcs12Motorola MC68HCS12
6816Motorola MC68HC16
javajavaJava family
ppcPowerPC big endianPowerPC family
ppclPowerPC little endianPowerPC family
armARM little endianARM family
armbARM big endianARM family
tms320c2TMS320C2x seriesTMS 16bit addressing family
tms320c5TMS320C5x seriesTMS 16bit addressing family
tms320c6TMS320C6x seriesTMS VLIW family
tms320c3TMS320C3x seriesTMS VLIW family
tms32054TMS320C54xx series
tms32055TMS320C55xx series
sh3Renesas SH-3 (little endian)Renesas SuperH series
sh3bRenesas SH-3 (big endian)Renesas SuperH series
sh4Renesas SH-4 (little endian)Renesas SuperH series
sh4bRenesas SH-4 (big endian)Renesas SuperH series
sh2aRenesas SH-2A (big endian)Renesas SuperH series
avrATMEL AVRATMEL family
mipslMIPS little endianMIPS family: R2000, R3000, R4000, R4200, R4300, R4400, R4600, R8000, R10000
mipsbMIPS big endianMIPS family: R2000, R3000, R4000, R4200, R4300, R4400, R4600, R8000, R10000
mipsrlMIPS & RSP littleMIPS family: R2000, R3000, R4000, R4200, R4300, R4400, R4600, R8000, R10000
mipsrMIPS & RSP bigMIPS family: R2000, R3000, R4000, R4200, R4300, R4400, R4600, R8000, R10000
r5900lMIPS R5900 littleMIPS family: R2000, R3000, R4000, R4200, R4300, R4400, R4600, R8000, R10000
r5900rMIPS R5900 bigMIPS family: R2000, R3000, R4000, R4200, R4300, R4400, R4600, R8000, R10000
h8300H8/300x in normal modeHitachi H8 family
h8300aH8/300x in advanced modeHitachi H8 family
h8s300H8S in normal modeHitachi H8 family
h8s300aH8S in advanced modeHitachi H8 family
h8500H8/500Hitachi H8/500 family
pic12cxxMicrochip PIC 12-bit (12xxx)PIC family
pic16cxxMicrochip PIC 14-bit (16xxx)PIC family
pic18cxxMicrochip PIC 16-bit (18xxx)PIC family
sparcbSPARC big endianSPARC family
sparclSPARC little endianSPARC family
alphabDEC Alpha big endianALPHA family
alphalDEC Alpha little endianALPHA family
hppaHP PA-RISC big endianHP PA-RISC family
dsp56kMotorola DSP 5600xDSP 56K family
dsp561xxMotorola DSP 561xxDSP 56K family
dsp563xxMotorola DSP 563xxDSP 56K family
dsp566xxMotorola DSP 566xxDSP 56K family
c166Siemens C166C166 family
c166v1Siemens C166 v1 familyC166 family
c166v2Siemens C166 v2 familyC166 family
st10SGS-Thomson ST10C166 family
super10Super10C166 family
st20SGS-Thomson ST20/C1ST20 family
st20c4SGS-Thomson ST20/C2-C4
st7SGS-Thomson ST7ST7 family
ia64lIntel Itanium little endianIA64 family
ia64bIntel Itanium big endianIA64 family
cliMicrosoft.Net platform
netMicrosoft.Net platform (alias)
i960lIntel 960 little endiani960 family
i960bIntel 960 big endiani960 family
f2mc16lFujitsu F2MC-16LFujitsu F2MC family
f2mc16lxFujitsu F2MC-16LXFujitsu F2MC family
78k0NEC 78k/0
78k0sNEC 78k/0s
m740Mitsubishi 8-bit
m7700Mitsubishi 16-bitMitsubishi 16-bit family
m7750Mitsubishi 16-bitMitsubishi 16-bit family
m32rMitsubishi 32-bitMitsubishi 32-bit family
m32rxMitsubishi 32-bit extendedMitsubishi 32-bit family
st9STMicroelectronics ST9+
frFujitsu FR family
m7900Mitsubishi M7900
kr1878Angstrem KR1878
ad218xAnalog Devices ADSP
oakdspAtmel OAK DSP
tricoreInfineon Tricore
ebcEFI Bytecode
msp430Texas Instruments MSP430

Processor modules can accept additional options that can be passed on the commandline with the -p switch. Currently only the ARM module supports it. For example, -parm:ARMv7-A will turn on options specific for the ARMv7-A architecture, such as NEON instruction set.

For information about additional processor modules, please check supported processors

Please note that when you change the processor type, IDA may change the target assembler, so check it out.

You may get a message saying that IDA does not know the specified processor if IDA fails to load the corresponding processor module:

  • Windows IDA uses .dll file extension
  • Linux IDA uses .so file extension
  • Mac IDA uses .dylib file extension

{% hint style=“info” %} Modules compiled with support for 64-bit address space, will feature a ‘64’ suffix before the extension. E.g., ‘pc64.dll’ {% endhint %}

{% hint style=“info” %} Changing the processor type leads to reanalysis of the whole program. Sometimes this is useful. {% endhint %}

{% hint style=“info” %} When you load a new processor module, all analysis options are reset to the values specified in the configuration file. {% endhint %}

IDA determines the default processor using the input file extension and the contents of the input file. The table which describes the input file extensions and the corresponding processor types is located in IDA.CFG file and looks like this:

 DEFAULT_PROCESSOR = {
 /* Extension   Processor */
  "com" :       "8086"                  // IDA will try the specified
  "exe" :       "80386r"                // extensions if no extension is
  "dll" :       "80386r"                // given.
  "drv" :       "80386r"
  "o"   :       "68000"
  "prc" :       "68000"                 // PalmPilot programs
  "axf" :       "arm"
  "h68" :       "68000"                 // MC68000 for *.H68 files
  "i51" :       "8051"                  // i8051   for *.I51 files
  "sav" :       "pdp11"                 // PDP-11  for *.SAV files
  "rom" :       "z80"                   // Z80     for *.ROM files
  "cla" :       "java"                  // Java classes
  "class":      "java"                  // Java classes
  "s19":        "6811"
  "*":          "80386p"                // Default processor
}

If you want to change the default processor type, you need to change this table. You may add/delete rows in this table.

See also: ARM processor specifics.

ARM processor specifics

Since architecture version v4 (introduced in ARM7 cores), ARM processors have a new 16-bit instruction set called Thumb (the original 32-bit set is referred to as “ARM”). Since these two sets have different instruction encodings and can be mixed in one segment, we need a way to specify how to disassemble instructions. For this purpose, IDA uses a virtual segment register named ‘T’. If its value is 0, then ARM mode is used. Otherwise, Thumb mode is used. ARM is the default mode. Please note that if you change the value of T register for a range, IDA will destroy all instructions in that range because their disassembly is no longer correct.

IDA use UAL (Unified Assembly Language) syntax by default which uses the same syntax for both ARM and Thumb mode. If necessary, legacy assembler syntax can be selected in Analysis options.

To decode Aarch64 (ARM64) instructions the segment with instructions must be set to 64-bit (see Edit segment… command; action EditSegment).

Processor options for ARM

  • Simplify instructions: If this option is on, IDA will simplify instructions and replace them by clearer pseudo-instructions. For example:

              MOV     PC, LR

is replaced by

              RET
  • Disable pointer dereferencing: If this option is on, IDA will not use =label syntax for loads from literal pools. For example,

                    LDR     R1, =dst
                    ...
      off_0_1003C   DCD dst

will be shown as


                    LDR     R1, off_0_1003C
  • No automatic ARM-Thumb switch: If this option is on, IDA will not propagate ARM-Thumb modes automatically when following jumps and calls.

  • Disable BL jumps detection: Some ARM compilers in Thumb mode use BL (branch-and-link) instead of B (branch) for long jumps, since BL has more range. By default, IDA tries to determine if BL is a jump or a call. You can override IDA’s decision using commands in Edit → Other menu (Force BL call/Force BL jump). If your target does not use this trick, you can set this option and IDA will always treat BL as a call.

  • Scattered MOVT/MOVW pairs analysis: A pair of MOVT and MOVW instructions can be used to load any 32-bit constant into a register without having to use the literal pool. For example: MOVW R1, #0xABA2 MOVT R1, #0x32AA is simplified by IDA into MOV R1, 0x32AAABA2 (unless macro creation is turned off). However, if there is an unrelated instruction between them, such simplification is not possible. If you enable the conversion, then IDA will try to convert operands of even scattered instructions. The example above could be represented as:


      MOVW  R1, #:lower16:0x32AAABA2
      [other instructions]
      MOVT  R1, #:upper16:0x32AAABA2

It is possible to select how aggressively IDA should try to handle such pairs:

  • leave them as is, convert only if the result a valid address, or try to

  • convert all pairs even if the result does not look like a valid address.

  • Edit ARM architecture options: This button allows you to edit various features of the ARM architecture. This will affect the disassembly of some instructions depending on whether the selected architecture supports them. For details, see the ARM Architecture Reference Manual.

Command-line options

You can configure the architecture options from the command line. For that, use the -parm:<option1[;option2...]> switch. The following options are accepted:

  • ARMv<N> - base ARM architecture version (e.g. ARMv4, ARMv4T, ARMv5TE, …, ARMv7-M, ARMv7-A), or
  • <name> - ARM core name (e.g. ARM7TDMI, ARM926EJ-S, PXA270, Cortex-M3, Cortex-A8)

Additionally, a special name “armmeta” can be used to enable decoding of all known instructions.

The options above will set some default values that can be adjusted further:

OptionDescription
NoVFP/VFPv<N>disable or enable support for VFP instructions (e.g. VFPv3).
NoNEON/NEON/NEON-FMAdisable or enable support for NEON (aka Advanced SIMD) instructions.
NoThumb/Thumb/Thumb-2disable or enable support for Thumb (16-bit) or Thumb-2 (16/32-bit) instructions.
NoARM/ARMdisable or enable support for ARM instructions.
XScalesupport for XScale-specific instructions. Implies ARMv5TE.
NoWMMX/WMMXv1/WMMXv2support for Intel Wireless MMX extensions (v1 or v2). Implies XScale.

See also

  • Change segment register value command (action SetSegmentRegister)
  • Set default segment register value… command (action SetSegmentRegisterDefault) to specify the segment register value.

Specify Target Assembler

This command allows you to change the target assembler, i.e. the assembler for which the output is generated. You select the target assembler from a menu. The menu items depend on the current processor type.

{% hint style=“info” %} Currently, IDA supports only a generic assembler for 80x86 processors. We recommend the use of Borland’s TASM to compile the output assembler files. {% endhint %}

Kernel options

Here you can change various kernel analysis options:

Kernel analysis options 1

  • Trace execution flow: This option allows IDA to trace execution flow and convert all references bytes to instructions (the Code command; action MakeCode) Mark typical code sequences as code. IDA knows some typical code sequences for each processor. For example, it knows about typical sequence
          push    bp
          mov     bp, sp

If this option is enabled, IDA will search for all typical sequences and convert them to instructions even if there are no references to them. The search is performed at the loading time.

  • Locate and create jump tables: This option allows IDA to try to guess the address and size of jump tables. Please note that disabling this option will not disable the recognition of C-style typical switch constructs.

  • Control flow to data segment is ignored: If set, IDA will not analyze code reference targets in pure data segments. Usually pure data segments have some instructions (e.g., thunk functions), that’s why this option is set off by default. For Mach-O files, it is set on because pure data segment do not contain instructions in them.

  • Analyze and create all xrefs: If this option is disabled, IDA will not thoroughly analyze the program: it will simply trace execution flow, nothing more (no xrefs, no additional checks, etc.)

  • Delete instructions with no xrefs: This option allows IDA to undefine instructions without any xrefs to them. For example, if you undefine (Edit → Undefine) an instruction at the start of a function, IDA will trace execution flow and delete all instructions that lose references to them.

  • Create function if data xref data->code32 exists: If IDA encounters a data reference from DATA segment to 32bit CODE segment, it will check for the presence of meaningful (disassemblable) instruction at the target. If there is an instruction, it will mark it as an instruction and will create a function there.

  • Create functions if call is present This option allows IDA to create function (Edit → Create function…) (proc) if a call instruction is present. For example, the presence of:

          call loc_1234

leads to creation of a function at label loc_1234

  • Create function tails: This option allows IDA to find and append separately located function tails to function definitions.

  • Create stack variables: This option allows IDA to automatically create stack variables and function parameters.

  • Propagate stack argument information:

This option propagates the stack argument information (the type and the name) to the caller’s stack. If the caller is called, then the information will be propagated further through the whole program. Currently, the type propagation is really simple and non-intelligent: the first encountered type for a stack variable will be used.

  • Propagate register argument information: This option propagates the register argument information (the type and the name) to the caller. If the caller is also called, then the information will be propagated further through the whole program.

  • Trace stack pointer: This option allows IDA to trace (Edit → Functions → Change stack pointer…) the value of the SP register.

  • Perform full stack pointer analysis: This option allows IDA to perform the stack pointer analysis using the simplex method. This option is valid only for the IBM PC processor.

  • Perform ‘no-return’ analysis: This option allows IDA to perform the control flow analysis and determine functions which do not return to their callers. The ‘exit()’ function, for example, does not return to its caller.

  • Try to guess member function types: If set, IDA will guess member function types using the demangled names. Please note that this rule may occasionally produce wrong results, for example, for static member functions. IDA has no means of distinguishing them from non-static member functions. If clear, IDA will guess only types of non-member functions.

See also:

Kernel analysis options 2

  • Truncate functions upon code deletion: Truncate functions when the code at the function end gets deleted. If this option is turned off, IDA does not modify function definitions when code is deleted.

  • Create string literals if data xref exists: If IDA encounters a data reference to an undefined item, it checks for the presence of the string literal at the target. If the length of the candidate string literal is big enough (more than 4 chars in 16bit or data segments; more than 16 chars otherwise), IDA will automatically create a string literal(Edit → Strings → String).

  • Check for unicode strings: This option allows IDA to check for the presence of the unicode strings in the program and creates them if necessary. IDA will check for the unicode strings only if the string style is set to “C-style (0 terminated)” or “Unicode”.

  • Create offsets and segments using fixup info: IDA will use relocation information to make the disassembly nicer. More precisely, it will convert all data items with relocation information to words or dwords like this:

          dd offset label
          dw seg seg000

If an instruction has a relocation information attached to it, IDA will convert its immediate operand to an offset or segment:

          mov     eax, offset label

You can display the relocation information attached to the current item by using the Print internal flags command.

  • Create offset if data xref to seg32 exists: If IDA encounters a data reference to 32bit segment and the target contains 32bit value which can be represented as an offset expression, IDA will convert it to an offset.

  • Convert 32bit instruction operand to offset: This option works only in 32bit and 64bit segments. If an instruction has an immediate operand and the operand can be represented as a meaningful offset expression, IDA will convert it to an offset. However, the value of immediate operand must be higher than 0x10000.

  • Automatically convert data to offsets:

This option allows IDA to convert all newly created data items to offsets if the following conditions are satisfied:

  • the offset target is a valid address in the program

  • the target address is higher than 0x20

  • the target does not point into the middle of an item

  • if the target is code, the execution does not flow to it from the previous instruction

  • the data is dword (4 bytes) in a 32-bit segment or qword(8 bytes) in a 64-bit segment

  • the segment type is not special (extern, communal, abs…)

  • Use flirt signatures: Allows usage of FLIRT technology

  • Comment anonymous library functions: This option appends a comment to anonymous library functions. The comment consists of the description of the FLIRT signature which has recognized the function and marked it as coming from a library.

  • Multiple copy library function recognition: This option allows FLIRT to recognize several copies of the same function in the program.

  • Automatically hide libary functions: This option hides the functions recognized by FLIRT. It will have effect only from the time it is set.

  • Rename jump functions as j_…: This option allows IDA to rename simple functions containing only

          jmp somewhere

instruction to “j_somewhere”.

  • Rename empty functions as nullsub_…: This option allows IDA to rename empty functions containing only a “return” instruction as “nullsub_…” (… is replaced by a serial number: 0,1,2,3…)

  • Coagulate data at the final pass: This option is meaningful only if “Make final analysis pass” is enabled. It allows IDA to convert unexplored bytes (Edit → Undefine) to data arrays in the non-code segments.

  • Coagulate code at the final pass: This option is meaningful only if “Make final analysis pass” is enabled. It allows IDA to convert unexplored bytes to data arrays in the code segments. Make final analysis pass This option allows IDA to coagulate all unexplored bytes by converting them to data or instructions. See also analysis options 1 analysis options 3

Kernel analysis options 3

  • Enable EH analysis: If this option is set on, IDA uses EH information of the binary for more detailed analysis.

  • Enable RTTI analysis: If this option is set on, IDA tries to detect C++ Run-Time Type Identification and does additional analysis based on this information.

  • Enable macros: This option is disabled if the processor module does not support macros. If this option is on, IDA will combine several instructions into one macro instruction. For example for the ARM processor:

      ADRP Rx, label@PAGE
      ADD  Rx, Rx, label@PAGEOFF

will be replaced by


      ADRL Rx, label
  • Merge strlits: If the analysis option “Create string literals if data xref exists” is set and the target string literal ends at the existing one (without a termination character), IDA will merge these strlits into one.

Cross-References options

This tab configures how cross-references (xrefs) are displayed.

Cross-references options

IDA maintains cross-references automatically. Of course, when IDA starts to disassemble a new file, the cross-references will not appear immediately; they will be collected during background analysis.

Cross-reference parts

  • Display segments in xrefs: This checkbox enables or disables segments in cross references:
           Enabled:     ; CODE XREF: 3000:1025
           Disabled:    ; CODE XREF: 1025
  • Display xref type mark: If this option is disabled, IDA will not display “CODE” or “DATA” in the cross-references.

IDA.CFG parameter: SHOW_XREF_TYPES

  • Display function offsets: This option controls the appearance of the cross-reference addresses. If it is enabled, the addresses will be displayed as offsets from a function beginning.

Example:

           Enabled:     somefunc+0x44
           Disabled:    cseg:0x4544

IDA.CFG parameter: SHOW_XREF_FUNC

  • Display xref values: If this option is disabled, IDA will just display the presence of cross-references, like this:
                ; CODE XREF: ...

IDA.CFG parameter: SHOW_XREF_VALUES

  • Right margin: Determines the maximal length of a line with the cross references.

IDA.CFG parameter: MAX_XREF_LENGTH

  • Cross reference depth: This value “how many bytes of an object to look at to collect cross references”. For example, we have an array:
                A       db 100 dup(0)

If some instruction refers to the 5-th element of the array:

                mov     al,A+5

         with TD=3      we'll have no xrefs displayed
         with TD=10     we'll have this xref

IDA.CFG parameter: MAX_TAIL

  • Number of displayed xrefs:

Determines the maximal number of the cross references to display. You may keep this value low because you can access all xrefs by using the List cross references to/from… command.
IDA.CFG parameter: SHOW_XREFS

String options

This tab sets up the string literals options.

String options

  • Generate names If this option is set, IDA will give meaningful names to newly created string literals.

Name generation

  • Prefix: The prefix inserted in the field will be used to form the string name.

  • Mark as autogenerated: If a name is marked as autogenerated, it will be displayed in a different color and will be included in the list of names [action JumpName] depending on the current setting.

  • Generate serial names: IDA can generate serial names for string literals, i.e.

                pref_001,pref_002,pref_003 etc...

To enable serial names generation, specify prefix for names, starting serial number, and number of leading zeroes.

Each time you create a string literal (Edit → Strings → String), IDA generates a new serial name and assigns it to the string.

  • String literal next line char: This symbol, when encountered in the string, will make IDA start a new line in the string representation in the disassembly. Usually it is the line feed character (‘\n’).

  • Comment string literal references: This option tells IDA to display the contents of the string literal next to the instruction or offset that refers to the string.

Browser options

This tab of IDA Options configures the disassembly browser’s display behavior, hints, highlighting and navigation features. There are two groups of settings:

Browser options

Hints

OptionDescription
Number of lines for identifier hintsSpecifies how tall the hint window will be initially. IDA may decide to display less lines than specified if the hint is small. The user can resize the hint window using the mouse wheel.
Delay for identifier hintsMilliseconds that pass before the hint appears when the user hovers the mouse pointer over an identifier.
Mouse wheel resizes hint windowPermit to resize the hint window by using the mouse wheel. Can be turned off if the user does not want to resize the hints.
No hints if debugger is activeHints will be disabled when the debugger is active. This may be useful to speed of debugging: calculating hints for zero filled ranges can be very expensive.

Other settings

OptionDescription
Auto highlight the current identifierHighlight the current identifier everywhere on the screen. IDA tries to determine if the current identifier denotes a register. In this case it will highlight references to other parts of the register. For example, if “AL” is highlighted, IDA will also highlight “AH”, “AX”, and “EAX” (if the current processor is x86).
Unhide collapsed items automatically when jumping to themIf this option is set on, IDA will automatically uncollapse hidden functions if the user decides to jump to them. As soon as the user quits the function by pressing Esc, the function is automatically collapsed again.
Lazy jumpsIf this option is set on, IDA will not redraw the disassembly window if the jump target is already on the screen. In this case, it will just move the cursor to the specified address. This option leads to less screen redraws and less jumpy behavior.
Enable history sharingThis option is enabled by default. It keeps a shared global history across multiple widgets (including Disassembly, Pseudocode, Local Types, and Stack), allowing you to navigate back and forward between them.
Number of items in navigation stack drop-down menusSpecifies the number of entries in the drop-down menu for the ‘Jump’ toolbar.
Number of lines for auto scrollSpecifies how many lines force automatic scrolling of the disassembly view.
Caret blinking intervalSpecifies how fast the input caret blinks (in milliseconds). Must be greater than or equal to 500, or zero. Zero means to disable blinking.

Graph options

This tab configures the visual appearance and behavior of graph view and proximity view.

Graph options

General

OptionDescription
Use graph view by defaultIDA switches to graph mode for each ‘jump’ command.
Enable graph animationAnimate the graph layout, movement, and group collapsing/uncollapsing. While animation takes time, it gives the user some idea what’s going on.
Draw node shadowsDisplay shadows for each graph node. Shadows are not displayed for really huge or ridiculously small nodes.
Auto fit graph into windowZoom the graph so that it occupies the whole window.
Fit window max zoom level 100%The ‘fit window’ command maximal zoom level is 100%.
Re-layout graph if nodes overlapIDA recomputes the graph layout if a node overlap is detected. The presence of a custom layout (if the user has displaced some graph nodes) effectively turns off this option.
Re-layout graph upon screen refreshIDA recomputes the graph layout at each screen refresh. Turning this option off accelerates IDA but then a manual layout might be required after some operations.
Truncate at the right marginAll nodes at truncated at the right margin. The right margin is specified in the Options → General → Disassembly tab. This option narrows the graph but hides some information by truncating long lines.
Lock graph layoutLocks the graph layout by ignoring attempts to displace nodes. This prevents the creation of custom layouts that might lead to ugly graph layouts when nodes change their sizes.

Proximity view

OptionDescription
Show data referencesShow data cross-referenced items in proximity view.
Hide library functionsDo not show data or code cross-references to library functions, only show cross-referenced local functions.
Unlimited children recursionRecurse until there are no more callees (children) of the currently selected central node and all of his children.
Recurse into library functionsDisplays children data or code cross-references from library functions.
Max parents recursionMaximum recursion level for displaying parents of the currently selected central node. The value 0 disables parents recursion.
Max children recursionMaximum recursion level for displaying children of the currently selected central node. The value 0 means no maximum recursion level.
Max nodes per levelMaximum number of nodes to show per level of children and parents.

Lumina options

This tab configures Lumina server connection settings.

Lumina options

Servers

  • Use public: Sets host and port to the default public server hosted by Hex-Rays. No username or password is required.

Private server authentication

Specify the username and password credentials for a Private Lumina server.

Automatically use Lumina server for analysis

Instructs IDA to fetch function metadata from the current Lumina server, after the initial auto-analysis is complete. This helps with the recognition of known functions stored in the database of the Lumina server.

Lumina command line options

Command line switch '-Olumina' overrides for ida session the primary server and '-Osecondary_lumina' the secondary one.

List of options

OptionDescription
hostlumina server host
portlumina server port
userusername for authentification on private lumina
passpassword for authentification on private lumina
proxy_hostproxy host
proxy_portproxy port
proxy_userusername for authentification on proxy
proxy_passpassword for authentification on proxy

Example

  -Osecondary_lumina:host=lumina.hex-rays.com:port=443

Use the public lumina as secondary server for this ida session

Miscellaneous options

This tab configures miscellaneous options including editor settings, encoding and types autocompletion.

  • Editor: A text editor is to be used when the user decides to edit an IDC script using the IDC toolbar.

  • Navigation band refresh interval (milliseconds): Specifies how often the navigation band will be refreshed. IDA tries to minimize the number of redrawings because they could be really time and processor consuming (imagine a huge program, 50-100 megabytes of code. It would take a long time to refresh information on the navigation band because the whole program will be examined to determine how to draw the band). If this option is set to 0, the navigation band is refreshed only when the cursor is moved far enough to reflect its movement on the band.

  • Convert already defined bytes: Determines how IDA should behave when user operations would end up redefining some already-defined bytes.

  • Associate .IDB file extension with IDA: Whether or not the .IDB extension should be associated, at the OS-level, with IDA.

  • Enable autocomplete in forms: Determines whether input fields should provide an auto-complete combo box by default.

  • Output files encoding: The encoding used to generate output text files from IDA. The value ‘’ means that the IDB’s default 8 bit-per-unit encoding will be used.

Types autocompletion

OptionDescription
Enable autocomplete for typesEnables or disables the entire autocomplete mechanism for types. If you uncheck the box, the behavior will not differ from previous versions. Enabled by default.
Case sensitiveChanges case sensitivity. When enabled, for example, the prefix b will show bucket but not BigStruct. Disabled by default.
Enable autocomplete for curly bracesEnables or disables autocompletion of curly braces and indents. When enabled, typing { inserts a closing brace on a new line, with an indented empty line and the cursor placed in between. Enabled by default.
Enable type hintsEnables or disables hints when selecting a type from the autocomplete suggestions. These hints behave similarly to the hints in Local Types. Enabled by default.

Colors…

Setup colors. The IDA Colors dialog lets you change the active theme or fine-tune the one currently in use. Each tab lets you customize specific parts of the UI.

IDA Colors

IDA keeps the color configuration in the registry. There are 3 predefined schemes. The user can modify the existing schemes or add his own schemes. New schemes should be added to the “themes” subdirectory in IDA.

Windows 11 style contrast

By default, IDA uses the “out-of-the-box” Qt style - named windows11.

That style mimics the core Microsoft Windows 11 theme, with which some users have reported some discomfort due to low-contrast hints.

This is observable especially in “tabular” widgets, where the selection painted using an somewhat discrete overlay:

Windows 11 style tabular view selection

Addressing this naïvely (e.g., by overriding the selection entries through CSS) might do more harm than good though, so we have decided against that.

Instead, we recommend using the Qt “Fusion” style, which offers significantly better contrast:

Fusion style tabular view selection

This is achievable by opening the “Environment variables” dialog, and adding an entry called QT_STYLE_OVERRIDE with the value fusion.

Font…

Setup font. This dialog allows you to customize the font used in listings.

Select font for: Listings

Feature Flags…

Configure feature flags. This dialog lists optional features that can be enabled or disabled. By default, the two options below are enabled, supporting the new JumpAnywhere feature:

  • Override G shortcut with new Jump Anywhere dialog.
    • (If disabled, the G will continue to trigger “Jump to address…” dialog).
  • Enable preview pane in Jump Anywhere dialog.

Shortcuts…

Edit shortcuts. This dialog allows you to view and customize all keyboard shortcuts used in IDA. You can use Ctrl + F to search by command name or keyboard shortcut.

Shortcuts

Show command palette…

Show command palette. This command opens a dialog, that provides quick access to all available IDA actions with shortcuts and descriptions.

Command palette

Reset undo history

Reset undo history. This command clears the undo history. After it the Undo and Redo commands become unavailable. However, once the user performs a new action, IDA will again start journaling all database modifications.

A side effect of this command is fast autoanalysis: since there is no user action to revert yet, IDA does not maintain undo buffers and this speeds up the analysis.

Assembler directives…

Setup assembler directive generation.

This command enables/disables the generation of some assembler directives, namely:

  • assume directive
  • origin directive Sometimes (when you do not intend to assemble the output file), you may want to disable their generation.

Name representation…

Setup name representation. Dummy names are automatically generated by IDA. They are used to denote subroutines, program locations and data. Dummy names have various prefixes depending on the item type and value:

PrefixDescription
sub_instruction, subroutine start
locret_‘return’ instruction
loc_instruction
off_data, contains offset value
seg_data, contains segment address value
asc_data, string literal
byte_data, byte
word_data, 16-bit
dword_data, 32-bit
qword_data, 64-bit
byte3_data, 3 bytes
xmmword_data, 128-bit
ymmword_data, 256-bit
packreal_data, packed real
flt_floating point data, 32-bit
dbl_floating point data, 64-bit
tbyte_floating point data, 80-bit
stru_structure
custdata_custom data type
algn_alignment directive
unk_unexplored byte

You can change representation of dummy names. IDA supports several types of dummy names:

FormatExampleDescription
0loc_0_1234segment base address relative to program base address & offset from the segment base
1loc_1000_1234segment base address & offset from the segment base
2loc_dseg_1234segment name & offset from the segment base
3loc_0_11234segment relative to base address & full address
4loc_1000_11234segment base address & full address
5loc_dseg_11234segment name & full address
6loc_12full address
7loc_0012full address (at least 4 digits)
8loc_00000012full address (at least 8 digits)
9dseg_1234the same as 2, but without data type specifier
10loc_1enumerated names (loc_1,loc_2,loc_3…)

If you have selected names type 10 (enumerated names), you may renumber them using a checkbox. The process is relatively fast, surprisingly.

The best representation for MS DOS programs is #0, for 16-bit processors - #7, and for 32-bit processors - #8. You can change dummy names type any time you want.

You can also set up types of names included in the name list (Jump by name… command, action JumpName). IDA knows about the following types of names:

  • normal names
  • public names
  • weak public or extern names
  • autogenerated (meaningful) names.
  • dummy (meaningless) names.

Dummy names may be public or weak, but they never appear in the list of names. You can specify the type of a name when you create or rename it.

You can also set maximal length of new names. Old names will not be affected by this parameter.

See also: the Rename command.

Demangled names…

Setup C++ demangled name representation. IDA can demangle mangled C++ names of the most popular C++ compilers:

  • Microsoft
  • Borland
  • Watcom
  • Visual Age
  • GNU

The demangled names are represented in two forms: short and long form. The short form is used when a name is used as a reference, the long form is used at the declaration.

You can set how demangled C++ names must be represented:

  • as comments: this representation allows you to obtain recompilable source text
  • instead of mangled names: this representation makes the output more readable (the disadvantage is that you cannot recompile the output)
  • don’t display demangled names.

You can setup short and long forms of demangled names. Short form is used when a reference to the name is made; long form is used at the declaration.

To make demangled names more readable, we introduce the possibility to suppress pointer modifiers (near/far/huge).

To demangle GNU C v3.x names, the “Assume GCC v3.x names” checkbox should be set, otherwise such names might not be demangled. Furthermore, to make the demangled name more compact, unsigned types may be displayed as uchar, uint, ushort, ulong. The same with signed basic types.

If the “Override type info” checkbox is set, the demangled name overrides the type information if both are present.

See also How to customize demangled names

Compiler…

Setup target compiler and its parameters. This dialog allows the user to specify the compiler used to create the program along with the memory model, default calling convention, ABI and other parameters. Please note that while some combinations of the parameters are meaningless, IDA doesn’t check them for validity. It is up to the user to specify a correct combination.

IDA tries to determine the correct values automatically.

The include directories are a list of directories that look for the standard C headers. This parameter is used during parsing C header files (the Parse C header file… command; action LoadHeaderFile). The directories must be separated by ‘;’ in MS Windows and ‘:’ in Linux. The predefined macros field has the same format and is used similarly. Please note that IDA doesn’t define any compiler-specific macros by default.

Parser options

You can select between different parsers using the parser settings located at the bottom of the Compiler options dialog.

Compiler - Parser options

IDA provides three parser options:

  • legacy - old internal IDA parser (will be removed in future versions)
  • old_clang - previous parser based on clang
  • clang - new parser introduced in IDA 9.2, (based on LLVM)

Parser Configuration

The old_clang and new clang parser can be fine-tuned using the Parser specific options dialog.

Parser specific options

String literals…

Setup string literal style. With this dialog you can setup string styles and also create a new string immediately at the current location.

The following string styles are defined:

  • C-style (zero-terminated)
  • DOS style ($ terminated)
  • Pascal style (one byte length prefix)
  • Wide pascal (two-byte length prefix)
  • Delphi (four-byte length prefix)
  • Unicode (UTF-16)
  • Unicode pascal style (two-byte length prefix)
  • Unicode wide pascal style (four-byte length prefix)
  • Character terminated

If you select “character terminated” string style then you may specify up to 2 termination characters. The string will be terminated by any of these characters. If the second character is equal to 0, then it is ignored. In IDA Qt you can also set a specific encoding to be used to display the string, or change the defaults for all strings.

String encodings

IDA Qt can display program strings using different encodings. You can specify default encodings for all strings or override the encoding of a specific string.

The following encodings can be used:

  • <default> - the default encoding for this string type (8-bit or 16-bit)
  • <no conversion> - the string bytes are printed using the current system encoding (after translating with XlatAsciiOutput array in the configuration file).
  • Windows codepages (e.g., 866, CP932, windows-1251)
  • Charset names (e.g., Shift-JIS, UTF-8, Big5)

You can add new encodings to the list using the context menu item Insert (Ins hotkey).

On Linux/OS X, you can run “iconv -l” to see the available encodings. Please note that some encodings are not supported on all systems.

Setup data types…

Setup data types. This command allows you to select the data types used in the round-robin carousel in the Data (action MakeData) command.

Valid data types are:

Data TypeSize
byte
word2 bytes
double word4 bytes
float4 bytes
quadro word8 bytes
double8 bytes
long double10 or 12 bytes
packed real10 or 12 bytes
octa word16 bytes

Naturally, not all data types are usable for all processors. For example, Intel 8051 processor doesn’t have the ‘double word’ type. Furthermore, this command allows you to select a data type for the current undefined item and convert it to data. Please note that if the current processor does not support a data type, you cannot assign it even if you have selected it. If you unselect all data types, IDA will use the ‘byte’ type.

Source paths…

Setup source paths. In this dialog you can configure path mappings to help IDA locate source files in different locations.

Windows menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Load desktop…LoadDesktopThis commands show all available desktops (stored in the database or in the registry). More…
Save desktop…SaveDesktopThis command saves the current desktop configuration to a desktop. More…
Delete desktop…DeleteDesktopThis command deletes a desktop containing a desktop configuration.
Reset desktopResetDesktopThis command resets all windows (IDA main window and database windows) by loading the original IDA disassembly desktop or debugger desktop(if the debugger is active).
Reset hidden messages…ResetHiddenMessagesReset hidden messages
Windows listWindowsListDisplay list of the currently open windows
Next windowNextWindowSwitch to the next window
Previous windowPrevWindowSwitch to the previous window
Close windowCloseWindowClose the current window
Focus command lineFocusCLI2Focus command line
Output windowOutputWindowDisplay the output window if hidden. More…
FunctionsWindowActivate1Functions
IDA View-AWindowActivate2IDA View-A
Pseudocode-AWindowActivate3Pseudocode-A
Hex View-1WindowActivate4Hex View-1
Local TypesWindowActivate5Local Types
ImportsWindowActivate6Imports
ExportsWindowActivate7Exports
Switch to window #8WindowActivate8Switch to window #8
Switch to window #9WindowActivate9Switch to window #9

Load desktop…

This commands show all available desktops (stored in the database or in the registry). Pressing Enter loads the desktop configuration from the selected desktop. Pressing Del> deletes the selected desktop.

Save desktop…

This command saves the current desktop configuration to a desktop. If you enter a name, IDA saves the current configuration to a named desktop in the database or registry. If you select ‘Default’, IDA saves the current configuration to the Default or Default debugger desktop (if the debugger is active) in the registry.

Output window

Display the output window if hidden. The Output window appears at the bottom of IDA’s interface by default and serves two key purposes:

  • Displays various IDA messages and notifications.
  • Provides a command line interface (CLI) for executing IDC or IDAPython commands.

Output window

If closed, you can reopen it via Windows -> Output window.

Context Menu Options

Right-click in the Output window to access these options:

  • Select All: Selects all content in the window
  • Find/Find next: Searches for a specific string
  • Clear: Removes all previous messages from the window
  • Copy to CLI: Places selected text into CLI field
  • Save to file: Exports window content to a .log file
  • Show timestamps: Displays time information with each message
  • Font…: Customizes the text appearance (font, style, size)

You can duplicate all messages appearing in this window to a file. To do this, you have to define an environment variable before starting IDA:

set IDALOG=logfile

Command Line Providers

Currently, the following command line providers exist:

  • IDC
  • Python
  • Bochs debugger
  • WinDbg debugger
  • GDB debugger

Command-line

When these plugins are active, they will process the entered commands. The current command language can be changed by clicking the button to the left of the input field. The current language can be set as default by choosing “Default CLI” from the context menu of the command line.

The command-line input field can be activated by pressing ., while Esc switches back to the previous window.

Help menu actions for Common

Below is an overview of all actions that can be accessed from this menu.

UI Action NameAction NameDescription
Online helpToggleOnlineManualUse either the online, or bundled IDA manual
HelpShowHelpHelp
API Documentation``
Python APIHelpPythonAPIPython API
IDA SDKHelpIDASDKIDA SDK
Decompiler SDKHelpHexraysSDKDecompiler SDK
IDC FunctionsHelpIDCFunctionsIDC Functions
About program…AboutAbout program
License manager…LicenseManagerOpen license manager. More…
How to buy IDABuyIDAHow to buy IDA
IDA home pageHomepageIDA home page
IDA support forumSupportForumIDA support forum
Send database…hx:SendIDBSend database
Extract function…hx:ExtractFuncExtract function
Check for free update…CheckFreeUpdateCheck for free update
Report a bug or an issue…BugReportReport a bug or an issue

License manager…

Open license manager. The license manager dialog (Help -> License manager…) lets you pick a license to use IDA with.

Depending on your licensing plan (e.g., floating), you may have the possibility to switch between various licenses located on the same license server (but having different sets of add-ons & decompilers, for example).

The active license is represented in bold in the list. Double-clicking on a line in the list, will make that license active, and make it the preferred license.

Preferred license

Doing so will also make it the “preferred” license – that is, it will be remembered for later sessions as being the default license to use.

Borrowing & returning licenses

When using floating licenses from a server, it is possible to borrow the license for an extended period of time, thereby allowing offline work. Please use the context menu to achieve that.

License management command line options

IDA recognizes the -Olicense command-line switch, with the following format:

  1. -Olicense:keyfile=<path-to-.hexlic-file>[:setpref]
  2. -Olicense:server[:host=<hostname>][:port=<port>][:lid=<xx-xxxx-xxxx-xx>][:setpref]

Where the optional bits are:

keyfilePath to the license file
hostThe license server host name
portThe license server port
lidThe license ID to use
setprefWhether the selected license should be remembered as the preferred license

The command-line switch -Olicense takes precedence over both:

  1. the preferred license information possibly stored in the registry, and
  2. the IDA_LICENSE environment variable

NOTE: The -Olicense switch (or IDA_LICENSE) will not, by default, overwrite the “preferred” license information in the registry. Specify setpref to achieve that.

NOTE: On Windows, the <DriveLetter>: scheme is recognized. Therefore -Olicense:keyfile=C:/tmp/my.hexlic:setpref will work as expected.

License management environment variable

Alternatively, the IDA_LICENSE environment variable can be used to specify licensing information, and accepts the same format as the -Olicense option

E.g., IDA_LICENSE=server:host=<hostname>:…

Desktops

IDA saves different settings in desktops: the main window configuration, the toolbars configuration, and the configuration of all database windows.

Different desktops are available:

  • <Database>
    This desktop configuration is stored in the database itself, and is automatically loaded each time you open this database. IDA also automatically saves the current desktop configuration to this desktop if you close and save the database.

  • <Database debugger>
    This desktop configuration is also stored in the database, and is loaded each time you start the debugger. As for the <Database> desktop, IDA automatically saves the current desktop configuration to this desktop once the debugger stops.

  • <Default>
    This desktop configuration is stored in the registry, and is loaded each time you start IDA without opening a database, or the first time you create a new database.

  • <Default debugger>
    This desktop configuration is stored in the registry, and is loaded the first time you start the debugger.

  • Named desktops
    These desktop configurations are stored in the registry, and can be loaded manually by the user during the disassembly or the debugging.

Notice IDA will use a default configuration for main windows and toolbars if the screen resolution changed.

Subviews

Subviews (also referred to as windows, widgets, or simply views) are an essential part of working with IDA, providing different perspectives and detailed information about the loaded binary.

Subviews essentials

  • Some subviews are opened by default, while others can be accessed at any time via View → Open subviews.
  • Certain subviews, (known as choosers) are list views, that allow you to interact with and manipulate their contents using list viewer commands.
  • All subviews windows can be moved, rearranged and docked in various parts of the IDA interface.

The following is a list of all available subviews.

IconViewAccess ModeShortcut
IconDisassembly/IDA ViewInteractive (r/w), address-based-
IconPseudocodeInteractive (r/w), address-basedF5
IconHex ViewInteractive (r/w), address-based-
IconAddress detailsRead-only chooser-
IconExportsRead-only chooser-
IconImportsRead-only chooser-
IconNamesRead-only chooserShift + F4
IconFunctionsRead-only chooserShift + F3
IconStringsRead-only chooserShift + F12
IconStack VariablesInteractive (r/w)Ctrl + K
IconSegmentsInteractive (r/w)Shift + F7
IconSegments RegistersInteractive (r/w)Shift + F8
IconSelectorsInteractive (r/w)-
IconSignaturesInteractive (r/w)Shift + F5
IconType librariesInteractive (r/w)Shift + F11
IconLocal TypesInteractive (r/w)Shift + F1
IconCross ReferencesInteractive (r/w)-
IconCross References TreeInteractive (r/w)Shift + X
IconFunction callsRead-only chooser-
IconBookmarksInteractive (r/w)Ctrl + Shift + M
IconNotepadInteractive (r/w)-
IconProblemsRead-only chooser-
IconPatched bytesRead-only chooserCtrl + Option + P
N/ANavigation historyRead-only chooser-
IconUndo historyRead-only chooser-
IconMicrocodeInteractiveCtrl + Shift + F8

IDA View / Disassembly window

{% hint style=“info” %} While working in the IDA/Disassembly view, the actions available under the Edit, Jump and Search menus may differ from those in other views. For more information, see View-Dependent Menus. {% endhint %}

IDA View has three modes:

  • Flat/linear mode (1)
  • Graph mode (2)
  • Proximity mode (3)

IDA automatically opens one disassembly window (IDA view) at the start. If the current location is an instruction belonging to a function, then the graph view is available. You can toggle between the flat and graph view using the Space key. You can also switch to proximity view by zooming out to the callgraph using the - key.

IDA View modes

Arrows on the left side of the flat mode represents the control flow. The IDA UI highlights the current identifier.

Disassembly - arrows

{% hint style=“info” %}

Synchronized views

By default, the IDA View and Hex View are synchronized. Navigating in one of these views automatically updates the cursor position in the others. You can disable/enable this behavior via the context menu by selecting Synchronize with. It’s worth mentioning that any address-based view (including IDA View, Pseudocode, or Hex View) can be synchronized with another. For more information on view synchronization, see Igor’s Tip of the Week on synchronized views. {% endhint %}

Arrows window

There is a small window with arrows on the left of the disassembly. These arrows represent the execution flow, namely the branch and jump instructions. The arrow color can be:

  • red: means that the arrow source and destination do not belong to the same function. Usually, the branches are within functions and the red color will conspicuously represent branches from or to different functions.
  • black: the currently selected arrow. The selection is made by moving to the beginning or the end of the arrow using the Up or Down keys or left-clicking on the arrow start or the arrow end. The selection is not changed by pressing the PageUp, PageDown, Home, End keys or using the scrollbar. This allows to trace the selected arrow far away.
  • grey: all other arrows

The arrow thickness can be:

  • thick: a backward arrow. Backward arrows usually represent loops. Thick arrows represent the loops in a clear and notable manner.
  • thin: forward arrows.

Finally, the arrows can be solid or dotted:

  • the dotted arrows represent conditional branches,
  • the solid arrows represent unconditional branches.

You can resize the arrows window using a vertical splitter or even fully hide it. If it is hidden, the arrows window will not be visible on the screen but you can reveal it by dragging the splitter to the right. IDA remembers the current arrow window size in the registry when you close the disassembly window.

Refine the disassembly results

Use the disassembly editing commands to improve the listing.

Set the anchor

Use Shift + or Alt + L to drop the anchor. If you have a mouse, you can drop the anchor with it too.

A double click of the mouse is equivalent to the Enter key.

Set disassembler options

Go to the Options → General → Disassembly to customize what information is displayed in the disassembly window.

Pseudocode window

{% hint style=“info” %} While working in the Pseudocode view, the actions available under the Edit, Jump and Search menus may differ from those in other views. For more information, see View-Dependent Menus. {% endhint %}

The Pseudocode view shows the assembly language translated into human-readable, C-like pseudocode. You can decompile the current function by F5 shortcut, and navigate between IDA disassembly and pseudocode with Tab.

Pseudocode view

Hex View / Hex dump window

{% hint style=“info” %} While working in the Hex view, the actions available under the Edit, Jump and Search menus may differ from those in other views. For more information, see View-Dependent Menus. {% endhint %}

Hex View shows the raw bytes of the program’s instructions or data.

There are two ways of highlighting the data in the Hex Dump:

  • Text match highlight, which shows matches of the selected text anywhere in the views
  • Current item highlight, which shows the bytes group constituting the current item

Hex dump view

Address details window

The Address details view displays detailed information about the current address selected in the IDA View, Hex View, or Pseudocode window. It updates automatically as you change location. By default, it opens on the right side of the main IDA window and consist of the below sections:

  • Name assigned to address; allows you to rename location (1)
  • Flags displays low-level details associated with the address, alternatively to print internal flags action (2)
  • Data inspector displays how the bytes at the current address can be interpreted in different formats (3)

Address details view

Exports window

This view shows list of all exported symbols. The columns display the following information:

  • Name of the exported symbol
  • Address of the exported symbol inside the analyzed program
  • Ordinal of the exported symbol

Exports view

You can use list viewer commands in this window.

Imports window

This view shows list of all symbols imported through dynamic linking. The columns display the following information:

  • Address of the imported symbol (located in virtual imports segment)
  • Ordinal of the imported symbol
  • Name of the imported symbol
  • Shared Library name from which the symbol is imported

Imports view

You can use list viewer commands in this window.

Functions window

{% hint style=“info” %} While working in the Functions view, the actions available under the Edit, Jump and Search menus may differ from those in other views. For more information, see View-Dependent Menus. {% endhint %}

This view presents all functions in the program. Functions view is a part of IDA’s default desktop layout and displays on the left side of the screen. You can add, delete, modify functions using list viewer commands.

Functions view

Each function entry includes the following details:

  • Function name
  • Segment that contains the function
  • Function Start address
  • Function Length in bytes
  • size (in bytes) of Locals + saved registers
  • size (in bytes) of Arguments passed to the function

The last column of this window has the following format:

SymbolMeaning
RFunction Returns to the caller
FFar function
LLibrary function
SStatic function
MLumina function
OOutlined function
BBP based frame. IDA will automatically convert all frame pointer [BP+xxx] operands to stack variables.
Tfunction has Type information
=Frame Pointer is equal to the initial stack pointer. In this case, the frame pointer points to the bottom of the frame
Xexception handling code; c stands for “catch” block, u means that the corresponding function is an unwind handler.

Colors and style indicators

Some functions in the list may appear with colored backgrounds. In most cases, these colors correspond to the legend used in the navigation band. Additional colors may be manually assigned the user via Edit function… in the context menu.

Functions displayed in bold have a definitive, user-specified prototype. Some plugins may also mark functions this way. The decompiler takes such prototypes as they are, while other prototypes are considered only as a starting point during decompilation.

Synchronize Functions view

You can automatically synchronize the function list with the active Disassembly, Pseudocode, or Hex view. To enable this, right-click in the function list and select Turn on synchronization in the context menu.

For a thorough overview of the Functions view, refer to Igor’s Tip of the Week #28.

Names window

Names view displays the list of all names existing in the database, not only function names but also instruction or data items names.

Names view

On the left side of the Name column, this view displays a small icon for each name:

SymbolMeaning
Llibrary function
𝑓regular function
Cinstruction
Astring literal
Ddata
Iimported name

You can use list viewer commands in this window.

Signatures window

This view displays both applied and planned signatures, and allows you to apply new ones.

For each signature, the following columns are shown:

  • Name of the file with the signature
  • State of the signature:
    • Planned: the signature will be applied
    • Current: the signature is being applied
    • Applied: the signature has been applied
  • #func: number of functions found using the signature

Signatures view

In this view, you can modify the list of planned signatures and add or remove library modules to be used during disassembly. Note that applied signatures cannot be removed from the list.

Add signatures

To add a signature to the list, right-click in the signatures view and click Apply new signature… in the context menu or press Ins. You will see a list of signatures that can be applied to the program being disassembled.

Text version: Not all signature files will be displayed (for example, 32 bit signatures will not be shown for a 16 bit program). If you want to see the full list of signatures, select the first line of the list saying SWITCH TO FULL LIST OF SIGNATURES.

Signature files location / SIG directory

Signature files reside in the subdirectories of the SIG directory. Each processor has its own subdirectory. The name of the subdirectory is equal to the name of the processor module file (z80 for z80.w32, for example). Note: IBM PC signatures are located in the SIG directory itself.

{% hint style=“info” %} The IDASGN environment variable can be used to specify the location of the signatures directory. {% endhint %}

Segments window

This view lists information about memory segments containing code and data.

Segments view

Each segment is represented by a line in the list. Please note that the end address of the segment never belongs to the segment in IDA.

The following columns (segment attributes) are displayed:

AttributeMeaning
NameSegment name
StartVirtual start address
EndVirtual end address
RR: readable, .: not readable, ?: unknown
WW: writable, .: not writable, ?: unknown
XX: executable, .: not executable, ?: unknown
DD: debugger only, .: regular
LL: created by loader, .: no
AlignSegment alignment
BaseSegment base selector or address
TypeSegment type
ClassSegment class — CODE: machine code instructions DATA, CONST: initialized data segment BSS, STACK: uninitialized data segment XTRN: imports
ADSegment addressing width

The rest of the columns display the default values of the segment registers for the segment.

By default, the cursor is located on the current segment.

You can use list viewer commands in this window.

In order to change the selector values, use selectors window.

Add new segment

To add a new segment to the list, right-click in the Segments view and click Add new segment… in the context menu or press Ins.

Segment registers window

This view contains segment register change points list.
Depending on the current processor type, you will see various segment registers such as DS, ES, SS, and potentially FS and GS. The Tag column indicates how each change point was created:

  • a — added automatically by IDA during autoanalysis
  • u — specified by the user or defined by a plugin
  • a — added automatically by IDA during autoanalysis
  • u — specified by the user or defined by a plugin

Segment registers view

You can use list viewer commands in this window.

Change points essentials

When IDA encounters an instruction which changes a segment register, it creates a segment register change point. So, mostly change points are maintained by IDA itself. IDA assumes that the segment registers do not change their values between change points. If you find out that IDA failed to locate a segment register change, or if you want to change a register value, you can create a change point using the Change segment register value… command (action SetSegmentRegister). You can change the value of a segment register using the Set default segment register value… command too (action SetSegmentRegisterDefault).

IDA generates the appropriate ‘assume’ instructions for the change points if it was not disabled (Options → Assembler directives…)

  • For additional segment management options, refer to the Edit → Segments submenu.

Selectors window

Here you can change the “selector to base” mapping. The selector table is used to look up the selector values when calculating the addresses that are visible in the disassembly listing.

Selectors view

You can use list viewer commands in this window:

  • jump to the paragraph pointed by the selector
  • add a new selector
  • delete selector (if it is not used by any segment)
  • change selector value (this leads to reanalysis of all program)
  • jump to the paragraph pointed by the selector
  • add a new selector
  • delete selector (if it is not used by any segment)
  • change selector value (this leads to reanalysis of all program)

Cross references window

This view contains all cross references (xrefs) to the current location. You can use list viewer commands in this window.

Cross reference attributes

The cross reference dialog displays a list of references to the various items. Each line has the following attributes:

  • Direction: Up or Down. Meaningful for program address; denotes where the reference comes from, from the lower addresses than the reference target (down) or from higher addresses (up).

  • Type: The following types exist:

TypeDescription
ooffset, the address of the item is taken
rread access
wwrite access
ttextual referenced (used for manually specified operands)
iinformational (e.g. a derived class refers to its base class)
Jfar (intersegment) jump
jnear (intrasegment) jump
Pfar (intersegment) call
pnear (intrasegment) call
^ordinary flow
sxref from a structure
mxref from a structure member
kxref from a stack variable
  • Address:

    • For ‘xrefs to’ dialogs: where the reference comes from (source)
    • For ‘xrefs from’ dialogs: where the reference goes to (destination)
  • Text: Additional info about the cross reference

Add cross reference (1)

To add a new cross reference to the list, right-click in the xrefs view and click Add cross-reference… in the context menu or press Ins.
In the Add Cross Reference dialog, you should specify the From and To address, as well as the xref type.

Add/delete xrefs

Delete cross reference (2)

To remove a cross reference from the list, right-click in the xrefs view and click Delete cross-reference… in the context menu or press Del. If the Undefine if no more xrefs is checked, then the instruction at the target address will be undefined upon the deletion of the last xref.

{% hint style=“info” %} IDA undefines instructions only if they do not start a function. {% endhint %}

Cross references tree window

The cross references tree view provides a comprehensive, textual view of inter-function code and data relationships. This non-modal widget displays both code and data references in a hierarchical tree format and is designed to complement the Xref Graph. The view shows both references to and from the current function, providing a clear overview of function call hierarchies.

Cross references tree view

Key features:

  • Non-modal/multiple instances: You can open several windows simultaneously, each displaying different functions
  • Real-time updates: Nodes update as you navigate through the database

Options

Click Options above the view to expand the available settings. Key options to be aware of:

  • Sync: synchronizes the current tree with the IDA View
  • Simplified view: when unchecked, displays the full function names, e.g., int main(int argc, char **argv)
  • Allow Duplicates: when checked, shows multiple cross-references to the same function

Function calls window

This view displays an overview of calls to and from the current function:

  • All functions who call the current function are displayed at the top section of the window (1)
  • All functions called from the current function are displayed at the bottom section of the window (2)

Function calls view

The list is automatically refreshed when the cursor is moved to another function.

Local Types window

{% hint style=“info” %} While working in the Local Types view, the actions available under the Edit, Jump and Search menus may differ from those in other views. For more information, see View-Dependent Menus. {% endhint %}

The Local Types window serves as your central hub for managing custom data types within your IDA database. It allows you to create and edit custom types—such as structures, unions, and enumerations—and import definitions from loaded type libraries.

Local Types view

Each database has a local type library embedded into it. This type library (til) is used to store types that are local to the current database. They are usually created by parsing a header file.

{% hint style=“info” %} As of IDA 9.0, the legacy Structure and Enums windows have been removed and their functionality consolidated by the Local types window. This view serves as a centralized place for all type-related actions. {% endhint %}

Local types essentials

In the Local types view, you can directly manage custom data types:

  • the existing types can be modified (the default hotkey is Ctrl+E, context menu Edit type…)
  • the existing types can be deleted (the default hotkey is Del, context menu Delete type…)
  • new types can be added (the default hotkey is Ins, context menu Add type…)
  • multiple types can be added at once by parsing declarations (context menu Parse declarations…)

Please note that Ins can be used to add many types at once. For that the user just needs to enter multiple declarations, one after another in the dialog box.

However, Ctrl + E permits for editing of one type at a time. This may cause problems with complex structure types with nested types. Nested types will not be saved by Ctrl + E.

If the edited type corresponds to an idb type (struct or enum), then the corresponding type will be automatically synchronized.

Some types in this list are created automatically by IDA. They are copies of the types defined in the Local Types views. Such types are displayed in gray, as if they are disabled.

Types displayed in black are considered as C level types. Read more.

Each type in the local type library has an ordinal number and may have a name.

Be careful when deleting existing types because if there are references to them, they will be invalidated.

A local type can be mapped to another type. Such an operation deletes the existing type and redirects all its references to the destination type. Circular dependencies are forbidden. In the case of a user mistake, a mapped type can be deleted and recreated with the correct information.

Type libraries window

Type libraries view

This view displays the currently loaded type libraries and allows you to load or unload them as needed.

The standard type libraries contain type definitions from the standard C header supplied with compilers. Usually, IDA tries to determine the target compiler and its type libraries automatically but if it fails, this window allows you to load the appropriate type library.

Loading/unloading additional libraries

To load new libraries, right-click in the view and click Load type library… in the context menu or press Ins. Analogically, use Unload type library(ies)… to remove it from the list.

Configure compiler and memory model

Don’t forget to specify the compiler and memory model in the compiler setup (Options → Compiler…) dialog box.

Local Types bookmarks

Check Choose marked location help message.

Strings window

The Strings view contains all strings in the program. However, if a range of addresses was selected before opening the window, only the selected range will be examined for strings.

The columns display the following information:

  • Address
  • Length in bytes
  • Type:
    • C for standard 8-bit strings, or
    • C16 for Unicode (UTF-16)
  • String text

Strings view

Strings view options

You can set up the list parameters by clicking Setup in the context menu.

The list always contains strings defined in the program, regardless of the settings in this dialog box, but the user can ask IDA to display strings not yet explicitly defined as strings.

The following parameters are available:

Display only defined strings

If checked, IDA will display only strings explicitly marked as string items (using the convert to string (action MakeStrlit) command). In this case, the other checkboxes are ignored.

Ignore instructions/data definitions

If checked, IDA will ignore instruction/data definitions and will try to treat them as strings. If it can build a string with the length greater than the minimal length, the string will be displayed in the list. This setting is ignored if ‘only defined strings’ is on.

Strict ASCII (7-bit) strings

If checked, only strings containing exclusively 7-bit characters (8th bit must be zero) will be added to the list. Please note that the user can specify which characters are accepted in the strings by modifying the StrlitChars parameter in the ida.cfg file. This setting is ignored if ‘only defined strings’ is on.

Allowed string types

Allows the user to specify the string types included in the list. This setting is ignored if ‘only defined strings’ is on.

Minimal string length

The minimal length the string must have to be added to the list.

{% hint style=“info” %} Click Rebuild… from the context menu to refresh the list after changing the options. {% endhint %}

Stack variables window

The Stack view displays local variables and function parameters for the currently analyzed function. It allows you to view, create, edit, and rename stack variables for the current function. To open it:

  • Go to Edit → Functions → Stack variables… or press Ctrl + K
  • Double-click or press Enter on a stack variable (in the Pseudocode or Disassembly/IDA View).

Stack variables view

Bookmarks window

This view displays list of all bookmarks and allows you to manage them. In IDA, bookmarks can be placed on any address in the database, so you can use them to quickly find a location.

Bookmarks view

In the IDA View, bookmarks are shown in the arrows panel. The active bookmark is highlighted in celadon and marked with a star icon. Double-clicking an active bookmark will remove it.

Active bookmarks in the IDA View

Adding bookmarks

You can add a bookmark to the selected location from Jump → Mark position to every address-based view (IDA View, Hex View and Pseudocode), as well to the Local types view. In the opened dialog, enter the bookmark description and click OK.

Creating folders

To organize your bookmarks into folders, select the chosen bookmarks, right-click in the view and click Create folder with items… in the context menu or press Ins.

Notepad window

The Notepad window is a convenient place to store general notes related to the current database. All notes entered here are automatically saved within the database itself.

Notepad view

Common shortcuts

  • Alt + T search for text
  • Ctrl + T repeat the last search

Problems window

The Problems window contains the list of all problems encountered by IDA during disassembling the program. You can jump to a problem by pressing Enter. The selected problem will be deleted from the list.

Problems view

Patched bytes window

The Patched bytes view shows the list of the patched locations in the database. It also allows you to revert modifications selectively.

Patched bytes view

Reverting changes

Select location(s) and click Revert… from the context menu to revert this modification.

Patching bytes

You can change individual bytes via Edit → Patch program → Change byte….

This view displays the saved navigation history. When history sharing is enabled (default setting, that can be changed under Options → General → Browser), it shows a shared history stack across multiple views (Disassembly, Pseudocode, Local Types, and Stack). Otherwise, it displays the navigation history for the currently active widget only. The bolded entry indicates the current cursor position.

Navigation history view

Enable/disable history sharing

History sharing is enabled by default. You can enable or disable this behavior in Options → General → Browser.

Undo history window

This view shows the history of all undo actions.

Double clicking on a line reverts the database to the state before the corresponding action.

Undo history view

Truncate history

It is possible to truncate the undo history by using the corresponding context menu command Truncate history. The undo information for the selected action will be removed together with the information about all preceding actions.

Style indicators

The redoable user actions are displayed in italics. The current position in the undo buffers is displayed in bold; it usually denotes the first redoable user action.

Microcode window

The Microcode view displays the decompiler’s microcode - an intermediate form that bridges CPU-specific assembly and high-level pseudocode. It shows micro instructions organized into blocks, along with control flow transfers and use-definition chains that track how data flows through the code. You can explore microcode at different maturity levels. Microcode view

Key features and interaction

  • Maturity level: Increase or decrease maturity level using > and < keys or via the context menu.
  • Synchronized Views: You can sync currently opened Microcode window with Disassembly, Pseudocode, or other Microcode views via the context menu.

How To Use List Viewers in IDA

The following commands work in the list viewers:

1. All usual movement keys: PgUp, PgDn, Home, End and arrows ( ).

2. It is possible to position to a line simply by typing in the desired line number.

3. It is possible to position on a line by typing in its beginning. In this case the user can use: Backspace key to erase the last character typed in. Ctrl+Enter to find another line with the same prefix. Please note that List Viewer ignores the prefix of a line up to the last backslash (\\) or slash (/) if it exists.

4. Alt+T search for a substring (case-insensitive). Ctrl+T repeat last search.

5. If the list is not in dialog mode, you can use the following keys:

  • Enter: jump to the selected item in the last IDA View window
  • Ctrl+E: edit the current item
  • Del delete the current item
  • Ins insert a new item
  • Ctrl+U refresh information in the window

6. Quick filtering is available using Ctrl+F. More complex filters can be defined with a right click (only the GUI mode).

7. The list can be sorted by any column by clicking on it. Please note that maintaining a frequently modified list sorted can be very time consuming, so try not to sort non-modal lists during the initial analysis. (sorting is available only in the GUI mode).

8. Right-click may show additional functionality for the list viewer.

Esc or Enter close modal list viewers.

Concepts

Segment Address Space and Creation

Here we explains IDA address space model and how to create segments with proper address translation. It covers the relationship between linear addresses, virtual addresses, and segment bases, with practical examples for different processor architectures.

Address space model

Internally, IDA has 32-bit linear address space (IDA64 uses 64-bit address space). The internal addresses are called “linear addresses”. The input program is loaded into this linear address space.

Please note that usually the linear addresses are not used in the program directly. During disassembling, we use so-called “virtual addresses”, which are calculated by the following formula:

        VirtualAddress = LinearAddress - (SegmentBase << 4);

We see that the SegmentBase determines what addresses will be displayed on the screen. More than that, IDA allows to create several segments with the same virtual address in them. For this, you just need to create segments with correct segment base values.

Normally a SegmentBase is a 16bit quantity. To create a segment with base >= 0x10000, you need to use selectors window . However, if you try to create a segment with a segment base >= 0x10000, IDA will automatically choose appropriately a free selector and setup for the new segment.

All SegmentBases are looked up in the selector table.

There are some address restrictions in IDA.

There is a range of addresses that are used for internal housekeeping. This range can be specified by the configuration variable PRIVRANGE (start address and size). It is not recommended to use these addresses for other purposes.

There is also one address which must never be used in the disassembly. It is the ‘all ones’ address, or -1. Internally, it is used as a BADADDR (bad address). No address or address range can include BADADDR.

Segment Creation Examples

Create segment - simple case (PC)

IBM PC case

Suppose we need to create a segment occupying addresses F000:1000..F000:2000 Let’s calculate linear addresses:

        start = (0xF000 << 4) + 0x1000 = 0xF1000
        end   = (0xF000 << 4) + 0x2000 = 0xF2000

The segment base must be selected so that the first offset in our segment will be 0x1000. Let’s find it using the following equation:

        VirtualAddress = LinearAddress - (SegmentBase << 4);
        0x1000         = 0xF1000 - (base << 4);

After solving this equation, we see that the segment base is equal to 0xF000. (you see, this is really a very simple case :) )

Now, we can create a segment entering:

        segment start address:  0xF1000
        segment end address:    0xF2000
        segment base:           0xF000

Please note that the end address never belongs to the segment in IDA.

Create segment - simple case (Z80)

Suppose we need to create a segment occupying virtual addresses 8000-C000. Since we are free to place our segment anywhere in the linear address space, we choose the linear addresses at our convenience. Let’s say we choose a linear address 0x20000:

        start = 0x20000
        end   = start + 0x4000 = 0x24000

The segment base must be selected so that the virtual address in our segment will be 0x8000. Let’s find it using the following equation:

        VirtualAddress = LinearAddress - (SegmentBase << 4);
        0x8000         = 0x20000 - (base << 4);
        base << 4      = 0x20000 - 0x8000
        base << 4      = 0x18000
        base           = 0x1800

After solving this equation, we see that the segment base is equal to 0x1800.

Now we can create a segment entering:

        segment start address:  0x20000
        segment end address:    0x24000
        segment base:           0x1800

Please note that the end address never belongs to the segment in IDA.

Create segment - automatically chosen selector case

Suppose we need to create a segment occupying linear addresses 200000-200C00 and the virtual addresses must have be 0000..0C00. If we simply enter

        segment start address:  0x200000
        segment end address:    0x200C00
        segment base:           0x20000

Then IDA will notice that the segment base is too big and does not fit into 16bits. Because of this IDA will find a free selector (let’s say it has found selector number 5), define it to point at paragraph 0x20000 and create a segment. After all this we will have:

        - a new selector is defined (5 -> 0x20000)
        - a new segment is created. Its attributes:
                start = 0x200000
                end   = 0x200C00
                base  = 5

The first virtual address in the segment will be 0:

        VirtualAddress = LinearAddress - (SelectorValue(SegmentBase) << 4)
                       = 0x200000      - (SelectorValue(5) << 4)
                       = 0x200000      - (0x20000 << 4)
                       = 0x200000      - 0x200000
                       = 0

Please note that the end address never belongs to the segment in IDA.

Create segment - user-defined selector case

If the previous example we saw how IDA allocates a selector automatically. You could make it yourself:

  1. Create a selector. For this, open the selectors window and press Ins. Enter a selector number and its value.
  2. Create a segment. Specify the selector number as the segment base.

Change segment translation

A call like:

        call    1000

in the segment C obviously refers to the segment B, while the instruction:

        call    500

refers to the segment A.

However, IDA does not try to link these references unless you tell it to do so: include the segments A and B into a translation list of the segment C. It means that you have to create a translation list

        A B

for the segment C.

Below is a more complicated example:

                start   end
        A       0000    1000
        B       1000    2000
        C       1000    2000
        D       3000    4000
        E       3000    4000

translations

        B:      A
        C:      A
        D:      A B
        E:      A C

allow you to emulate overlays (the first set is A B D, the second A C E)

{% hint style=“info” %} If you use the segment translations, make sure that all segments have unique segment bases. If two segments are placed in the linear address space so that they must have the same segment base, you may assign different selectors with equal values to them. {% endhint %}

{% hint style=“info” %} IDA supports only one translation list per segment. This translation is applied by default to all instruction in the segment. If the segment uses other mappings, then these individual mappings can be specified for each instruction separately by using the convert operand commands. {% endhint %}

{% hint style=“info” %} Since only code references are affected by the segment translations, try to create the RAM segment at its usual place (i.e., its linear address in IDA corresponds to its address in the processor memory). This will make all data references to it to be correct without any segment translation. For the data references to other segments you’ll need to use the convert operand commands for each such reference. {% endhint %}

Binary string format

It is possible to enter a sequence of the following items:

  • a number in the selected radix (hexadecimal, decimal or octal)
  • a string constant: "string"
  • a Unicode string constant: L"unicode string"
  • a question mark ? to ignore variable bytes

The sequence must be separated by a space or a comma.

An entered number will occupy the minimal number of bytes it fits in with the restriction that the number of bytes is a power of 2 (1, 2, or 4 bytes).

Two question marks without a space between them are the same as one question mark. One question mark corresponds to one CPU byte. One CPU byte may consist of multiple octets for a wide-byte CPU, like TMS320C28.

Example:

CD 21          - bytes 0xCD, 0x21
21CD           - bytes 0xCD, 0x21 (the order depends on the endiannes)
"Hello", 0     - the null terminated string "Hello"
L"Hello"       - 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0
B8 ? ? ? ? 90  - byte 0xB8, 4 bytes with any value, byte 0x90

Breakpoints

IDA’s debugger supports various types of breakpoints to control program execution. This guide covers page breakpoints (memory access breakpoints) and how to use conditions to control breakpoint behavior.

Page breakpoints

Page breakpoints are memory access breakpoints that can be set to detect when the application reads, writes, or executes code/data in a specific memory range. Page breakpoints are very similar to hardware breakpoints but there is no limitation on the number of page breakpoints that can be set or their size, in contrast with normal hardware breakpoints.

Memory access breakpoints are implemented by removing page permissions according to the specified type of the page breakpoint to be added (for example, for a write page breakpoint, the write permission will be removed from the page). When the access violation exception occurs because the application tries to access the specific memory region, IDA reports a breakpoint hit.

As page breakpoints can be set for a small part of a memory page but the permissions of the whole page must be changed, page breakpoints can slow down the debugger because many access violation exceptions may be generated. If the application accesses memory outside of the desired range but on the same page, the generated exception must be silently handled and the application resumed. Specifically, page breakpoints in the code segment can slow down the debugger very much.

Memory access breakpoints are supported since IDA version 6.3 for the following debuggers:

  • Win32: Page breakpoints are supported for both local and remote debugging of 32 and 64bit applications.

  • WinDbg: Page breakpoints are supported only for local debugging of 32-bit applications.

  • Bochs: Page breakpoints are supported for both of 32 and 64bit applications. Page breakpoints in the bochs debugger are just like normal hardware breakpoints but with no limit on the number of breakpoints or their size. Please note that hardware breakpoints in the bochs debugger occur AFTER the instruction is executed while regular page breakpoints occur BEFORE the instruction is actually executed.

Regular Expression Syntax Summary

The full syntax and semantics of the regular expressions that are supported by PCRE2 are described in the pcre2pattern documentation. This document contains a quick-reference summary of the syntax.

QUOTING

  \x         where x is non-alphanumeric is a literal x
  \Q...\E    treat enclosed characters as literal

ESCAPED CHARACTERS

This table applies to ASCII and Unicode environments.

  \a         alarm, that is, the BEL character (hex 07)
  \cx        "control-x", where x is any ASCII printing character
  \e         escape (hex 1B)
  \f         form feed (hex 0C)
  \n         newline (hex 0A)
  \r         carriage return (hex 0D)
  \t         tab (hex 09)
  \0dd       character with octal code 0dd
  \ddd       character with octal code ddd, or backreference
  \o{ddd..}  character with octal code ddd..
  \U         "U" if PCRE2_ALT_BSUX is set (otherwise is an error)
  \uhhhh     character with hex code hhhh (if PCRE2_ALT_BSUX is set)
  \xhh       character with hex code hh
  \x{hhh..}  character with hex code hhh..

Note that \0dd is always an octal code. The treatment of backslash followed by a non-zero digit is complicated; for details see the section "Non-printing characters" in the pcre2pattern documentation, where details of escape processing in EBCDIC environments are also given.

When \x is not followed by {, from zero to two hexadecimal digits are read, but if PCRE2_ALT_BSUX is set, \x must be followed by two hexadecimal digits to be recognized as a hexadecimal escape; otherwise it matches a literal "x". Likewise, if \u (in ALT_BSUX mode) is not followed by four hexadecimal digits, it matches a literal "u".

CHARACTER TYPES

  .          any character except newline;
               in dotall mode, any character whatsoever
  \C         one code unit, even in UTF mode (best avoided)
  \d         a decimal digit
  \D         a character that is not a decimal digit
  \h         a horizontal white space character
  \H         a character that is not a horizontal white space character
  \N         a character that is not a newline
  \p{xx}     a character with the xx property
  \P{xx}     a character without the xx property
  \R         a newline sequence
  \s         a white space character
  \S         a character that is not a white space character
  \v         a vertical white space character
  \V         a character that is not a vertical white space character
  \w         a "word" character
  \W         a "non-word" character
  \X         a Unicode extended grapheme cluster

\C is dangerous because it may leave the current matching point in the middle of a UTF-8 or UTF-16 character. The application can lock out the use of \C by setting the PCRE2_NEVER_BACKSLASH_C option. It is also possible to build PCRE2 with the use of \C permanently disabled.

By default, \d, \s, and \w match only ASCII characters, even in UTF-8 mode or in the 16-bit and 32-bit libraries. However, if locale-specific matching is happening, \s and \w may also match characters with code points in the range 128-255. If the PCRE2_UCP option is set, the behaviour of these escape sequences is changed to use Unicode properties and they match many more characters.

GENERAL CATEGORY PROPERTIES FOR \p and \P

  C          Other
  Cc         Control
  Cf         Format
  Cn         Unassigned
  Co         Private use
  Cs         Surrogate

  L          Letter
  Ll         Lower case letter
  Lm         Modifier letter
  Lo         Other letter
  Lt         Title case letter
  Lu         Upper case letter
  L&         Ll, Lu, or Lt

  M          Mark
  Mc         Spacing mark
  Me         Enclosing mark
  Mn         Non-spacing mark

  N          Number
  Nd         Decimal number
  Nl         Letter number
  No         Other number

  P          Punctuation
  Pc         Connector punctuation
  Pd         Dash punctuation
  Pe         Close punctuation
  Pf         Final punctuation
  Pi         Initial punctuation
  Po         Other punctuation
  Ps         Open punctuation

  S          Symbol
  Sc         Currency symbol
  Sk         Modifier symbol
  Sm         Mathematical symbol
  So         Other symbol

  Z          Separator
  Zl         Line separator
  Zp         Paragraph separator
  Zs         Space separator

PCRE2 SPECIAL CATEGORY PROPERTIES FOR \p and \P

  Xan        Alphanumeric: union of properties L and N
  Xps        POSIX space: property Z or tab, NL, VT, FF, CR
  Xsp        Perl space: property Z or tab, NL, VT, FF, CR
  Xuc        Univerally-named character: one that can be
               represented by a Universal Character Name
  Xwd        Perl word: property Xan or underscore

Perl and POSIX space are now the same. Perl added VT to its space character set at release 5.18.

SCRIPT NAMES FOR \p AND \P

Ahom, Anatolian_Hieroglyphs, Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak, Bengali, Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Carian, Caucasian_Albanian, Chakma, Cham, Cherokee, Common, Coptic, Cuneiform, Cypriot, Cyrillic, Deseret, Devanagari, Duployan, Egyptian_Hieroglyphs, Elbasan, Ethiopic, Georgian, Glagolitic, Gothic, Grantha, Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hatran, Hebrew, Hiragana, Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscriptional_Parthian, Javanese, Kaithi, Kannada, Katakana, Kayah_Li, Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha, Limbu, Linear_A, Linear_B, Lisu, Lycian, Lydian, Mahajani, Malayalam, Mandaic, Manichaean, Meetei_Mayek, Mende_Kikakui, Meroitic_Cursive, Meroitic_Hieroglyphs, Miao, Modi, Mongolian, Mro, Multani, Myanmar, Nabataean, New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Hungarian, Old_Italic, Old_North_Arabian, Old_Permic, Old_Persian, Old_South_Arabian, Old_Turkic, Oriya, Osmanya, Pahawh_Hmong, Palmyrene, Pau_Cin_Hau, Phags_Pa, Phoenician, Psalter_Pahlavi, Rejang, Runic, Samaritan, Saurashtra, Sharada, Shavian, Siddham, SignWriting, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac, Tagalog, Tagbanwa, Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu, Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic, Vai, Warang_Citi, Yi.

CHARACTER CLASSES

  [...]       positive character class
  [^...]      negative character class
  [x-y]       range (can be used for hex characters)
  [[:xxx:]]   positive POSIX named set
  [[:^xxx:]]  negative POSIX named set

  alnum       alphanumeric
  alpha       alphabetic
  ascii       0-127
  blank       space or tab
  cntrl       control character
  digit       decimal digit
  graph       printing, excluding space
  lower       lower case letter
  print       printing, including space
  punct       printing, excluding alphanumeric
  space       white space
  upper       upper case letter
  word        same as \w
  xdigit      hexadecimal digit

In PCRE2, POSIX character set names recognize only ASCII characters by default, but some of them use Unicode properties if PCRE2_UCP is set. You can use \Q...\E inside a character class.

QUANTIFIERS

  ?           0 or 1, greedy
  ?+          0 or 1, possessive
  ??          0 or 1, lazy
  *           0 or more, greedy
  *+          0 or more, possessive
  *?          0 or more, lazy
  +           1 or more, greedy
  ++          1 or more, possessive
  +?          1 or more, lazy
  {n}         exactly n
  {n,m}       at least n, no more than m, greedy
  {n,m}+      at least n, no more than m, possessive
  {n,m}?      at least n, no more than m, lazy
  {n,}        n or more, greedy
  {n,}+       n or more, possessive
  {n,}?       n or more, lazy

ANCHORS AND SIMPLE ASSERTIONS

  \b          word boundary
  \B          not a word boundary
  ^           start of subject
                also after an internal newline in multiline mode
                (after any newline if PCRE2_ALT_CIRCUMFLEX is set)
  \A          start of subject
  $           end of subject
                also before newline at end of subject
                also before internal newline in multiline mode
  \Z          end of subject
                also before newline at end of subject
  \z          end of subject
  \G          first matching position in subject

MATCH POINT RESET

  \K          reset start of match

\K is honoured in positive assertions, but ignored in negative ones.

ALTERNATION

  expr|expr|expr...

CAPTURING

  (...)           capturing group
  (?<name>...)    named capturing group (Perl)
  (?'name'...)    named capturing group (Perl)
  (?P<name>...)   named capturing group (Python)
  (?:...)         non-capturing group
  (?|...)         non-capturing group; reset group numbers for
                   capturing groups in each alternative

ATOMIC GROUPS

  (?>...)         atomic, non-capturing group

COMMENT

  (?#....)        comment (not nestable)

OPTION SETTING

  (?i)            caseless
  (?J)            allow duplicate names
  (?m)            multiline
  (?s)            single line (dotall)
  (?U)            default ungreedy (lazy)
  (?x)            extended (ignore white space)
  (?-...)         unset option(s)

The following are recognized only at the very start of a pattern or after one of the newline or \R options with similar syntax. More than one of them may appear. (*LIMIT_MATCH=d) set the match limit to d (decimal number)

  (*LIMIT_RECURSION=d) set the recursion limit to d (decimal number)
  (*NOTEMPTY)     set PCRE2_NOTEMPTY when matching
  (*NOTEMPTY_ATSTART) set PCRE2_NOTEMPTY_ATSTART when matching
  (*NO_AUTO_POSSESS) no auto-possessification (PCRE2_NO_AUTO_POSSESS)
  (*NO_DOTSTAR_ANCHOR) no .* anchoring (PCRE2_NO_DOTSTAR_ANCHOR)
  (*NO_JIT)       disable JIT optimization
  (*NO_START_OPT) no start-match optimization (PCRE2_NO_START_OPTIMIZE)
  (*UTF)          set appropriate UTF mode for the library in use
  (*UCP)          set PCRE2_UCP (use Unicode properties for \d etc)

Note that LIMIT_MATCH and LIMIT_RECURSION can only reduce the value of the limits set by the caller of pcre2_match(), not increase them. The application can lock out the use of (*UTF) and (*UCP) by setting the PCRE2_NEVER_UTF or PCRE2_NEVER_UCP options, respectively, at compile time.

NEWLINE CONVENTION

These are recognized only at the very start of the pattern or after option settings with a similar syntax.

  (*CR)           carriage return only
  (*LF)           linefeed only
  (*CRLF)         carriage return followed by linefeed
  (*ANYCRLF)      all three of the above
  (*ANY)          any Unicode newline sequence

WHAT \R MATCHES

These are recognized only at the very start of the pattern or after option setting with a similar syntax.

  (*BSR_ANYCRLF)  CR, LF, or CRLF
  (*BSR_UNICODE)  any Unicode newline sequence

LOOKAHEAD AND LOOKBEHIND ASSERTIONS

  (?=...)         positive look ahead
  (?!...)         negative look ahead
  (?<=...)        positive look behind
  (?<!...)        negative look behind

Each top-level branch of a look behind must be of a fixed length.

BACKREFERENCES

  \n              reference by number (can be ambiguous)
  \gn             reference by number
  \g{n}           reference by number
  \g{-n}          relative reference by number
  \k<name>        reference by name (Perl)
  \k'name'        reference by name (Perl)
  \g{name}        reference by name (Perl)
  \k{name}        reference by name (.NET)
  (?P=name)       reference by name (Python)

SUBROUTINE REFERENCES (POSSIBLY RECURSIVE)

  (?R)            recurse whole pattern
  (?n)            call subpattern by absolute number
  (?+n)           call subpattern by relative number
  (?-n)           call subpattern by relative number
  (?&name)        call subpattern by name (Perl)
  (?P>name)       call subpattern by name (Python)
  \g<name>        call subpattern by name (Oniguruma)
  \g'name'        call subpattern by name (Oniguruma)
  \g<n>           call subpattern by absolute number (Oniguruma)
  \g'n'           call subpattern by absolute number (Oniguruma)
  \g<+n>          call subpattern by relative number (PCRE2 extension)
  \g'+n'          call subpattern by relative number (PCRE2 extension)
  \g<-n>          call subpattern by relative number (PCRE2 extension)
  \g'-n'          call subpattern by relative number (PCRE2 extension)

CONDITIONAL PATTERNS

  (?(condition)yes-pattern)
  (?(condition)yes-pattern|no-pattern)

  (?(n)               absolute reference condition
  (?(+n)              relative reference condition
  (?(-n)              relative reference condition
  (?(<name>)          named reference condition (Perl)
  (?('name')          named reference condition (Perl)
  (?(name)            named reference condition (PCRE2)
  (?(R)               overall recursion condition
  (?(Rn)              specific group recursion condition
  (?(R&name)          specific recursion condition
  (?(DEFINE)          define subpattern for reference
  (?(VERSION[>]=n.m)  test PCRE2 version
  (?(assert)          assertion condition

BACKTRACKING CONTROL

The following act immediately they are reached:

  (*ACCEPT)       force successful match
  (*FAIL)         force backtrack; synonym (*F)
  (*MARK:NAME)    set name to be passed back; synonym (*:NAME)

The following act only when a subsequent match failure causes a backtrack to reach them. They all force a match failure, but they differ in what happens afterwards. Those that advance the start-of-match point do so only if the pattern is not anchored. (*COMMIT) overall failure, no advance of starting point

  (*PRUNE)        advance to next starting character
  (*PRUNE:NAME)   equivalent to (*MARK:NAME)(*PRUNE)
  (*SKIP)         advance to current matching position
  (*SKIP:NAME)    advance to position corresponding to an earlier
                  (*MARK:NAME); if not found, the (*SKIP) is ignored
  (*THEN)         local failure, backtrack to next alternation
  (*THEN:NAME)    equivalent to (*MARK:NAME)(*THEN)

CALLOUTS

  (?C)            callout (assumed number 0)
  (?Cn)           callout with numerical data n
  (?C"text")      callout with string data

The allowed string delimiters are ` ' " ^ % # $ (which are the same for the start and the end), and the starting delimiter { matched with the ending delimiter }. To encode the ending delimiter within the string, double it.

Problems list

These problems appear in the Problems window (View → Open subviews → Problems). IDA automatically detects and lists potential issues during analysis, helping you identify areas that may need manual review or correction.

The following problems may occur:

Problem: Cannot find offset base

Description: The current item has an operand marked as an offset, but IDA cannot find the offset base in the database.

Possible reason(s): The database is probably corrupted. This may occur if the database was corrupted and repaired.

What to do: Mark the operand again as an offset. Use one of the following commands:

  • Offset (data segment) (action OpOffset)
  • Offset (current segment) (action OpOffsetCs)
  • Offset by (any segment)… (action OpAnyOffset)
  • Offset (user-defined)… (action OpUserOffset)

Problem: Cannot find name

Description: Two reasons can cause this problem:

  1. Reference to an illegal address is made in the program being disassembled;
  2. IDA couldn’t find a name for the address but it must exist.

What to do:

  1. If this problem is caused by a reference to an illegal address:
  • Try to enter the operand manually (The Manual… command; action ManualOperand), or
  • Make the illegal address legal by creating a new segment (Create segment… command; action CreateSegment)
  1. Otherwise, the database is corrupt.

Problem: Cannot find alternative string for an operand

Description: The current item has an operand marked as entered manually, but IDA cannot find the manually entered string in the database.

Possible reason(s): The database is corrupt.

What to do: Enter the operand manually again. Use the Manual… command (action ManualOperand).

Problem: Cannot find comment

Description: Should not happen. Please inform the author if you encounter this problem.

Problem: Cannot find references

Description: The current item is marked as referenced from other place(s) in the program, but IDA cannot find any reference to it.

Possible reason(s): The database is corrupt.

What to do: Database is corrupt, the best thing to do is to reload the database.

Problem: Indirect execution flow

Description: Actually, this is not a problem. IDA warns you that here it encountered an indirect jump and couldn’t follow the execution.

What to do: Nothing, this entry is just for your information

Problem: Cannot disassemble

Description: IDA cannot represent the specified bytes as an instruction.

Possible reason(s):

  1. The specified bytes do not form an instruction.
  2. The current processor type (Options → General… → Analysis) is incorrect.

What to do: If you are sure that the specified bytes contain an instruction, you can try to change processor type (Options → General… → Analysis) and mark these bytes as an instruction using the following command: Code (action MakeCode)

Problem: Already data or code

Description: IDA cannot convert this byte(s) to an instruction or data because it would overlap another instruction.

What to do: Make the following overlapping instruction or data ‘unexplored’ using the Undefine command (action MakeUnknown).

Problem: Execution flows beyond limits

Description: IDA encountered a jump or call instruction to an illegal address. Namely:

  • jump/call beyond program segments
  • near jump/call beyond the current segment

What to do:

  1. Enter the operand manually (The Manual… command; action ManualOperand), or
  2. Create a new segment making the illegal address legal (Create segment… command; action CreateSegment), or
  3. Change the current segment bounds using one of the following:
  • change segment attributes (Edit → Segments → Edit segment…)
  • move a segment (Edit → Segments → move current segment…)

Problem: Too many lines

Description: The current item (instruction or data) occupies more lines on the screen than it is allowed by the current configuration.

What to do:

  1. If the current item is an array or string literal, try to divide it, or
  2. Delete additional comment lines (added via Edit → Comments → Enter anterior/posterior lines…), or
  3. Disable cross-references display (Options → General… → Cross-references), or
  4. Increase the limit in IDA.CFG; the parameter name is MAX_ITEM_LINES.

Problem: Failed to trace the value of the stack pointer

Description: The value of the stack pointer at the end of the function is different from its value at the start of the function. IDA checks for the difference only if the function is ended by a “return” instruction. The most probable cause is that stack tracing has failed. This problem is displayed in the disassembly listing with the “sp-analysis failed” comment.

What to do:

  1. Examine the value of stack pointer (Edit → Functions → Change stack pointer…) at various locations of the function and try to find out why the stack tracing has failed. Usually, it fails because some called function changed the stack pointer (by purging the input parameters, for example)
  2. If you have found the offending function, change (Edit → Functions → Edit function…) its attributes (namely, number of bytes purged upon return).
  3. Another way is to specify manually how the stack pointer is modified. See the Edit → Functions → Change stack pointer… command.

Problem: Attention! Probably erroneous situation

Description: This is a generic problem message. IDA uses it when no more detailed information is available or the problem is processor-specific.

Problem: Decision to convert to instruction/data is made by IDA

Description: In fact, this is not exactly a problem: IDA collects all the locations where it has decided to convert undefined bytes to instructions or data even if they don’t have any references to them. We consider this decision as dangerous and therefore we provide you with a way to examine all such places.

What to do: Examine the result of conversion and modify the instructions or data if IDA has made a wrong conversion.

Problem: The decision made by IDA was wrong and rolled back

Description: This problem occurs when IDA has converted unexplored bytes to instruction(s) and later found that the decision was wrong. For example:

            mov     ax, bx
            db 0FFh, 0FFh

0FFh, 0FFh cannot be converted to an instruction, therefore the mov instruction cannot be here.

In this case, IDA automatically destroys the instruction(s) and enlists the address as problematic.

What to do: Examine the end result and modify it accordingly.

FLIRT collision: the function with the given name already exists

Description: It means that IDA recognized the function as coming from a standard library but there already was another function with the same name in the program.

What to do: Examine the function and rename it as you wish.

FLIRT match indecision: reference to function expected

Description: IDA matched code bytes against at least one signature entry, but failed finding expected cross-references at certain offsets in the code.

Consider the following .pat file contents:

            5589E583EC18A1........890424E8........C9C3...................... 00 0000 0015 :0000 _test ^000F _my_fun0
            5589E583EC18A1........890424E8........C9C3...................... 00 0000 0015 :0000 _smuk ^000F _my_fun1

Now, turn that .pat file into a signature (.sig) file, telling sigmake to include function references into signature (using the -r switch).Then, apply that .sig file to a binary that you are examining.

If IDA recognizes the 0x15-bytes long pattern in the binary, it will check that, at offset 0xF from the start of the match, a call to either “_my_fun0” or “_my_fun1” is performed. If either one of the two is found, then that code will be named “test”, or “smuk”, respectively. Otherwise, a SIGFNREF problem will be signalled.

What to do: Examine the code pointed to by the address at the given offset (i.e., 0xF) and try and determine whether that function could be “_my_fun0”, or “_my_fun1”. If so, name it accordingly and re-apply the signature.

An alternative is to generate the signature (.sig) file without the cross-references to functions (i.e., dropping the ‘-r’ switch). But beware of collisions: a pattern like the one above will inevitably create a collision, since the pattern bytes are similar for the two entries.

Various dialog help messages

Packed Files

Sometimes, executable files are shipped in a packed form. It means that to disassemble these files you need to unpack them.

IDA displays this message if the relocation table of the input MZ executable file is empty.

Bad Relocation Table

Relocation table has references beyond program limits.

Additional information at the end of file

The file being loaded is not completely loaded to memory by the operating system. This may be because:

  • the file is overlayed; IDA does not know this type of overlays
  • the file has debugging information attached to its end
  • the file has other type of information at the end

Anyway, IDA will not load the additional information.

Overlayed files

Some EXE files are built with overlays. This means that the whole file is not loaded into the memory at the start of the program, but only a part of it. Other parts are loaded by the program itself into the dynamic memory or over some subroutines of the program. This fact leads to many difficulties when you disassemble such a program.

Currently, IDA knows about overlays created by Borland and Microsoft C and Pascal compilers.

Error loading overlays

One of the following occurred:

        - overlay stub is not found
        - overlay relocation data is incorrect

i.e. the input file structure is bad.

Maximal number of segments is reached

When IDA tried to delete bytes outside of any segment, the maximal number of contiguous chunks is reached. This is NOT a fatal error.

Some bytes outside of any segment will be present => the output text will be incorrect because of these bytes. However, you can delete them in the output text using a text editor.

Cannot generate executable file

IDA produces executable files only for:

  • MS DOS .exe
  • MS DOS .com
  • MS DOS .drv
  • MS DOS .sys
  • general binary
  • Intel Hex Object Format
  • MOS Technology Hex Object Format

Furthermore, external loaders may or may not support the creation of user-defined input file formats.

Bad input file format

The input file does not conform to the following definitions:

Intel Hex Object Format ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ This is the default format. This format is line oriented and uses only printable ASCII characters except for the carriage return/line feed at the end of each line. Each line in the file assumes the following format:

 :NNAAAARRHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHCCTT

Where:

All fields marked ‘hex’ consist of two or four ASCII hexadecimal digits (0-9, A-F). A maximum of 24 data bytes will be represented on each line.

 :      = Record Start Character
 NN     = Byte Count (hex)
 AAAA   = Address of first byte (hex)
 RR     = Record Type (hex, 00 except for last record which is 01)
 HH     = Data Bytes (hex)
 CC     = Check Sum (hex)
 TT     = Line Terminator (carriage return, line feed)

The last line of the file will be a record conforming to the above format with a byte count of zero (‘:00000001FF’).

The checksum is defined as:

        sum      =  byte_count + address_hi + address_lo +
                        record_type + (sum of all data bytes)
        checksum =  ((-sum) & ffh)

MOS Technology Hex Object Format ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ This format is line oriented and uses only printable ASCII characters except for the carriage return/line feed at the end of each line. Each line in the file assumes the following format:

 ;NNAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHCCCCTT

Where:

All fields marked ‘hex’ consist of two or four ASCII hexadecimal digits (0-9, A-F). A maximum of 24 data bytes will be represented on each line.

 ;      = Record Start Character
 NN     = Byte Count (hex)
 AAAA   = Address of first byte (hex)
 HH     = Data Bytes (hex)
 CCCC   = Check Sum (hex)
 TT     = Line Terminator (carriage return, line feed)

The last line of the file will be a record with a byte count of zero (‘;00’).

The checksum is defined as:

        sum      =  byte_count + address_hi + address_lo +
                        (sum of all data bytes)
        checksum =  (sum & ffffh)

Choose mark number

This command allows you to mark a location so that afterwards you can jump to the marked location immediately. Select any line from the list. The selected line will be used for mark description. Afterwards, you will be able to jump to the marked location using <Alt-J> key.

You can use <Up>, <Down>, <PgUp>, <PgDn>, <Home>, <End> keys. If you select the first line of the list, nothing will be selected.

Press <Enter> to select line, <Esc> to cancel.

See also: How to jump to the marked location

Enter mark description

Mark description is any text line. The description is for your information only.

Choose marked location

This command allows you to jump to the previously marked location. Select any line. You will jump to the selected location.

You can use <Up>, <Down>, <PgUp>, <PgDn>, <Home>, <End> keys. If you select the first line of the list, nothing will be selected.

Press <Enter> to select line, <Esc> to cancel.

See also: How to mark a location

IDA View bookmarks

See: Choose marked location

Structs bookmarks

See: Choose marked location

Enums bookmarks

See: Choose marked location

Cannot rename a location

It might be because of one of the following reasons:

1. The name is ill-formed:

  • it is a reserved word

{% hint style=“info” %} IDA does not allow the use of register names as byte names. {% endhint %}

  • it contains bad characters. The list of allowed characters is specified in IDA.CFG
  • it starts with a reserved prefix. Some prefixes are used by IDA to generate names. See Names Representation dialog for the list of prefixes.
  1. The name is already used in the program. Try to use another name. In order to know where the name is used, you can try to jump to it using Jump to the Named Location

3. The address cannot have a name:

     - IDA refuses to rename tail bytes (i.e. the second, third...
       bytes of instruction/data).
     - the address does not belong to the program

Cannot find file segmentation

The database is empty or corrupt. Unfortunately, all information has been lost.

Please use a backup copy of the database if there is any.

If you have previously saved your database into a text file, you can load it. See the Dump database command for explanations.

Negative Offsets

A segment cannot have bytes with negative offset from the segment base. Example: if a segment base is 0x3000, this segment can have a start address above or equal to 0x30000, but it cannot have a start address 0x2FFFF.

Obsolete Database Format

Please use an old version of IDA. The current version of IDA does not support this database.

Database is not closed

The database was not closed after the last IDA session. Most probably this happened due to a power fault, unexpected reboot of the computer, or another abnormal session termination.

You may try to repair the database but the best solution would be to use the intact packed database or use a backup.

The repairing may fail to recover the database.

See also the Dump database command.

The Name List is Empty

is command allows you to select a name from the user defined names. It means that no such names are defined now, or that all user-defined names are hidden. To give a name to the location, use Rename or [Rename any]../edit/other/rename-any-address.md) commands.

Upgrading IDA database

If IDA finds out that your database has an old format, it will try to upgrade the database to a new format. The upgrade process is completely automatic, no user intervention is needed. However, after upgrading your database, you will not be able to work with it using old versions of IDA. That is why IDA asks your confirmation before upgrading the database.

This feature works only for databases starting from IDA version 2.05.

Unexpected Database Format

Database format is newer than expected. That is because you are using an old version of IDA. The only thing you can do is to get a new version of IDA.

Imported module is not found

IDA did not find the specified module in:

  • the current directory

  • the operating system directory (see switch -W and configuration file parameters WINDIR,OS2DIR)

    OR
          - the module cannot be accepted because:
          - the module name (recorded in the file) doesn't match
            the expected name
          - the module does not contains any exported names (all exported functions
            are exported by ordinal numbers)
    

Entries imported by ordinal entries will not be commented. If IDA finds a module, all entries that are imported by ordinal will be commented like this:

  KERNEL_91:
                retf            ; INITTASK
                                  ^^^^^^^^^
                                  comment

This comment will be propagated (repeated - see the Enter repeatable comment… command) to all locations which call this entry:

                call    far ptr KERNEL_91 ; INITTASK

IDA searches all files named “modulename.*” for the module. If you know that the imported module resides in another directory, copy it to your current directory. If the module file name is different from “modulename.*”, rename it. After the database is loaded, you can delete the copied module.

IDA also looks for file “modulename.ids” in the current directory in the IDS subdirectory of the directory where IDA.EXE resides in the PATHed directories

You can create such a file yourself. For an example, look at DOSCALLS.IDS in the IDS subdirectory.

Load file dialog

Below is the description of dialog box fields:

 Load address - the paragraph where the file will be loaded.
                Meaningful only for EXE and binary files. For new exe
                files, please use 'manual load' feature.
 Load offset  - relevant only for binary files.
                specifies offset of the first byte from the start of
                the first segment. For example, if load offset=0x2700 and
                load address=0x1000, the first byte of the file will
                be at 1000:2700.
 DLL directory - path where IDA will look up referenced DLL files.
                Note that if IDA finds .IDS file, it does not look for
                .DLL file.
 Create segments        - relevant for binary files.
                          If not checked, IDA does not create segments.
 Load resources         - If not checked, IDA does not load resources from
                          NE files.
 Rename DLL entries     - If not checked, IDA makes repeatable comments
                          for entries imported by ordinals. Otherwise,
                          IDA renames the entries to meaningful names.
 Manual load            - relevant only for NE,LE,LX,ELF files.
                          If checked, IDA will ask loading addresses
                          and selectors for each object of the file.
                          For experienced users only!
 Fill segment gaps      - relevant only for COFF & OMF files.
                          If checked, IDA will fill gaps between
                          segments, creating one big chunk.
                          This option facilitates loading of big
                          object files.
 Make imports section   - relevant only for PE files.
                          If checked, IDA will convert .idata section
                          definitions to "extrn" directives and truncate it.
                          Unfortunately, sometimes there are some additional
                          data in .idata section so you'll need to disable
                          this feature if some information is not loaded
                          into the database.
 Create FLAT group      - relevant only for IBM PC PE files.
                          If checked, IDA will automatically create FLAT
                          group and use its selector as the default value
                          for the segment registers.
 Code segment           - If checked, IDA creates a code but not a data
                          segment. Relevant for processors with different
                          code/data segment addressing schemes (for
                          example, Atmel AVR).
 Loading options        - relevant only ELF,JAVA files.
                          If checked, IDA will ask additional loader
                          options. For experienced users only!

PE .idata section has additional data

If “create imports section” in the file loading dialog is checked, IDA will convert .idata section definitions to “extrn” directives and truncate it so it will not contain empty lines.

Unfortunately, sometimes there is some additional data in .idata section so you’ll need to disable this feature if some information is not loaded into the database.

IDA tries to detect additional data in .idata section automatically.

If you disable conversion of .idata section to a segment with “extrn” directives, you will see

somename dd ?

instead of

        extrn   somename

directives.

Another impact is that the .idata segment will not be truncated in any way.

Moving the Segment Start

When you edit the segment boundaries, you can check the “move the adjacent segments” checkbox.

IDA will try to shrink/expand the previous segment in order to move the beginning of the selected segment. Of course, you cannot move the start of the segment ‘too far’:

  - the segment must have at least 1 byte
  - the start address of the segment must be less than the end of the segment
  - no segments can be killed during moving
  - the segment cannot have bytes with negative offsets

You cannot shrink a segment to zero bytes. A segment must have at least one byte.

This command is mostly used when IDA does not detect the boundary between segments correctly.

Sometimes, IDA creates 2 segments where only one segment must exist. In this case, you should not use this command. Use the following sequence instead:

  • [delete](see the Delete segment… command) one segment. Choose the one with the bad segment base value. Do not disable addresses occupied by the segment being deleted.
  • change boundaries of the other segment. Caution: moving the first segment of the program will delete all information about the bytes between the old start of the segment and the new start of the segment!

See also another command that changes segment bounds in the Edit → Segments submenu.

Deleting a Segment

Deleting a Segment

If you want to delete the segment, please mark ‘CONFIRM DELETION’ checkbox

Disable addresses checkbox

        CAUTION: ALL INFORMATION ABOUT THE SEGMENT WILL BE LOST!

If you disable the addresses occupied by the segment, all information about these addresses will be lost. You will not see them on the screen anymore.

Otherwise, the segment will be deleted, but its data will remain unchanged. You can create another segment(s) for these addresses using the Create segment… command.

Auto analysis is not completed

As long as auto analysis is not completed, the IDA database is not consistent:

  • not all cross-references are found
  • not all instructions are disassembled
  • not all data items are explored

See also:

  • auto analysis
  • Set up auto analysis via Options → General… → Analysis

Silent mode of IDA

In this mode, IDA will not display dialog boxes on the screen. Instead, it will assume the default answer and proceed. For example, if you press @<Quit>, IDA will promptly exit to OS without asking for any confirmation.

To return to normal mode you will need to execute an IDC function: batch(0); i.e. disable batch “silent” mode. To execute a script command, select File → Script command… menu item or press @<ExecuteLine> hotkey.

Rename a structure/member

IDA maintains separate namespaces for each structure. For example, you can define something like this:

 xxx    struc
 xxx    db ?
 xxx    struc

Beware, usually assemblers have one common namespace and do not allow the mentioned above example.

An empty name cannot be specified.

This command is available when you open a Local Types window.

If the cursor is on the structure name at the beginning of the structure definition, IDA proposes to rename the structure. Otherwise, IDA proposes to rename a structure field.

If a structure is being renamed, the option “Don’t include in the list” means that the structure will not be included in the list of the structures which appears when the user applies the structure definition (for example, when the user creates a variable of this structure type). We recommend to mark this checkbox when you have defined all variables of this structure type and want to reduce the number of choices in the list.

See also:

Delete a structure member

Please remember that deleting a member deletes also all information
about this member, including comments, member name etc.

See also Edit → Structs submenu.

Unpacked database is dangerous

First of all, you may lose all information because you will not have a backup copy of the database. IDA makes modifications to the unpacked database and if some unexpected condition occurs, the unpacked database is usually damaged. IDA is able to repair this database, but some information could be irreversibly lost, leading to disastrous consequences.

The only advantage of the unpacked database is that it is loaded very fast. the same way, exiting IDA is fast too.

If packing is disabled, the Abort command will not be available the next time the database is loaded.

We strongly discourage using unpacked databases.

To disable this prompt in the future, simply modify ASK_EXIT_UNPACKED parameter in IDATUI.CFG or IDAGUI.CFG file.

Please note that when the “File -> Save as” is used with an unpacked database, IDA will continue to use the unpacked database and not the newly created database (the saved as one). In this case, please close and re-open the newly created database to ensure that IDA will use it instead of the original database.

Database Is Empty

Although the database exists, it is empty. Please delete it and start over.

If you have previously saved your database into a text file, you can load it. See Dump database to IDC file… command for explanations. See also IDA usage help

Illegal Usage of the Switch

Not all switches can be used when you start IDA for the second or more time. Below are valid switches: -a disable auto analysis -d debug

See also IDA usage help

Cannot Find Input File

IDA has tried to find a file with the extensions mentioned in the IDA.CFG file, but could not find anything.

The default extension table looks like this:

 Extension    Processor

  "com" :       ""
  "exe" :       ""
  "dll" :       ""
  "drv" :       ""
  "sys" :       ""
  "bin" :       ""
  "ovl" :       ""
  "ovr" :       ""
  "ov?" :       ""
  "nlm" :       ""
  "lan" :       ""
  "dsk" :       ""
  "obj" :       ""
  "prc" :       "68000"
  "axf" :       "arm710a"
  "h68" :       "68000"
  "i51" :       "8051"
  "sav" :       "pdp11"
  "rom" :       "z80"
  "cla*":       "java"
  "s19":        "6811"
  "epoc":       "arm"
  "o":          ""

See also IDA usage help

Patched Bytes Are Skipped

Some bytes in program memory have no corresponding byte in the executable file. For example, uninitialized data is not kept in the file. OS/2 Warp and Window support compressed pages.

In this case, IDA cannot create a full difference file. It shows the skipped byte addresses along with their values in the message window.

Patched bytes have relocation information

List of Functions

You can use list viewer commands in this window. Here is the format of this window.

No Segment for the current byte

Some commands cannot be applied to the addresses without a segment.

Create a segment first. You can do this using the Create segment… command.

Empty Program

The input file doesn’t contain any instructions or data, i.e. there is nothing to disassemble.

Some file formats allow the situation when the file is not empty but it doesn’t contain anything to disassemble. For example, COFF/OMF/EXE formats could contain a file header which just declares that there are no executable sections in the file.

There could be type information, compiler options and other auxiliary information in the file. This is the reason why the file doesn’t look empty but IDA doesn’t find anything to disassemble.

Load additional binary file

Below is the description of dialog box fields:

 Load segment    - The paragraph where the file will be loaded.
 Load offset     - Specifies offset of the first byte from the start of
                   the first segment. For example, if load offset=0x2700
                   and load segment=0x1000, the first byte of the file will
                   be at 1000:2700, or in linear addressing, 0x12700.
 File offset     - Offset in the input file to load bytes from.
 Number of bytes - Number of bytes to load from the file.
                   0 means load as many as possible.
 Create segments        - If not checked, IDA does not create segments.
 Code segment           - If checked, IDA creates a code segment.
                          relevant for processors which have different
                          code/data segment addressing schemes (for
                          example, Atmel AVR).

Patching Relocation Bytes

If a byte has relocation information attached to it, then the value of this byte is changed when the file is loaded into the memory by the system loader or linker. Therefore, it doesn’t make much sense (and sometimes it is simply illegal) to modify the byte.

We recommend to return the original value of the byte(s).

You can see the relocation information attached to an item by using the Print internal flags command.

NotVaFile

Not a virtual array file

The most probable error is that you tried to use an incompatible version of IDA. Starting from IDA 2.0 beta2 the format of virtual files was changed.

VaTooHighVersion

Virtual Array: Too high VA version

The most probable error is that you tried to open database with old version of IDA. Please use newer version of IDA to open this database.

Cannot assign to Segment Register | Cannot create segment registers range

This error happens because of the database corruption. Try to finish your work as soon as possible and generate the text source file.

The best choice would be to restore from a backup because the database is corrupted.

Advanced Type Annotations

IDA extends standard C/C++ type declarations with specialized annotations that provide control over data interpretation and display in disassembly and decompiled code.

For a complete list of all type system keywords, see the Type System Keywords

Shifted Pointers

Sometimes in binary code we can encounter a pointer to the middle of a structure. Such pointers usually do not exist in the source code but an optimizing compiler may introduce them to make the code shorter or faster.

Such pointers can be described using shifted pointers. A shifted pointer is a regular pointer with additional information about the name of the parent structure and the offset from its beginning. For example:

        struct mystruct
        {
          char buf[16];
          int dummy;
          int value;            // <- myptr points here
          double fval;
        };
        int *__shifted(mystruct,20) myptr;

The above declaration means that myptr is a pointer to ‘int’ and if we decrement it by 20 bytes, we will end up at the beginning of ‘mystruct’.

Please note that IDA does not limit parents of shifted pointers to structures. A shifted pointer after the adjustment may point to any type except ‘void’.

Also, negative offsets are supported too. They mean that the pointer points to the memory before the structure.

When a shifted pointer is used with an adjustment, it will be displayed with the ‘ADJ’ helper function. For example, if we refer to the memory 4 bytes further, it can be represented like this:

        ADJ(myptr)->fval

Shifted pointers are an improvement compared to the CONTAINING_RECORD macro because expressions with them are shorter and easier to read.

Scattered Argument Locations

Modern compilers may pass structure arguments across multiple registers or mixed register/stack locations. Scattered argument locations describe these complex calling conventions.

  00000000 struc_1         struc ; (sizeof=0xC)
  00000000 c1              db ?
  00000001                 db ? ; undefined
  00000002 s2              dw ?
  00000004 c3              db ?
  00000005                 db ? ; undefined
  00000006                 db ? ; undefined
  00000007                 db ? ; undefined
  00000008 i4              dd ?
  0000000C struc_1         ends

If we have this function prototype:

  void myfunc(struc_1 s);

the 64bit GNU compiler will pass the structure like this:

  RDI: c1, s2, and c3
  RSI: i4

Since compilers can use such complex calling conventions, IDA needs some mechanism to describe them. Scattered argument locations are used for that. The above calling convention can be described like this:

  void __usercall myfunc(struc_1 s@<0:rdi.1, 2:rdi^2.2, 4:rdi^4.1, 8:rsi.4>);

It reads:

  • 1 byte at offset 0 of the argument is passed in byte 0 of RDI
  • 2 bytes at offset 2 of the argument are passed in bytes 1–2 of RDI
  • 1 byte at offset 4 of the argument is passed in byte 3 of RDI
  • 4 bytes at offset 8 of the argument are passed starting from byte 0 of RSI

In other words, the following syntax is used:

  argoff:register^regoff.size

where:

  • argoff — offset within the argument
  • register — register name used to pass part of the argument
  • regoff — offset within the register
  • size — number of bytes

The regoff and size fields can be omitted if there is no ambiguity.

If the register is not specified, the expression describes a stack location:

  argoff:^stkoff.size

where:

  • argoff - offset within the argument
  • stkoff - offset in the stack frame (the first stack argument is at offset 0)
  • size - number of bytes

Please note that while IDA checks the argument location specifiers for soundness, it cannot perform all checks and some wrong locations may be accepted. In particular, IDA in general does not know the register sizes and accepts any offsets within them and any sizes.

See also the Set type… (action SetType) command.

Data Representation Annotations

Data representation: enum member

Syntax:

  __enum(enum_name)

Instead of a plain number, a symbolic constant from the specified enum will be used. The enum can be a regular enum or a bitmask enum. For bitmask enums, a bitwise combination of symbolic constants will be printed. If the value to print cannot be represented using the specified enum, it will be displayed in red.

Example:

   enum myenum { A=0, B=1, C=3 };
   short var __enum(myenum);

If var is equal to 1, it will be represented as “B”

Another example:

   enum mybits __bitmask { INITED=1, STARTED=2, DONE=4 };
   short var __enum(mybits);

If var is equal to 3, it will be represented as “INITED|STARTED”

This annotation is useful if the enum size is not equal to the variable size. Otherwise using the enum type for the declaration is better:

   myenum var;  // is 4 bytes, not 2 as above

Data representation: offset expression

Syntax:

  __offset(type, base, tdelta, target)
  __offset(type, base, tdelta)
  __offset(type, base)
  __offset(type|AUTO, tdelta)
  __offset(type)
  __off

where type is one of:

TypeDescription
OFF88-bit full offset
OFF1616-bit full offset
OFF3232-bit full offset
OFF6464-bit full offset
LOW8low 8 bits of 16-bit offset
LOW16low 16 bits of 32-bit offset
HIGH8high 8 bits of 16-bit offset
HIGH16high 16 bits of 32-bit offset

The type can also be the name of a custom refinfo.

It can be combined with the following keywords:

KeywordDescription
RVAOFFbased reference (rva)
PASTENDreference past an item; it may point to an nonexistent address
NOBASEforbid the base xref creation; implies that the base can be any value
Note: base xrefs are created only if the offset base points to the middle of a segment
SUBTRACTthe reference value is subtracted from the base value instead of (as usual) being added to it
SIGNEDOPthe operand value is sign-extended (only supported for REF_OFF8/16/32/64)
NO_ZEROSan opval of 0 will be considered invalid
NO_ONESan opval of ~0 will be considered invalid
SELFREFthe self-based reference

The base, target delta, and the target can be omitted. If the base is BADADDR, it can be omitted by combining the type with AUTO:

  __offset(type|AUTO, tdelta)

Zero based offsets without any additional attributes and having the size that corresponds the current application target (e.g. REF_OFF32 for a 32-bit bit application), the shoft __off form can be used.

Examples:

  • A 64-bit offset based on the image base:
  int var __offset(OFF64|RVAOFF);
  • A 32-bit offset based on 0 that may point to an non-existing address:
  int var __offset(OFF32|PASTEND|AUTO);
  • A 32-bit offset based on 0x400000:
  int var __offset(OFF32, 0x400000);
  • A simple zero based offset that matches the current application bitness:
  int var __off;

This annotation is useful when the type of the pointed object is unknown, or the variable size is different from the usual pointer size. Otherwise, it is better to use a pointer:

  type *var;

Data representation: string

Syntax:

  __strlit(strtype, "encoding")
  __strlit(strtype, char1, char2, "encoding")
  __strlit(strtype)

where strtype is one of:

TypeDescription
CZero-terminated string, 8 bits per symbol
C_16Zero-terminated string, 16 bits per symbol
C_32Zero-terminated string, 32 bits per symbol
PASCALPascal string: 1-byte length prefix, 8 bits per symbol
PASCAL_16Pascal string: 1-byte length prefix, 16 bits per symbol
LEN2Wide Pascal string: 2-byte length prefix, 8 bits per symbol
LEN2_16Wide Pascal string: 2-byte length prefix, 16 bits per symbol
LEN4Delphi string: 4-byte length prefix, 8 bits per symbol
LEN4_16Delphi string: 4-byte length prefix, 16 bits per symbol

It may be followed by two optional string termination characters (only for C). Finally, the string encoding may be specified, as the encoding name or “no_conversion” if the string encoding was not explicitly specified.

Example:

  • A zero-terminated string in windows-1252 encoding:
  char array[10] __strlit(C,"windows-1252");
  • A zero-terminated string in utf-8 encoding:
  char array[10] __strlit(C,"UTF-8");

Data representation: structure offset

Syntax:

  __stroff(structname)
  __stroff(structname, delta)

Instead of a plain number, the name of a struct or union member will be used. If delta is present, it will be subtracted from the value before converting it into a struct/union member name.

Example: An integer variable named var that hold an offset from the beginning of the mystruct structure:

  int var __stroff(mystruct);

If mystruct is defined like this:

  struct mystruct
  {
    char a;
    char b;
    char c;
    char d;
  }

The value 2 will be represented as mystruct.c

Another example: A structure offset with a delta:

  int var __stroff(mystruct, 1);

The value 2 will be represented as mystruct.d-1

Data representation: custom data type and format

Syntax:

 __custom(dtid, fid)

where dtid is the name of a custom data type and fid is the name of a custom data format. The custom type and format must be registered by a plugin beforehand, at the database opening time. Otherwise, custom data type and format ids will be displayed instead of names.

Data representation: tabular form

Syntax:

  __tabform(flags)
  __tabform(flags,lineitems)
  __tabform(flags,lineitems,alignment)
  __tabform(,lineitems,alignment)
  __tabform(,,alignment)

This keyword is used to format arrays. The following flags are accepted:

FlagDescription
NODUPSdo not use the dup keyword
HEXuse hexadecimal numbers to show array indexes
OCTuse octal numbers to show array indexes
BINuse binary numbers to show array indexes
DECuse decimal numbers to show array indexes

It is possible to combine NODUPS with the index radix: NODUPS|HEX

The `lineitems` and `alignment` attributes have the meaning described for the Array… (action MakeArray) command.

Example:

Display the array in tabular form, 4 decimal numbers on a line, each number taking 8 positions. Display indexes as comments in hexadecimal:

  char array[16] __tabform(HEX,4,8) __dec;

A possible array may look like:

  dd   50462976, 117835012, 185207048, 252579084; 0
  dd  319951120, 387323156, 454695192, 522067228; 4
  dd  589439264, 656811300, 724183336, 791555372; 8
  dd  858927408, 926299444, 993671480,1061043516; 0Ch

Without this annotation, the `dup` keyword is permitted, number of items on a line and the alignment are not defined.

Type System Keywords and Attributes

Below is the full list of attributes that can be handled by IDA:

  • packed: pack structure/union fields tightly, without gaps
  • aligned: specify the alignment
  • noreturn: declare as not returning function
  • ms_struct: use microsoft layout for the structure/union
  • format: possible formats: printf, scanf, strftime, strfmon

For data declarations, the following custom __attribute((annotate(X))) keywords have been added. The control the representation of numbers in the output:

__bin unsigned binary number

__oct unsigned octal number

__hex unsigned hexadecimal number

__dec signed decimal number

__sbin signed binary number

__soct signed octal number

__shex signed hexadecimal number

__udec unsigned decimal number

__float floating point

__char character

__segm segment name

__enum() enumeration member (symbolic constant)

__off offset expression (a simpler version of __offset)

__offset() offset expression

__strlit() string __stroff() structure offset

__custom() custom data type and format

__invsign inverted sign

__invbits inverted bitwise

__lzero add leading zeroes

__tabform() tabular form

The following additional keywords can be used in type declarations:

_BOOL1 a boolean type with explicit size specification (1 byte)

_BOOL2 a boolean type with explicit size specification (2 bytes)

_BOOL4 a boolean type with explicit size specification (4 bytes)

__int8 a integer with explicit size specification (1 byte)

__int16 a integer with explicit size specification (2 bytes)

__int32 a integer with explicit size specification (4 bytes)

__int64 a integer with explicit size specification (8 bytes)

__int128 a integer with explicit size specification (16 bytes)

_BYTE an unknown type; the only known info is its size: 1 byte

_WORD an unknown type; the only known info is its size: 2 bytes

_DWORD an unknown type; the only known info is its size: 4 bytes

_QWORD an unknown type; the only known info is its size: 8 bytes

_OWORD an unknown type; the only known info is its size: 16 bytes

_TBYTE 10-byte floating point value

_UNKNOWN no info is available

__pure pure function: always returns the same value and does not modify memory in a visible way

__noreturn function does not return

__usercall user-defined calling convention; see above

__userpurge user-defined calling convention; see above

__golang golang calling convention

__swiftcall swift calling convention

__spoils explicit spoiled-reg specification; see above

__hidden hidden function argument; this argument was hidden in the source code (e.g. ‘this’ argument in c++ methods is hidden)

__return_ptr pointer to return value; implies hidden

__struct_ptr was initially a structure value

__array_ptr was initially an array

__unused unused function argument __cppobj a c++ style struct; the struct layout depends on this keyword

__ptr32 explicit pointer size specification (32 bits)

__ptr64 explicit pointer size specification (64 bits)

__shifted shifted pointer declaration

__high high level prototype (does not explicitly specify hidden arguments like ‘this’, for example) this keyword may not be specified by the user but IDA may use it to describe high level prototypes

__bitmask a bitmask enum, a collection of bit groups

__tuple a tuple, a special kind of struct. tuples behave like structs but have more relaxed comparison rules: the field names and alignments are ignored.

Environment variables

The following environment variables are used by IDA:

TMP or TEMP

Specifies the directory where the temporary files will be created.
Default: C:\TEMP

EDITOR

The name of the preferred text editor.

IDALOG

Specifies the name of the log file. Everything appearing in the message window will be dumped there.
Default: none

IDALOG_SILENT

Suppress all output to the message window. If the IDALOG variable is set, messages will continue to be written to the log file. Otherwise, they will be lost.

IDADIR

Specifies the IDA directory.
Default: the directory where IDA executable is located

IDA_LOADALL

The selected loader will load all segments without asking.

IDAUSR

Specifies the directory for user-specific settings.
Default:

  • Windows: %APPDATA%/Hex-Rays/IDA Pro
  • Linux: $HOME/.idapro
  • Mac OS X: $HOME/.idapro

This variable can contain multiple paths, in which case they must be separated by the platform’s path separator character (i.e., ; on Windows, and : on Linux & Mac OS X.)

  • Using %IDAUSR% for loading plugins:

    %IDAUSR% will be considered when scanning for plugins: for each directory component of %IDAUSR%, IDA will iterate on files in its “plugins” subdirectory, in alphabetical order.

    Plugins with the same case-insensitive file name (without extension) are considered to be duplicates and are ignored; only the first plugin with a given name will be considered. Thus, let’s say %IDAUSR% is set to C:\my_idausr, and a file C:\my_idausr\plugins\DWARF.py exists, then C:\my_idausr\plugins\DWARF.py will be picked up first while %IDADIR%\plugins\dwarf.dll will be considered conflicting, and thus ignored.

    In addition, in each directory, IDA first looks for plugins with the native extension (e.g., .dll on Windows) and only then looks for files with extensions corresponding to extension languages (e.g., .idc, .py, …). Consequently, if two files, say foo.dll and foo.py, are present in the same directory, foo.dll will be picked first, and foo.py will be considered conflicting, and thus ignored.

  • Using %IDAUSR% for overriding configuration:

    %IDAUSR% will be considered when looking for configuration files, after the config file found in %IDADIR%\cfg has been read.

    After %IDADIR%\cfg\<filename> has been read & applied, for each directory component of %IDAUSR%, IDA will look for cfg/<filename> in it, and, if found, read & apply its contents as well. This enables users to have their own small, fine-tuned configuration files containing just the bits they wanted to override, stored in one (or more) folder(s) of their choosing.

  • Using %IDAUSR% for specifying themes:

    %IDAUSR% will be considered when scanning for themes: for each directory component of %IDAUSR%, IDA will iterate on subdirectories in its “themes” subdirectory.

  • Using %IDAUSR% for providing additional loaders, processor modules, .til files, .sig and .ids files:

    %IDAUSR% will also be considered when building the list of existing loaders, processor modules, .til, .sig and .ids files.

    The following directories will be inspected:

    • %IDAUSR%\loaders
    • %IDAUSR%\procs
    • %IDAUSR%\til\<arch-name>
    • %IDAUSR%\sig\<arch-name>
    • %IDAUSR%\ids\<platform-name>

IDA_MINIDUMP

Platform: Windows only

If IDA crashes, it creates a minidump file with the MiniDumpWrite(). Use this environment variable to specify MiniDump flags (a combination of MINIDUMP_TYPE flags as a hexadecimal number). If set to NO, IDA will not write a dump.

IDA_MDMP_INIT

Platform: Windows only

Let IDA load dbghlp.dll on startup so it is used for crash dump file generation in case of a crash. If not set, IDA will load dbghlp.dll dynamically (if needed). Using this option may cause the Windbg debugger plugin to malfunction in case its dbghlp.dll does not match the one loaded by IDA.

IDA_NOEH

If set, disable IDA’s own exception handler and let all possible crashes to be handled by the OS or active debugger. It is useful if you’re debugging a crash in a plugin or processor module.

IDAIDS

Specifies the directory with the IDS files.
Default: %IDADIR%\IDS

IDASGN

Specifies the directory with the SIG files.
Default: %IDADIR%\SIG

IDATIL

Specifies the directory with the TIL files.
Default: %IDADIR%\TIL

IDAIDC

Specifies the directory with the IDC files.
Default: %IDADIR%\IDC

IDA_LIBC_PATH

Platform: Android remote host only

Specifies the exact path to the system libc.so

IDA_SKIP_SYMS

Platform: Linux host only

Turns off loading of exported symbols for the main executable file at the start of a debugging session.

IDA_NONAMES

Disables the name resolution.

IDA_NO_HISTORY

Disables updating file history.

IDA_NORELOC

Disables processing of the relocation information for some file formats.

IDA_NOEXP

Disables processing of the export information for some file formats.

IDA_NOTLS

Disables processing of the TLS entries for some file formats.

H8_NOSIZER

Disables the display of the operand sizes for H8 module.

IDA_LOADALL

Load all segments of the input file without further confirmations.

IDA_DEBUGBREAKPROCESS

Platform: Windows only

IDA debugger will use the DebugBreakProcess() API to break into the process. Otherwise it will instead attempt to set temporary breakpoints for all threads.

IDA_NO_REBASE

IDA Debugger will not rebase the program when debugging. (This will be in effect even if the debugger plugin implements the rebase_if_required_to callback).

IDABXPATHMAP

Variables related to the Bochs debugger.

IDABXENVMAP

See plugins/bochs/startup.* for more details.

IDA_NOWIN

Platform: Text MS Windows version only

Bypass the code trying to find out the foreground window. This code causes problems under WINE.

IDA_DONT_SWITCH_SCREENS

Platform: Text version only

Tells IDA to keep only one screen even during local debugging sessions. For local debugging sessions, IDA keeps by default one screen for the debugged application and one screen for itself.

IDA_NOAUTOCOMP

Do not autodetect compiler for name demangling. If this variable is absent and the current compiler is one of MS, Borland and Watcom, the compiler is autodetected.

IDA_ELF_PATCH_MODE

Overrides patch mode for the new ELF files. If this variable is defined, it must contain a number. Each bit of this number corresponds to an option from the following list:

IDA_ELF_PATCH_MODE

Overrides patch mode for the new ELF files. If this variable is defined, it must contain a number. Each bit of this number corresponds to an option from the following list:

BitDescription
0Replace PIC form of ‘Procedure Linkage Table’ to non PIC form
1Direct jumping from PLT (without GOT) regardless of its form
2Convert PIC form of loading ‘GLOBAL_OFFSET_TABLE[]’ of address
3Obliterate auxiliary bytes in PLT & GOT for ‘final autoanalysis’
4Natural form of PIC GOT address loading in relocatable file
5Unpatched form of PIC GOT references in relocatable file
6Mark ‘allocated’ objects as library-objects (MIPS only)

IDA_DYLD_SHARED_CACHE_SLIDE

Mach-O loader: specify the dyld shared cache image ASLR slide value (hexadecimal) or 'search' for automatic detection. If not set, slide is assumed to be 0 (unslid image).

Linux-Specific Variables

The following variables are used to fine-tune the Linux version of IDA:

TVLOG

Specifies the name of the log file. If not defined, use syslog with LOG_WARNING priority.

TERM

The terminal definition (see terminfo).

TVHEADLESS

Disable all output (for i/o redirection). If this variable is defined, the TVOPT variable is ignored. This environment variable also works in graphical versions of IDA. When set, the graphical interface will not restore desktops, toolbars or show the main window.

TVOPT

The end-user flags. It has many subfields, delimited by commas ','.

  • noX11 - when libX11.so is not compatible
  • noGPM - when libgpm.so is not compatible
  • ansi - OR mono - when the terminfo data of your display does not declare it as having the ANSI-color support
  • ign8 - ignore '8bit as meta key' in the terminfo description
  • xtrack - if your xterm-emulator in telnet client does not support mode 1002 (only 1000), set this flag
  • alt866 - do not encode pseudographic symbols (for the console with alt-font loaded)
  • cyrcvt= - Cyrillic conversion (oem/koi8r). Possible values are:
    • linux - for linux russian users and PuTTY (in/out koi8r)
    • kwin - output in koi8 and input in cp1251 - any telnet
    • windows - for many telnet and any linux users (in/out 1251)
Client nameTerminalTVOPTClient settings
SecureCRTxterm-scokeyxtrackEmulation->Terminal: xterm, Emulation->keyboard: either the built-in keyboard, either custom ‘xt-sco.key’ file Advanced->Terminaltype: xterm-scokey
SecureCRTxtermxtrackEmulation->Terminal: xterm+internal kbd
Puttyxterm-scokey-Terminal,Keyboard: Control?, Standard, SCO, Normal, Normal
Puttyxterm-Terminal,Keyboard: ControlH, Standard, ~num, Normal, Normal
Consolelinux-default
X11:xtermxterm-default

We recommend to use the ‘xterm-scokey’ terminal type for remote clients.

When the terminal type is xterm-scokey, add the following string to /etc/inputrc (or to ~/.inputrc):

"\e[.": delete-char

When working on the console without GPM installed, append noGPM to TVOPT.

Russian Language Support

Russian users should append the following settings to the above:

Append to TVOPTAppend to Client Settings
Consolealt866,cyrcvt=linux-
X11cyrcvt=linux-
Puttycyrcvt=linuxWindow,Translation: use font in both ANSI and OEM modes
SecureCRT
- with koi8font and kbd-hookcyrcvt=linux-
- with koi8fontcyrcvt=kwin-
- with ANSI-fontcyrcvt=windows-

The best settings for Russian users on the console are:

setfont alt-8x16.psf.gz -m koi2al
loadkey ru-ms.map
export TVOPT=cyrcvt=linux,alt866

C++ type details

IDA can parse and handle simple C++ class declarations. It cannot parse templates and other complex constructs but simple standard cases can be parsed.

If a C++ class contains virtual functions, IDA will try to rebuild the virtual function table (VFT) for the class. The VFT will be linked to the class by the name: if the class is called “A”, the VFT type will be “A_vtbl”.

Let us consider the following class hierarchy:

  class A { virtual int f(); int data; };
  class B : public A { virtual int g(); };

IDA will create the following structures:

  struct __cppobj A {A_vtbl *__vftable;int data;}
  struct A_vtbl {int (*f)(A *__hidden this);}
  struct __cppobj B : A {}
  struct B_vtbl {int (*f)(A *__hidden this);
                 int (*g)(B *__hidden this);}

Please note that the VFT pointer in the class A has a special name: “__vftable”. This name allows IDA to recognize the pointer as a VFT pointer and treat it accordingly.

Another example of more complex class hierarchy:

  class base1 { virtual int b1(); int data; };
  class base2 { virtual int b2(); int data; };
  class der2 : public base2 { virtual int b2(); int data; };
  class derived : public base1, public der2 { virtual int d(); };

Compiling in 32-bit Visual Studio mode yields the following layout:

  class derived size(20):
        +---
   0    | +--- (base class base1)
   0    | | {vfptr}
   4    | | data
        | +---
   8    | +--- (base class der2)
   8    | | +--- (base class base2)
   8    | | | {vfptr}
  12    | | | data
        | | +---
  16    | | data
        | +---
        +---

IDA will generate the following types:

  struct __cppobj base1 {base1_vtbl *__vftable /*VFT*/;int data;};
  struct /*VFT*/ base1_vtbl {int (*b1)(base1 *__hidden this);};
  struct __cppobj base2 {base2_vtbl *__vftable /*VFT*/;int data;};
  struct /*VFT*/ base2_vtbl {int (*b2)(base2 *__hidden this);};
  struct __cppobj der2 : base2 {int data;};
  struct /*VFT*/ der2_vtbl {int (*b2)(der2 *__hidden this);};
  struct __cppobj derived : base1, der2 {};
  struct /*VFT*/ derived_vtbl {int (*b1)(base1 *__hidden this);
                               int (*d)(derived *__hidden this);};

The ‘derived’ class will use 2 VFTs:

  offset 0: derived_vtbl
  offset 8: der2_vtbl

IDA and Decompiler can use both VFTs and produce nice code for virtual calls.

Please note that the VFT layout will be different in g++ mode and IDA can handle it too. Therefore it is important to have the target compiler set correctly.

It is possible to build the class hierarchy manually. Just abide by the following rules:

  • VFT pointer must have the “__vftable” name
  • VFT type must follow the “CLASSNAME_vtbl” pattern

C++ classes are marked with “__cppobj” keyword, it influences the class layout. However, this keyword is not required for VFT types.

In the case of a multiple inheritance it is possible to override a virtual table for a secondary base class by declaring a type with the following name: “CLASSNAME_XXXX_vtbl” where XXXX is the offset to the virtual table inside the derived (CLASSNAME) class.

Example: if in the above example we add one more function

        virtual int derived::b2();

then we need one more virtual table. Its name must be “derived_0008_vtbl”. Please note that our parser does not create such vtables, you have to do it manually.

Assembler level and C level types

In order to provide intuitive yet powerful interface to types IDA introduces two kinds of types:

  • Assembler level types
  • C level types

Assembler level types are the ones defined by the user using the Local Types view.

Since the user has to specify manually the member offset and other attributes, IDA considers the member offsets to be fixed for them and never shifts members of such types. If a member of struct becomes too big and does not fit the struct anymore, IDA will delete it.

The types defined in the Local types window are considered as C level types. For them IDA automatically calculates the member offsets and if necessary may shift members and change the total struct size.

The user may change the type level by simply editing the type from the appropriate window.

In the Local Types view:

  • C level types are displayed using regular colors.
  • Assembler level types are displayed in gray, as if they are disabled (but they are not).

Disassembler

Interactivity
Background Analysis
Graph View
Proximity View
Navigation
Disassembly Gallery
Supported processors
Supported file formats
Bitfields
Structures tutorial
Union tutorial
Variable length structures tutorial
Data types, operands and constructs
Packed executables

Interactivity

Main Idea

IDA is an interactive disassembler, which means that the user takes active participation in the disassembly process. IDA is not an automatic analyzer of programs. IDA will give you hints about suspicious instructions, unsolved problems etc. It is your job to inform IDA how to proceed.

If you are using IDA for the very first time, here are some commands that you will find very useful:

  • convert to instruction : the hotkey is C
  • convert to data : the hotkey is D

All the changes that you made are saved to disk. When you run IDA again, all the information on the file being disassembled is read from the disk, so that you can resume your work.

For other commands please refer to the menu system and the help.

Background Analysis

IDA can analyze a program when it is not occupied performing an action you prompted. You disassemble a program together with IDA, but your requests have priority.

The state of background analysis is shown on the upper right-hand corner of the screen.

You can disable autoanalysis, but in this case some functions of IDA will produce strange results (e.g. if you try to convert data into instructions, IDA will NOT trace all the threads of control flow and the data will be converted into instructions only on the screen…)

See also analysis options.

Graph view

In the graph view, the current function is represented as a collection of nodes linked together with edges. Nodes represent basic blocks and edges represent code cross-references between them.

Only code items are visible in the graph view, data items are hidden. To display them, switch to text mode by pressing Space. The graph view is available for the instructions belonging to functions. IDA automatically switches to text mode if the current item cannot be displayed in graph mode. It also displays a warning, which we recommend to hide away as soon as you become familiar with the concept.

The Space key can be used to toggle between the graph and text views.

Please select one of the following topic to learn more about graphs:

The current node

There are two concepts: the current node and the selected nodes. The node with the keyboard cursor is considered as the current node. If the user clicks on the graph background, the keyboard cursor will disappear and there will be no current node. In the absence of the current node, IDA uses the last valid address for the user commands (like rename and similar commands). For example, if the user invokes the ‘rename’ command by pressing N and if there is no current node, IDA will still display the ‘rename’ dialog box for the last valid address.

Clicking on the node title will make the clicked node the current one. The keyboard cursor will be moved to the clicked node. Any selection of the disassembly text will be cancelled upon switching the current node.

The default color for the title of the current node is dark gray.

In addition to the obvious method of clicking with the mouse left-button to select the current node, IDA supports many other methods:

 - Clicking with the mouse wheel selects the clicked node and centers
   the clicked point in the window
 - Keyboard arrows can be used to move from one node to another. When
   the keyboard cursor reaches the node border and the user presses
   the arrow once more, IDA finds a node in the specified direction
   and makes it the current.
 - The Ctrl-Up key displays the list of nodes referring to the current
   node and allows jumping to them. The Ctrl-Down key does the same
   with the referenced nodes.
 - Pressing '5' on the keypad positions the keyboard cursor at
   the window center
 - Left-click on an edge makes one of its ends (source or destination)
   the current node. The node farthest from the click point is selected
 - Ctrl-click on an edge jumps to its destination
 - Alt-click on an edge jumps to its source

Clicking with the mouse on the node text (disassembly listing) has the usual meaning: IDA will move the keyboard cursor to the clicked location. It is also possible to select the disassembly listing within one node.

Selections in graphs

Many graph operations are applied to the selected nodes. The current node is considered to be part of the node selection for all operations.

The graph nodes can be selected using the mouse. To select many nodes at once, press and hold the Ctrl key during the mouse operation. The Alt key removes nodes from the current selection.

Internally, IDA keeps track of the selected nodes and edge layout points. Edge layout points are the points where edges are bent. If the current selection is moved in the graph, the selected edge layout points are moved too.

The default color for the title of the selected nodes is light gray. Other node titles are displayed with white color.

See also proximity view.

Customizing graph layout

Each node has a title bar with title buttons. The title bar can be used to displace the node. Displacing nodes or edges creates a custom layout. The custom layouts are automatically saved in the database. If there is a custom layout for the function, IDA never destroys it without your explicit permission. This behavior has its drawbacks: when the nodes are resized (because of added comments, for example), the old layout will be retained and the nodes could overlap. In this case, the user can ask IDA to redo the layout or manually move the overlapping nodes. To avoid displacing nodes inadvertently, turn on the lock graph layout option.

The user can also click on the edge layout points (edge bending points) and drag them. If two edge layout points are too close, one of them will be deleted. To create new edge layout points, use Shift-DoubleClick on the edge.

Zooming graphs

The graph can be zoomed in and out. There are several ways of zooming the graph:

 - Use Ctrl-Wheel. The current mouse position will be the zoom center
   point (i.e. this point will not move during the zoom operation)
 - Use the predefined 'Zoom 100%' and 'Fit window' commands. They are
   available from the right-click menu or by their shortcuts: '1' and
   'W' respectively. The current mouse position is the zoom center
   point for the 'zoom 100%' command.
 - Use Ctrl-KeypadPlus or Ctrl-KeypadMinus keys. The current keyboard
   cursor is the zoom center for these commands.
 - Use Ctrl-Shift-drag. This lets you draw a rectangle to which IDA
   will zoom.

There are two options linked to the graph zooming:

 - Auto fit graph to window: will fit the current graph to the window
   size. Default: off
 - Fit window max zoom level 100%: the 'fit window' command does not
   use zoom levels higher than 100%. Default: on

The zoom level is never greater than 1000% and less than 1%. IDA remembers the current zoom level for each location in the navigation history.

See also proximity view.

Scrolling graphs

The user can pan (shift) the graph by clicking with the left mouse button on the graph background and dragging it. In the rare case when there is no graph background visible on the screen, the Shift-click can be used to move the graph. This can happen on very high zoom levels, when the current node occupies the whole window.

The mouse wheel scrolls the graph vertically. If the Alt key is pressed, it will scroll the graph horizontally.

The Page Up and Page Down keys scroll the graph vertically. The keyboard arrows can scroll the graph if they reach the node border and cannot jump to another node in the specified direction.

Scrolling the graph does not change the keyboard cursor position. As soon as the graph is refreshed on the screen, IDA will scroll the graph so that the keyboard cursor becomes visible.

See also proximity view.

Graph node groups

Any number of nodes can be collapsed into a single synthetic node. Such a synthetic node contains a user-provided text instead of normal disassembly listing. The ‘group’ command is available from the right-click menu if there are selected nodes.

Even a single node can be used to create a group. This feature can be used to collapse huge nodes into something manageable or to hide a group that consists of one node.

After creating a group, IDA automatically refreshes the graph layout. If a custom layout was present, it is not applied to the reduced graph. However, the existing custom layout is not destroyed and will be re-used as soon as the user switches to the full graph by deleting the group or uncollapsing it.

The node groups can be nested: synthetic nodes can be used to create other groups. This feature allows reducing the graph into a single node. Each node can belong to only one group at a time.

Groups can be uncollapsed to display the original node content. The node frames of the current uncollapsed group (the one with the mouse pointer) are displayed with a special color. The default group frame color is yellow. This way, the existing uncollapsed groups can be visualized by hovering the mouse over the graph nodes.

There are also commands to collapse and uncollapse all groups in the graph. They are available from the right click menu.

To edit the contents of synthetic nodes, use the ‘set node text’ button on the node title. The ‘rename’ command can be used too.

IDA automatically remembers the graph groups and their state for each function.

Graph overview window

IDA has a small graph overview window. It displays the whole graph in the zoom out form and gives the user an idea about which part of the graph is visualized on the main window.

Clicking on the graph overview window visualizes different parts of the graph in the main window. It is also possible to click and drag the focus frame - the main window will be refreshed accordingly.

The graph overview window is visible only in the graph view node. As soon as another non-modal window gets focus, the graph overview is closed. It automatically opens when a graph view is activated.

The graph overview is displayed by default. To hide it, right click on the main toolbar background and select Navigation, Graph overview menu item.

The graph overview window can be resized to accommodate really huge graphs.

Graph colors

Graph edges can have several colors. In graph view:

 - Blue: a normal edge
 - Green: if the jump is taken (its condition is satisfied)
 - Red: if the jump is not taken
 - Blinking: when in the debugger, the edge that will be followed blinks

And, in proximity view:

 - Blue: Code cross-reference edge
 - Gray: Data cross-reference edge

IDA highlights the current mouse items. If the mouse is hovered over an edge, it is highlighted. If the mouse is hovered over a node, all adjacent edges are highlighted. To turn off the highlighting, specify the ‘current edge’ color as an undefined custom color.

The ‘highlighted edge’ and ‘foreign node’ colors are not used yet.

See also proximity view.

Graph options

Use graph view by default

        IDA switches to graph mode for each 'jump' command.

Enable graph animation

        Animate the graph layout, movement, and group collapsing/uncollapsing.
        While animation takes time, it gives the user some idea what's going on.

Draw node shadows

        Display shadows for each graph node. Shadows are not displayed
        for really huge or ridiculously small nodes.

Auto fit graph into window

        Zoom the graph so that it occupies the whole window.

Fit window max zoom level 100%

        The 'fit window' command maximal zoom level is 100%.

Re-layout graph if nodes overlap

        IDA recomputes the graph layout if a node overlap is detected.
        The presence of a custom layout (if the user has displaced
        some graph nodes) effectively turns off this option.

Re-layout graph upon screen refresh

        IDA recomputes the graph layout at each screen refresh.
        Turning this option off accelerates IDA but then
        a manual layout might be required after some operations.

Truncate at the right margin

        All nodes at truncated at the right margin. The right margin
        is specified in the Options, General, Disassembly tab.
        This option narrows the graph but hides some information
        by truncating long lines.

Lock graph layout

        Locks the graph layout by ignoring attempts to displace
        nodes. This prevents the creation of custom layouts that might lead
        to ugly graph layouts when nodes change their sizes.

PROXIMITY VIEW

Show data references

        Show data cross-referenced items in proximity view.

Hide library functions

        Do not show data or code cross-references to library functions,
        only show cross-referenced local functions.

Unlimited children recursion

        Recurse until there are no more callees (children) of the currently
        selected central node and all of his children.

Recurse into library functions

        Displays children data or code cross-references from library
        functions.

Max parents recursion

        Maximum recursion level for displaying parents of the currently
        selected central node. The value '0' disables parents recursion.

Max children recursion

        Maximum recursion level for displaying children of the currently
        selected central node. The value '0' means no maximum recursion
        level.

Max nodes per level

        Maximum number of nodes to show per level of children and parents.

See also: right margin

Various graph hints

  1. The following actions can improve the speed of graph drawing:
 - Turn off animation
 - Turn off node shadows
 - Specify identical top and bottom background colors
 - Turn off 'relayout' options (might lead to stale graph contents)
 - Turn off the graph overview window
  1. Printing the graph: the ‘print’ command is available at the graph toolbar. The graph toolbar is visible by default but if you have saved a custom desktop configuration in the past, it will not be visible. To set it on, check the View, Toolbars, Graph view menu item.
  2. Working with huge graphs: do not forget about the node groups and use them to make the graph simpler.

Proximity view

Starting from IDA v6.2, the callgraph of a program can be displayed in a graph form.

In the proximity view, the current address, the callers and the callees are represented as a collection of nodes linked together with edges. Nodes represent functions and data references (global variables, strings, etc..) and edges represent code or data cross-references between them.

To open the proximity view press the ‘-’ key to zoom out and switch to the callgraph of the address under cursor.

Only the address names (function names or data labels) are displayed in the proximity view, but not the disassembly, nonetheless, hovering the mouse over a node will display brief disassembly listing in a resizable hint window. To see the complete disassembly listing switch to text or graph mode by pressing ‘+’ or Space respectively.

When disassembling new files, IDA will display a dialog offering to switch to proximity view when applicable. It is possible to turn off this dialog and not show it again.

In the proximity view there are 3 types of nodes: Function nodes, data nodes and auxiliar nodes. Function nodes are rectangular and they have a toolbar. Those nodes are used to display the callers or callees of the current central node (or any of his parents or children). Data nodes are rectangular nodes (without a toolbar) and they are used to display the data references (global variables, strings, etc…) to/from the current central node or any of his parents and children.

Please select one of the following topic to learn more about graphs:

Highlighting identifiers

In the graphical version, IDA highlights the identifier under the cursor. For example, if the cursor is on the “EAX” register, then all occurrences of “EAX” will be displayed with the yellow background. This feature is meant to make the program analysis easier by highlighting the interesting parts of the disassembly. For example, if the user wants to see all references to “EAX”, he just clicks on any “EAX” on the screen and all of them will be highlighted.

The selection is made by pressing the Up, Down, Left, Right keys or by simply clicking on the identifier.

The selection is not changed by pressing the PageUp, PageDown, Home, End keys, using the scrollbar, or pressing the Alt-Up, Alt-Down, Ctrl-Up, Ctrl-Down keys.

The Alt-Up and Alt-Down keys perform a search of the currently selected identifier backward or forward respectively.

The Ctrl-Up and Ctrl-Down keys scroll the disassembly text.

IDA does not highlight the segment names at the line prefix because it is not very useful.

It is possible to turn off the highlight. The appropriate checkbox is in the Options → General… → Browser tab.

Navigation

Anchor

Some IDA commands such as selecting a portion of file to output or specifying a segment to move need an anchor.

To drop the anchor, you can either use the Alt-L key or the Shift-<arrow> combination, which is more convenient. You can also drop the anchor with the mouse by simply clicking and dragging it.

After you’ve dropped the anchor, you can navigate freely using arrows, etc. Any command that uses the anchor, raises it.

The anchored range is displayed with another color.

When you exit from IDA, the anchor value is lost.

How to Enter a Segment Value

You must enter a segment base value as a hexadecimal number or a segment name. IDA will warn you if you enter an invalid segment.

You may enter a segment register name too.

How to Enter a Number

You can enter any ‘C’ expression with constants. Long arithmetic will be used for calculations.

In these expressions, you can use all the names that you have created in your program.

How to Enter an Identifier

An identifier is a name which starts with a letter and contains only letters and digits. The list of allowed characters is specified in config file IDA.CFG. All names are case-sensitive.

Maximal length of a name is specified in the configuration file too:

        MAX_NAME_LENGTH=120     // Maximal length of new names

Default is 120.

Some assemblers have a shorter name length limit, beware!

IDA will warn you if you enter an illegal name.

How to enter text

How to enter text

 In the text version of IDA, you can use the following keys:

 Enter          starts a new line
 Ctrl-Enter     finishes the input
 Esc            cancels the input
 F1             gives some help

                                        Shift-<arrow>  Select
 Ctrl-L         Search Again            Shift-Ins       Paste
 Ctrl-O         Indent Mode             Shift-Del       Cut
 Ctrl-T         Delete Word             Ctrl-Ins        Copy
 Ctrl-U         Undo                    Ctrl-Del        Clear
 Ctrl-Y         Delete Line             Ctrl-K B        Start Select
 Ctrl-Left      Word Left               Ctrl-K H        Hide Select
 Ctrl-Right     Word Right
 Ctrl-PgUp      Text Start              Ctrl-Q A        Replace
 Ctrl-PgDn      Text End                Ctrl-Q F        Search
                                        Ctrl-Q H        Delete Line Start
                                        Ctrl-Q Y        Delete Line End

Input containing only whitespaces is equal to an empty input.

Do not forget that you can also use the clipboard.

How to Enter an Address

You should enter an address as a hexadecimal number or a location name. When you enter the address in the hexadecimal format, you can omit the segment part of the address and the current segment will be used. Addresses beyond the program limits are invalid.

Also, you can enter a location name with a displacement:

        name+5

And finally you can specify a relative address:

        +10             0x10 bytes further
        -5              5 bytes backwards

If the entered string cannot be recognized as a hexadecimal number or location name, IDA will try to interpret it as an expression using the current script interpreter. The default interpreter is IDC.

Special addresses: $ - current location (depends on the current assembler) Examples:

456 current segment, offset 0x456

5E current segment, offset 0x5E

3000:34 segment 0x3000, offset 0x34

ds:67 segment pointed by ds, offset 0x67

0:4000000 linear address

0x4000000 start a location with name ‘start’

Disassembly Gallery

Philips 51XA-G3

seg000:02E4
seg000:02E4 ; =============== S U B R O U T I N E =======================================
seg000:02E4
seg000:02E4
seg000:02E4 sub_2E4:                                ; CODE XREF: seg000:0316↓p
seg000:02E4                                         ; seg000:0344↓p
seg000:02E4                 cmp.b   R1H, #0
seg000:02E7                 bge     loc_2F6
seg000:02E9                 movs.w  R4, #0
seg000:02EB                 sub.w   R4, R0
seg000:02ED                 mov.w   R0, R4
seg000:02EF                 movs.w  R4, #0
seg000:02F1                 subb.w  R4, R1
seg000:02F3                 mov.w   R1, R4
seg000:02F5                 nop
seg000:02F6
seg000:02F6 loc_2F6:                                ; CODE XREF: sub_2E4+3↑j
seg000:02F6                 cmp.b   R3H, #0
seg000:02F9                 bge     locret_308
seg000:02FB                 movs.w  R4, #0
seg000:02FD                 sub.w   R4, R2
seg000:02FF                 mov.w   R2, R4
seg000:0301                 movs.w  R4, #0
seg000:0303                 subb.w  R4, R3
seg000:0305                 mov.w   R3, R4
seg000:0307                 nop
seg000:0308
seg000:0308 locret_308:                             ; CODE XREF: sub_2E4+15↑j
seg000:0308                 ret
seg000:0308 ; End of function sub_2E4
seg000:0308
seg000:030A ; ---------------------------------------------------------------------------
seg000:030A                 push.w  R4
seg000:030C                 push.w  R5
seg000:030E                 push.w  R6

{% file src=“../../.gitbook/assets/shot_51xa.png” %} Disassembly image {% endfile %}

6502 and 65C02 Disassembler

IDA is the most powerful existing 6502 disassembler. Companies such as Commodore, Atari and Apple have used the 6502 and 65c02 design. If you are looking for additional information or even less powerful disassemblers, we recommend www.6502.org, a very useful 6502 resource center.

Assembler code

seg000:0065 ; ---------------------------------------------------------------------------
seg000:0065                 CMP     $3E8
seg000:0068                 CMP     $3E8,X
seg000:006B                 CMP     $3E8,Y
seg000:006E                 CMP     0,X
seg000:0071                 CMP     $FF,X
seg000:0073                 CPX     #0
seg000:0075                 CPX     #$FF
seg000:0077                 CPX     byte_64
seg000:0079                 CPX     $3E8
seg000:007C                 CPY     #0
seg000:007E                 CPY     #$FF
seg000:0080                 CPY     byte_64
seg000:0082                 CPY     $3E8
seg000:0085                 DEC     byte_64
seg000:0087                 DEC     $3E8
seg000:008A                 DEC     $3E8,X
seg000:008D                 DEC     0,X
seg000:0090                 DEC     $FF,X
seg000:0092                 DEX
seg000:0093                 DEY
seg000:0094                 EOR     #0
seg000:0096                 EOR     #$FF
seg000:0098                 EOR     ($64),Y
seg000:009A                 EOR     ($64,X)
seg000:009C                 EOR     byte_64
seg000:009E                 EOR     $3E8
seg000:00A1                 EOR     $3E8,X
seg000:00A4                 EOR     $3E8,Y
seg000:00A7                 EOR     0,X
seg000:00AA                 EOR     $FF,X
seg000:00AC                 INC     byte_64
seg000:00AE                 INC     $3E8
seg000:00B1                 INC     $3E8,X
seg000:00B4                 INC     0,X

{% file src=“../../.gitbook/assets/shot_6502.png” %} Disassembly image {% endfile %}

6301, 6303, 6800, 6801 and 6803 Disassembler

IDA is the most powerful disassembler available for the 6803 microcontroller family.

Assembler code

RAM:0098                 fcb   3
RAM:0099                 fcb $E8 ; è
RAM:009A                 fcb $C8 ; È
RAM:009B                 fcb   0
RAM:009C ; ---------------------------------------------------------------------------
RAM:009C                 eorb    #$FF
RAM:009E                 eorb    byte_64
RAM:00A1                 eorb    0,x
RAM:00A3                 eorb    $FF,x
RAM:00A5                 eorb    byte_3E8
RAM:00A8                 ldaa    #0
RAM:00AA                 ldaa    #$FF
RAM:00AC                 ldaa    byte_64
RAM:00AF                 ldaa    0,x
RAM:00B1                 ldaa    $FF,x
RAM:00B3                 ldaa    byte_3E8
RAM:00B6                 ldab    #0
RAM:00B8                 ldab    #$FF
RAM:00BA                 ldab    byte_64
RAM:00BD                 ldab    0,x
RAM:00BF                 ldab    $FF,x
RAM:00C1                 ldab    byte_3E8
RAM:00C4                 oraa    #0
RAM:00C6                 oraa    #$FF
RAM:00C8                 oraa    byte_64
RAM:00CB                 oraa    0,x
RAM:00CD                 oraa    $FF,x
RAM:00CF                 oraa    byte_3E8
RAM:00D2                 orab    #0
RAM:00D4                 orab    #$FF
RAM:00D6                 orab    byte_64
RAM:00D9                 orab    0,x
RAM:00DB                 orab    $FF,x
RAM:00DD                 orab    byte_3E8
RAM:00E0                 staa    byte_64

{% file src=“../../.gitbook/assets/shot_6803.png” %} Disassembler image {% endfile %}

68040, Amiga

Assembler code

CODE:00010390 ; ===========================================================================
CODE:00010390
CODE:00010390 ; Segment type: Pure code
CODE:00010390 ; segment "CODE"
CODE:00010390
CODE:00010390 ; =============== S U B R O U T I N E =======================================
CODE:00010390
CODE:00010390 ; Attributes: noreturn bp-based frame
CODE:00010390
CODE:00010390 _main:                                  ; CODE XREF: startup+CA↑p
CODE:00010390                                         ; startup:domain↑p
CODE:00010390
CODE:00010390 var_4           = -4
CODE:00010390
CODE:00010390                 link    a6,#-4
CODE:00010394                 jsr     _Init
CODE:0001039A                 jsr     _InitTrace
CODE:000103A0
CODE:000103A0 loc_103A0:                              ; CODE XREF: _main+182↓j
CODE:000103A0                                         ; _main+18C↓j
CODE:000103A0                 jsr     _WaitToAnimate
CODE:000103A6                 jsr     _ClearControl
CODE:000103AC                 moveq   #2,d0
CODE:000103AE                 move.l  d0,-(sp)
CODE:000103B0                 jsr     sub_1E88C
CODE:000103B6                 addq.l  #4,sp
CODE:000103B8                 moveq   #4,d0
CODE:000103BA                 move.l  d0,-(sp)
CODE:000103BC                 jsr     sub_1E88C
CODE:000103C2                 addq.l  #4,sp
CODE:000103C4                 jsr     _PollJoy
CODE:000103CA                 jsr     _UserIn
CODE:000103D0                 tst.l   (dword_2052A).l
CODE:000103D6                 bne.s   loc_103EA
CODE:000103D8                 movea.l (_aniObj).l,a0

{% file src=“../../.gitbook/assets/shot_68040_amiga.png” %} Disassembly image {% endfile %}

6805 Disassembler

The 6805 microcontroller family is Motorola’s simplest and least-expensive family of microcontrollers. As usual there were many variations of the chips and the part numbers usually contain letter and digits, like 68HC05. IDA is the most powerful disassembler available for those microcontrollers.

68HC05B6, 68HC05B8, 68HC05B16, 68HC705B16, 68HC05B32, 68HC705B32, 68HC05BD5, 68HC05C8A, 68HC705C8A, 68HC05C9A, 68HC705C9A, 68HC705F32, 68HC05J1A, 68HC705J1A, ,68HC05J5A, 68HC705J5A, 68HC05JB3, 68HC705JB3, 68HC05JB4, 68HC705JB4, 68HC05JJ6, ,68HC705JJ7, 68HC05JP6, 68HC705JP7, 68HC05K3, 68HC705KJ1, 68HC05L16, 68HC705L16, ,68HC05L25, 68HC05LJ5, 68HC05P18A, 68HC05P4A, 68HC05P6, 68HC705P6A, 68HC05PV8A, ,68HC805PV8, 68HC05SR3, 68HC705SR3, 68HC05SU3A, 68HC05X4, 68HC705X4, 68HC05X16, ,68HC05X32, 68HC705X32.

Assembler code

RESERVED:01DC                 fcb $BF ; ¿
RESERVED:01DD                 fcb $64 ; d
RESERVED:01DE                 fcb $CF ; Ï
RESERVED:01DF                 fcb   3
RESERVED:01E0 ; ---------------------------------------------------------------------------
RESERVED:01E0                 eorb    $97,x
RESERVED:01E2                 sts     <byte_9D
RESERVED:01E4                 suba    #$81
RESERVED:01E6                 subd    #$8F98
RESERVED:01E9                 oraa    <byte_9C
RESERVED:01EB                 adca    <byte_9B
RESERVED:01ED                 lds     #$200E
RESERVED:01F0                 brn     loc_1FE
RESERVED:01F2                 bhi     loc_1FE
RESERVED:01F4                 bls     loc_1FE
RESERVED:01F6                 bcc     loc_1FE
RESERVED:01F8                 bcc     loc_1FE
RESERVED:01FA                 bcs     loc_1FE
RESERVED:01FC                 bcs     *+2
RESERVED:01FE
RESERVED:01FE loc_1FE:                                ; CODE XREF: RESERVED:01F0↑j
RESERVED:01FE                                         ; RESERVED:01F2↑j ...
RESERVED:01FE                 bne     loc_1FE
RESERVED:0200                 beq     loc_1FE
RESERVED:0202                 bvc     loc_1FE
RESERVED:0204                 bvs     loc_1FE
RESERVED:0206                 bpl     loc_1FE
RESERVED:0208                 bmi     loc_1FE
RESERVED:020A                 bge     loc_1FE
RESERVED:020C                 blt     loc_1FE
RESERVED:020E                 bgt     loc_1FE
RESERVED:0210                 ble     loc_1FE
RESERVED:0212                 jsr     $EA,x
RESERVED:0212 ; ---------------------------------------------------------------------------
RESERVED:0214                 fcb   0

6808 Disassembler

IDA is the most powerful disassembler available for the 6808 family of microcontrollers. Which include the following devices:

68HC08AB16A, 68HC908AB32, 68HC08AS32, 68HC08AS32A, 68HC908AS32A, 68HC908AS60, ,68HC908AS60A, 68HC08AZ32A, 68HC908AZ32A, 68HC08AZ60A, 68HC908AZ60A, 68HC08BD24, 68HC908BD48, ,68HC908EY16, 68HC908GP32, 68HC908GR4, 68HC908GR8, 68HC908GR8A, 68HC908GR16, 68HC908GT8, ,68HC908GT16, 68HC908GZ8, 68HC908GZ16, 68HC08JB1, 68HC908JB16, 68HC908JB8, 68HC08JB8, 68HC908JK1, ,68HC908JK3, 68HC08JK3, 68HC908JK8, 68HC08JK8, 68HC908JL3, 68HC08JL3, 68HC908JL8, 68HC08JL8, 68HC08JT8, 68HC08KH12, 68HC908KX2, 68HC908KX8, 68HC908LD64, 68HC908LJ12, 68HC908MR8, 68HC908MR16, 68HC908MR32, 68HC908QT1, 68HC908QT2, 68HC908QT4, 68HC908QY1, 68HC908QY2, 68HC908QY4, 68HC908RF2, ,8HC908RK2, 68HC908SR12, MC3PHAC, MC9S08GB32, MC9S08GB60, MC9S08GT32, MC9S08GT60.

Assembler code

EXTRA0_87:0000C1B5
EXTRA0_87:0000C1B5 ; =============== S U B R O U T I N E =======================================
EXTRA0_87:0000C1B5
EXTRA0_87:0000C1B5
EXTRA0_87:0000C1B5                 ; public App_OnReadValues
EXTRA0_87:0000C1B5 App_OnReadValues:                       ; CODE XREF: main+2A9↓P
EXTRA0_87:0000C1B5                 pshx
EXTRA0_87:0000C1B6                 pshh
EXTRA0_87:0000C1B7                 tax
EXTRA0_87:0000C1B8                 add     2, sp1
EXTRA0_87:0000C1BB                 sta     1, sp1
EXTRA0_87:0000C1BE                 cpx     #1
EXTRA0_87:0000C1C0                 txa
EXTRA0_87:0000C1C1                 bhi     loc_C1D2
EXTRA0_87:0000C1C3                 tsx
EXTRA0_87:0000C1C4                 ldx     , x
EXTRA0_87:0000C1C5                 cpx     #2
EXTRA0_87:0000C1C7                 bcs     loc_C1D2
EXTRA0_87:0000C1C9                 brset   DDRF6, _LEDC, loc_C1CE
EXTRA0_87:0000C1CC                 clrx
EXTRA0_87:0000C1CD                 skip2
EXTRA0_87:0000C1CE
EXTRA0_87:0000C1CE loc_C1CE:                               ; CODE XREF: App_OnReadValues+14↑j
EXTRA0_87:0000C1CE                 ldx     #1
EXTRA0_87:0000C1D0                 stx     byte_70
EXTRA0_87:0000C1D2
EXTRA0_87:0000C1D2 loc_C1D2:                               ; CODE XREF: App_OnReadValues+C↑j
EXTRA0_87:0000C1D2                                         ; App_OnReadValues+12↑j
EXTRA0_87:0000C1D2                 ldx     #$6F ; 'o'
EXTRA0_87:0000C1D4                 pshx
EXTRA0_87:0000C1D5                 tsx
EXTRA0_87:0000C1D6                 ldx     2, x1
EXTRA0_87:0000C1D8                 jsr     SSD_CopyParmsToAppBuffer
EXTRA0_87:0000C1DB                 ais     #3
EXTRA0_87:0000C1DD                 rts
EXTRA0_87:0000C1DD ; End of function App_OnReadValues
EXTRA0_87:0000C1DD

6809 OS9 Flex Disassembler

FLEX is the name of the Operating System for the Motorola 6800 and 6809. IDA can disassemble OS9 object and FLEX STX files and is probably the most powerful disassembler for that platform.

Assembler code

TEXT:54A5
TEXT:54A5 * =============== S U B R O U T I N E =======================================
TEXT:54A5
TEXT:54A5
TEXT:54A5 sub_54A5                                * CODE XREF: sub_4F06+78↑P
TEXT:54A5                                         * sub_5048+1CB↑P ...
TEXT:54A5                 pshs    dpr,y,u
TEXT:54A7                 ldy     7,s
TEXT:54AA                 ldx     ,y
TEXT:54AC                 ldd     9,s
TEXT:54AE                 aslb
TEXT:54AF                 leay    b,y
TEXT:54B1                 ldd     $B,s
TEXT:54B3                 pshs    a,b,x
TEXT:54B5                 tfr     b,a
TEXT:54B7                 ldu     ,y
TEXT:54B9                 beq     loc_54BD
TEXT:54BB                 jsr     ,u
TEXT:54BD
TEXT:54BD loc_54BD                                * CODE XREF: sub_54A5+14↑j
TEXT:54BD                 tfr     a,b
TEXT:54BF                 clra
TEXT:54C0                 leas    4,s
TEXT:54C2                 puls    pcr,u,y,dpr
TEXT:54C2 * End of function sub_54A5
TEXT:54C2
TEXT:54C4
TEXT:54C4 * =============== S U B R O U T I N E =======================================
TEXT:54C4
TEXT:54C4
TEXT:54C4 sub_54C4                                * CODE XREF: sub_4C67+63↑P
TEXT:54C4                                         * sub_4C67+87↑P ...
TEXT:54C4                 pshs    dpr,y,u
TEXT:54C6                 lda     $C,s
TEXT:54C8                 ldx     7,s

6809 Disassembler

FLEX is the name of the Operating System for the Motorola 6800 and 6809. IDA can disassemble OS9 object and FLEX STX files

Assembler code\

TEXT:102F                 bcs     loc_1065
TEXT:1031                 leax    ,u
TEXT:1033
TEXT:1033 loc_1033                                * CODE XREF: start+25↓j
TEXT:1033                 clr     ,x+
TEXT:1035                 subd    #1
TEXT:1038                 bhi     loc_1033
TEXT:103A                 stu     $80
TEXT:103C                 ldd     ,s++
TEXT:103E                 std     $B0
TEXT:1040                 ldd     ,s++
TEXT:1042                 leax    d,u
TEXT:1044                 stx     $82
TEXT:1046                 ldd     $B0
TEXT:1048                 leax    d,x
TEXT:104A                 stx     $B0
TEXT:104C                 ldx     $88
TEXT:104E                 OS9     F$All64 * '0'   * Allocate Process/Path Descriptor
TEXT:1051                 bcs     loc_1065
TEXT:1053                 stx     $88
TEXT:1055                 OS9     F$Ret64 * '1'   * Return Process/Path Descriptor
TEXT:1058                 leax    word_16A2,pc
TEXT:105C                 stx     $26
TEXT:105E                 leay    word_1067,pc
TEXT:1061                 OS9     F$SSvc * '2'    * Service Request Table Initialization
TEXT:1064                 rts
TEXT:1065 * ---------------------------------------------------------------------------
TEXT:1065
TEXT:1065 loc_1065                                * CODE XREF: start+1C↑j
TEXT:1065                                         * start+3E↑j
TEXT:1065                 jmp     $6B
TEXT:1065 * End of function start
TEXT:1065
TEXT:1065 * ---------------------------------------------------------------------------
TEXT:1067 word_1067       fdb $7F00               * DATA XREF: start+4B↑r

6811 Disassembler

The 68HC11 is a powerful 8-bit data, 16-bit address microcontroller from Motorola. IDA is, without any doubts, the most powerful 6811 disassembler. Here are a few part numbers of that huge family: 68HC11D0, 68HC11D3, 68HC711D3, 68HC11E0, 68HC11E1, 68HC11E9, 68HC11EA9, 68HC711E9, 68HC11E20, 68HC711E20, 68HC11F1, 68HC11K0, 68HC11K1, 68HC11K4, 68HC11KS1, 68HC11KS2, 68HC711KS2, 68HC11P1, 68HC11P2.

Assembler code\

RAM:00B4                 asl     $B4,y
RAM:00B7                 asl     $88,y
RAM:00BA
RAM:00BA loc_BA:                                 ; DATA XREF: RAM:loc_BA↓w
RAM:00BA                 asl     loc_BA
RAM:00BD                 asl     word_8888
RAM:00C0                 asra
RAM:00C1                 asrb
RAM:00C2                 asr     word_8888
RAM:00C5                 asr     word_8888
RAM:00C8                 asr     0,x
RAM:00CA                 asr     $CA,x
RAM:00CC                 asr     $88,x
RAM:00CE                 asr     0,y
RAM:00D1                 asr     $D1,y
RAM:00D4                 asr     $88,y
RAM:00D7
RAM:00D7 loc_D7:                                 ; DATA XREF: RAM:loc_D7↓w
RAM:00D7                 asr     loc_D7
RAM:00DA                 asr     word_8888
RAM:00DD                 bclr    $DD,x 0
RAM:00E0                 bclr    $E0,x $88 ; 'ˆ'
RAM:00E3                 bclr    $88,x $88 ; 'ˆ'
RAM:00E6                 bclr    $E6,y $88 ; 'ˆ'
RAM:00EA                 bclr    $88,y $88 ; 'ˆ'
RAM:00EE                 bita    #0
RAM:00F0
RAM:00F0 loc_F0:                                 ; DATA XREF: RAM:loc_F0↓r
RAM:00F0                 bita    <loc_F0
RAM:00F2                 bita    0,x
RAM:00F4                 bita    $F4,x
RAM:00F6                 bita    $88,x
RAM:00F8                 bita    0,y
RAM:00FB                 bita    $FB,y
RAM:00FB ; ---------------------------------------------------------------------------

68HC12 Disassembler

The 68HC12 is a Motorola microcontroller that has been widely used by the automotive industry. IDA is the most powerful disassembler available for the 68HC12 family and a car tuner’s favourite. Typical parts include the 68HC812A4, 68HC912B32, 68HC912BC32, 68HC12BC32, 68HC12BE32, 68HC12D60, 68HC912D60, 68HC912D60A, 68HC912D60C, 68HC912D60P, 68HC912DG128A, 68HC912DG128C, 68HC912DG128P, 68HC912DT128A, 68HC912DT128C, 68HC912DT128P and, in its automotive versions, 68HC912B32, 68HC912BC32, 68HC12BC32, 68HC12BE32, 68HC912D60A, 68HC912D60C, 68HC912D60P, 68HC12D60, 68HC912DG128A, 68HC912DG128C, 68HC912DG128P, 68HC912DT128A, 68HC912DT128C, 68HC912DT128P.

Assembler code

.text:00000042
.text:00000042 ; =============== S U B R O U T I N E =======================================
.text:00000042
.text:00000042
.text:00000042 L26:                                    ; CODE XREF: L26:L87↓p
.text:00000042                 addd    symbol141
.text:00000045
.text:00000045 L27:
.text:00000045                 addd    $76,x
.text:00000048
.text:00000048 L28:
.text:00000048                 anda    #$5A ; 'Z'
.text:0000004A
.text:0000004A L29:
.text:0000004A                 anda    Z46
.text:0000004C
.text:0000004C L30:
.text:0000004C                 anda    $63,x
.text:0000004F
.text:0000004F L31:
.text:0000004F                 anda    symbol51
.text:00000052
.text:00000052 L32:
.text:00000052                 anda    $9F,x
.text:00000055
.text:00000055 L33:
.text:00000055                 andb    #$C9 ; 'É'
.text:00000057
.text:00000057 L34:
.text:00000057                 andb    Z154
.text:00000059
.text:00000059 L35:
.text:00000059                 andb    $66,x
.text:0000005C
.text:0000005C L36:
.text:0000005C                 andb    symbol50

68HC16 Disassembler

The 68HC16 is a Motorola microcontroller that is used, among other things, in the automotive industry: IDA is the most powerful disassembler for the 68HC16Y1 , 68HC16Z1, 68HC16Z3 processors and is widely used by car tuner and race teams.

Assembler code

RESERVED:01BC                 fcb  $D
RESERVED:01BD                 fcb $7F ; 
RESERVED:01BE                 fcb  $D
RESERVED:01BF                 fcb $80 ; €
RESERVED:01C0 ; ---------------------------------------------------------------------------
RESERVED:01C0                 sec
RESERVED:01C1                 stx     byte_E00
RESERVED:01C4                 cli
RESERVED:01C5                 nop
RESERVED:01C6                 cli
RESERVED:01C7                 clr     byte_E80
RESERVED:01CA                 cli
RESERVED:01CB                 stx     byte_F00
RESERVED:01CE                 sei
RESERVED:01CF                 nop
RESERVED:01D0                 sei
RESERVED:01D1                 clr     byte_F80
RESERVED:01D4                 sei
RESERVED:01D5                 stx     PORTA           ; Port A data
RESERVED:01D8                 sba
RESERVED:01D9                 nop
RESERVED:01DA                 sba
RESERVED:01DB                 clr     byte_1080
RESERVED:01DE                 sba
RESERVED:01DF                 stx     byte_1100
RESERVED:01E2                 cba
RESERVED:01E3                 nop
RESERVED:01E4                 cba
RESERVED:01E5                 clr     byte_1180
RESERVED:01E8                 cba
RESERVED:01E9                 stx     byte_1200
RESERVED:01EC                 brset   <byte_1 $12 loc_26F
RESERVED:01F0
RESERVED:01F0 loc_1F0:                                ; CODE XREF: RESERVED:loc_1F0↑j
RESERVED:01F0                 brset   <byte_80 $12 loc_1F0+3

68k Amiga Disassembler

IDA is the best disassembler for Amiga hunk files. The Motorola 68K family of processors is huge and very widely used. A few sample parts: MC68000, MC68010, MC68020, MC68030, MC68040, MC68330, MC68882, MC68851, MC68020EX, MC68302 Integrated Communication Processor, MC68306 68K/ColdFire, MC68331 68K/ColdFire, MC68332 68K/ColdFire, MC68336 68K/ColdFire, MC68340 68K/ColdFire, MC68360 Integrated Communication Processor, MC68F375 68K/ColdFire, MC68376 68K/ColdFire, etc….

Assembler code

CODE:00010190
CODE:00010190 ; =============== S U B R O U T I N E =======================================
CODE:00010190
CODE:00010190
CODE:00010190 waitmsg:                                ; CODE XREF: startup+DE↑p
CODE:00010190                 lea     $5C(a4),a0
CODE:00010194                 jsr     -$180(a6)
CODE:00010198                 lea     $5C(a4),a0
CODE:0001019C                 jsr     -$174(a6)
CODE:000101A0                 rts
CODE:000101A0 ; End of function waitmsg
CODE:000101A0
CODE:000101A2
CODE:000101A2 ; =============== S U B R O U T I N E =======================================
CODE:000101A2
CODE:000101A2
CODE:000101A2 openDOS:                                ; CODE XREF: startup:fromCLI↑p
CODE:000101A2                                         ; startup:fromWorkbench↑p
CODE:000101A2
CODE:000101A2 ; FUNCTION CHUNK AT CODE:00010176 SIZE 0000001A BYTES
CODE:000101A2
CODE:000101A2                 clr.l   (_DOSBase).l
CODE:000101A8                 lea     (DOSName).l,a1  ; "dos.library"
CODE:000101AE                 move.l  #$1E,d0
CODE:000101B4                 jsr     -$228(a6)
CODE:000101B8                 move.l  d0,(_DOSBase).l
CODE:000101BE                 beq.s   noDOS
CODE:000101C0                 rts
CODE:000101C0 ; End of function openDOS
CODE:000101C0
CODE:000101C0 ; ---------------------------------------------------------------------------
CODE:000101C2                 align 4
CODE:000101C2 ; end of 'CODE'
CODE:000101C2
DATA:000101D0 ; ===========================================================================
DATA:000101D0
DATA:000101D0 ; Segment type: Pure data
DATA:000101D0 ; segment "DATA"
DATA:000101D0 VerRev:         dc.l startup

68k Mac OS

IDA is the most powerful disassembler for Max OS 8 and Mac OS 9 PEF files.

The Motorola 68K family of processors is huge and very widely used. A few sample parts: MC68000, MC68010, MC68020, MC68030, MC68040, MC68330, MC68882, MC68851, MC68020EX, MC68302 Integrated Communication Processor, MC68306 68K/ColdFire, MC68331 68K/ColdFire, MC68332 68K/ColdFire, MC68336 68K/ColdFire, MC68340 68K/ColdFire, MC68360 Integrated Communication Processor, MC68F375 68K/ColdFire, MC68376 68K/ColdFire, etc.

Assembler code

seg000:40800530
seg000:40800530 ; =============== S U B R O U T I N E =======================================
seg000:40800530
seg000:40800530
seg000:40800530 sub_0_40800530:                         ; CODE XREF: sub_0_40800194+164↑p
seg000:40800530                 pea     -4(a5)
seg000:40800534                 _InitGraf               ; f
seg000:40800536                 pea     -$200(a6)
seg000:4080053A                 _OpenCPort              ; ort
seg000:4080053C                 movea.l (a5),a2
seg000:4080053E                 pea     -$6C(a2)
seg000:40800542                 _SetCursor              ; or
seg000:40800544                 lea     -$74(a2),a0
seg000:40800548                 move.l  a0,-(sp)
seg000:4080054A                 lea     ($9FA).w,a1
seg000:4080054E                 move.l  a1,-(sp)
seg000:40800550                 move.l  a1,-(sp)
seg000:40800552                 move.l  (a0)+,(a1)+
seg000:40800554                 move.l  (a0),(a1)
seg000:40800556                 move.l  #-$20003,-(sp)
seg000:4080055C                 _InsetRect              ; ct
seg000:4080055E                 move.l  #$30003,-(sp)
seg000:40800564                 _PenSize
seg000:40800566                 move.l  #$160016,-(sp)
seg000:4080056C                 _FrameRoundRect         ; undRect
seg000:4080056E                 _PenNormal              ; al
seg000:40800570                 move.l  #$100010,-(sp)
seg000:40800576                 pea     -$18(a2)
seg000:4080057A                 _FillRoundRect          ; ndRect
seg000:4080057C                 rts
seg000:4080057C ; End of function sub_0_40800530
seg000:4080057C
seg000:4080057C ; ---------------------------------------------------------------------------
seg000:4080057E                 align $10
seg000:40800580
seg000:40800580 ; =============== S U B R O U T I N E =======================================
seg000:40800580
seg000:40800580
seg000:40800580 sub_0_40800580:                         ; CODE XREF: sub_0_40800194+80↑p
seg000:40800580                 clr.w   -(sp)

68k Palm Pilot

IDA is the best disassembler for Palm Pilot programs. It supports all Palm OS versions and will even accept partially packed programs. The Palm Pilot uses a 68K processor.

The Motorola 68K family of processors is huge and very widely used. A few sample parts: MC68000, MC68010, MC68020, MC68030, MC68040, MC68330, MC68882, MC68851, MC68020EX, MC68302 Integrated Communication Processor, MC68306 68K/ColdFire, MC68331 68K/ColdFire, MC68332 68K/ColdFire, MC68336 68K/ColdFire, MC68340 68K/ColdFire, MC68360 Integrated Communication Processor, MC68F375 68K/ColdFire, MC68376 68K/ColdFire, etc.

Assembler code

code0001:00000204
code0001:00000204 ; =============== S U B R O U T I N E =======================================
code0001:00000204
code0001:00000204 ; Attributes: bp-based frame
code0001:00000204
code0001:00000204 proc            sub_204()               ; CODE XREF: sub_31E+A0↓p
code0001:00000204
code0001:00000204 var_68          = -$68
code0001:00000204 var_50          = -$50
code0001:00000204 arg_0           =  8
code0001:00000204 arg_8           =  $10
code0001:00000204 arg_A           =  $12
code0001:00000204
code0001:00000204                 link    a6,#-$50
code0001:00000208                 movem.l d3-d6/a2-a3,-(sp)
code0001:0000020C                 movea.l arg_0(a6),a3
code0001:00000210                 move.w  arg_8(a6),d0
code0001:00000214                 beq.s   loc_222
code0001:00000216                 addi.w  #-$8000,d0
code0001:0000021A                 clr.l   d4
code0001:0000021C                 move.w  d0,d4
code0001:0000021E                 bra     loc_224
code0001:00000222 ; ---------------------------------------------------------------------------
code0001:00000222
code0001:00000222 loc_222:                                ; CODE XREF: sub_204+10↑j
code0001:00000222                 moveq   #0,d4
code0001:00000224
code0001:00000224 loc_224:                                ; CODE XREF: sub_204+1A↑j
code0001:00000224                 move.w  d4,-(sp)
code0001:00000226                 move.l  #$636F6465,-(sp)
code0001:0000022C                 systrap DmGet1Resource()
code0001:00000230                 move.l  a0,d5
code0001:00000232                 addq.w  #6,sp
code0001:00000234                 bne.s   loc_272
code0001:00000236                 lea     aCouldNotLoadCo(pc),a1 ; "Could not load code segment #"

Unix COFF

IDA is the most powerful disassembler for 68K UNIX COFF Files. The Motorola 68K family of processors is huge and very widely used. A few sample parts: MC68000, MC68010, MC68020, MC68030, MC68040, MC68330, MC68882, MC68851, MC68020EX, MC68302 Integrated Communication Processor, MC68306 68K/ColdFire, MC68331 68K/ColdFire, MC68332 68K/ColdFire, MC68336 68K/ColdFire, MC68340 68K/ColdFire, MC68360 Integrated Communication Processor, MC68F375 68K/ColdFire, MC68376 68K/ColdFire, etc.

Assembler code

.text:000001AC
.text:000001AC ; =============== S U B R O U T I N E =======================================
.text:000001AC
.text:000001AC ; Attributes: bp-based frame
.text:000001AC
.text:000001AC                 global new_main
.text:000001AC new_main:                               ; CODE XREF: main+16↑p
.text:000001AC
.text:000001AC var_C           = -$C
.text:000001AC
.text:000001AC                 link    a6,#-$10
.text:000001B2                 movem.l 0,$10+var_C(sp)
.text:000001B8                 fmovem  0,$10+var_C.l(sp)
.text:000001C2
.text:000001C2 qwerty:                                 ; CODE XREF: new_main+96↓j
.text:000001C2                 pea     var_C+4(a6)
.text:000001C6                 pea     var_C+8(a6)
.text:000001CA                 move.l  #aLdLd,-(sp)    ; "%ld %ld"
.text:000001D0                 jsr     (scanf).l
.text:000001D6                 adda.w  #$C,sp
.text:000001DA                 tst.l   var_C+8(a6)
.text:000001DE                 bne.w   loc_200
.text:000001E2                 tst.l   var_C+4(a6)
.text:000001E6                 bne.w   loc_200
.text:000001EA                 move.l  (fignqm).l,d0
.text:000001F0                 add.l   (fignqn).l,d0
.text:000001F6                 add.l   (fignqr).l,d0
.text:000001FC                 bra.w   loc_246
.text:00000200 ; ---------------------------------------------------------------------------
.text:00000200
.text:00000200 loc_200:                                ; CODE XREF: new_main+32↑j
.text:00000200                                         ; new_main+3A↑j
.text:00000200                 move.l  var_C+4(a6),(sp)
.text:00000204                 move.l  var_C+8(a6),-(sp)
.text:00000208                 jsr     (b1).l

NEC 78k0 and 78k0s Processor

These NEC microcontrollers are available under many part numbers, which are all supported by the IDA Disassembler. IDA is the most powerful disassembler available for that line.

78K0/KB1

uPD78075B, uPD78078, uPD78078Y, uPD78070A, uPD78070AY, uPD780058, uPD780058Y, uPD780065, uPD780078, uPD780078Y, uPD780034AS, uPD780024AS uPD780034A, uPD780024A, uPD780034AY, uPD780024AY, uPD780988, uPD780208, uPD780232, uPD78044F, uPD780354, uPD780344, uPD780354Y, uPD780344Y, uPD780338, uPD780328, uPD780318, uPD780308, uPD780308Y, uPD78064B, uPD78064, uPD78064Y, uPD78098B, uPD780702Y, uPD780833Y, uPD780958, uPD780852, uPD780828B, uPD780101, uPD780102, uPD780103, uPD78F010

78K0S

uPD789046, uPD789026, uPD789074, uPD789088, uPD789062, uPD789052, uPD789177Y, uPD789167Y, uPD789177, uPD789167, uPD789134A, uPD789124A, uPD789114A, uPD789104A, uPD789842, uPD789417A, uPD789407A, uPD789456, uPD789446, uPD789436, uPD789426, uPD789316, uPD789306, uPD789467, uPD789327, uPD789835, uPD789830, uPD789479, uPD789489, uPD789800, uPD789862, uPD789861, uPD789860, uPD789850, uPD789871, uPD789881, uPD78F9026, uPD78F9046, uPD78F9076, uPD78F9116, uPD78F9136, uPD78F9177, uPD78F9306, uPD78F9316, uPD78F9328, uPD78F9418, uPDF78F9436, uPD78F9456, uPD78F9468, uPD78F9478, uPD78F9488, uPD78F9801, uPD78F9842, uPD78F9850.

Assembler code

ROM_:00B9                 set1    CY
ROM_:00BA                 set1    byte_FED3.00h
ROM_:00BC                 set1    byte_FED7.00h
ROM_:00BE                 set1    byte_FEDB.00h
ROM_:00C0                 set1    byte_FEDF.00h
ROM_:00C2                 set1    byte_FEDD.00h
ROM_:00C4                 callt   [word_54]
ROM_:00C5                 set1    CY
ROM_:00C6                 incw    AX
ROM_:00C7                 incw    DE
ROM_:00C8                 add     byte_FE8C, #90h
ROM_:00CB                 decw    DE
ROM_:00CC                 sub     byte_FE9C, #00h
ROM_:00CF                 movw    AX, #1202h
ROM_:00D2                 set1    CR00.00h        ; 16-bit timer capture/compare register 00
ROM_:00D4                 callt   [word_64]
ROM_:00D5                 set1    SIO30.00h       ; Serial I/O shift register 30
ROM_:00D7                 callt   [word_64]
ROM_:00D8                 set1    byte_FE2A.00h
ROM_:00DA                 callt   [word_64]
ROM_:00DB                 set1    byte_FE3A.00h
ROM_:00DD                 callt   [word_64]
ROM_:00DE                 set1    byte_FE4A.00h
ROM_:00E0                 callt   [word_64]
ROM_:00E1                 set1    byte_FE5A.00h
ROM_:00E3                 callt   [word_64]
ROM_:00E4                 set1    byte_FE6A.00h
ROM_:00E6                 callt   [word_64]
ROM_:00E7                 set1    byte_FE7A.00h
ROM_:00E9                 callt   [word_64]
ROM_:00EA                 set1    CR00.00h        ; 16-bit timer capture/compare register 00
ROM_:00EA ; ---------------------------------------------------------------------------
ROM_:00EC                 .db  15h
ROM_:00ED                 .db  0Ah
ROM_:00EE                 .db  1Ah

80196 Processor

IDA is probably the most powerful disassembler available for the INTEL 80196 line of micro-processors. IDA disassemble the Intel 80196, 80196NP and its variations.

Assembler code

INTMEM:007C                 db 0FFh ; ÿ
INTMEM:007D                 db 0FFh ; ÿ
INTMEM:007E                 db 0FFh ; ÿ
INTMEM:007F                 db 0FFh ; ÿ
INTMEM:0080 ; ---------------------------------------------------------------------------
INTMEM:0080                 skip    INTMEM_FF
INTMEM:0082                 clr     INTMEM_20
INTMEM:0084                 not     INTMEM_20
INTMEM:0086                 neg     INTMEM_20
INTMEM:0088                 xch     INTMEM_20, INTMEM_20
INTMEM:008B                 dec     INTMEM_20
INTMEM:008D                 ext     INTMEM_22
INTMEM:008F                 inc     INTMEM_20
INTMEM:0091                 shr     INTMEM_20, #8
INTMEM:0094                 shr     INTMEM_20, INTMEM_FF
INTMEM:0097                 shl     INTMEM_20, INTMEM_FF
INTMEM:009A                 shra    INTMEM_20, INTMEM_FF
INTMEM:009D                 xch     INTMEM_20, 55h[INTMEM_20]
INTMEM:00A1                 xch     INTMEM_20, 3030h[INTMEM_20]
INTMEM:00A6                 shrl    INTMEM_22, INTMEM_FF
INTMEM:00A9                 shll    INTMEM_22, INTMEM_FF
INTMEM:00AC                 shral   INTMEM_22, INTMEM_FF
INTMEM:00AF                 norml   INTMEM_22, INTMEM_FF
INTMEM:00B2                 clrb    INTMEM_FF
INTMEM:00B4                 notb    INTMEM_FF
INTMEM:00B6                 negb    INTMEM_FF
INTMEM:00B8                 xchb    INTMEM_FF, INTMEM_FF
INTMEM:00BB                 decb    INTMEM_FF
INTMEM:00BD                 extb    INTMEM_20
INTMEM:00BF                 incb    INTMEM_FF
INTMEM:00C1                 shrb    INTMEM_FF, INTMEM_FF
INTMEM:00C4                 shlb    INTMEM_FF, INTMEM_FF
INTMEM:00C7                 shrab   INTMEM_FF, INTMEM_FF
INTMEM:00CA                 xchb    INTMEM_FF, 55h[INTMEM_20]
INTMEM:00CE                 sjmp    INTMEM_D2
INTMEM:00CE ; ---------------------------------------------------------------------------

8051 Disassembler

Assembler code

code:0000019C                 .byte    0
code:0000019D                 .byte 0xFF ; ÿ
code:0000019E                 .byte 0xF5 ; õ
code:0000019F                 .byte 0xFF ; ÿ
code:000001A0 ; ---------------------------------------------------------------------------
code:000001A0                 mov     RESERVED00FF, R0 ; RESERVED
code:000001A2                 mov     RESERVED00FF, R1 ; RESERVED
code:000001A4                 mov     RESERVED00FF, R2 ; RESERVED
code:000001A6                 mov     RESERVED00FF, R3 ; RESERVED
code:000001A8                 mov     RESERVED00FF, R4 ; RESERVED
code:000001AA                 mov     RESERVED00FF, R5 ; RESERVED
code:000001AC                 mov     RESERVED00FF, R6 ; RESERVED
code:000001AE                 mov     RESERVED00FF, R7 ; RESERVED
code:000001B0                 mov     RESERVED00FF, RAM_0 ; RESERVED
code:000001B3                 mov     RESERVED00FF, RESERVED00FF ; RESERVED
code:000001B6                 mov     RESERVED00FF, @R0 ; RESERVED
code:000001B8                 mov     RESERVED00FF, @R1 ; RESERVED
code:000001BA                 mov     RESERVED00FF, #0 ; RESERVED
code:000001BD                 mov     RESERVED00FF, #0xFF ; RESERVED
code:000001C0                 mov     @R0, #0
code:000001C2                 mov     @R0, #0xFF
code:000001C4                 mov     @R0, RAM_0
code:000001C6                 mov     @R0, RESERVED00FF ; RESERVED
code:000001C8                 mov     @R0, A
code:000001C9                 mov     @R1, #0
code:000001CB                 mov     @R1, #0xFF
code:000001CD                 mov     @R1, RAM_0
code:000001CF                 mov     @R1, RESERVED00FF ; RESERVED
code:000001D1                 mov     @R1, A
code:000001D2                 mov     C, RAM_20.0
code:000001D4                 mov     C, P5.7         ; Port 5
code:000001D6                 mov     RAM_20.0, C
code:000001D8                 mov     P5.7, C         ; Port 5
code:000001DA                 mov     DPTR, #0xFF
code:000001DD                 mov     DPTR, #0xFF00

Analog Devices 218x.

Assembler code

ROM:0034 ; ---------------------------------------------------------------------------
ROM:0034
ROM:0034 loc_34:                                 ; CODE XREF: TIMER+CF↓j
ROM:0034                 ar = $37
ROM:0035                 dm(byte_1003F4F) = ar
ROM:0036                 jump loc_25C3
ROM:0037 ; ---------------------------------------------------------------------------
ROM:0037                 imask = $240
ROM:0038
ROM:0038 loc_38:                                 ; CODE XREF: TIMER+12↓j
ROM:0038                 ar = dm(byte_1003E33)
ROM:0039                 ar = ar - 1
ROM:003A                 if lt jump loc_38
ROM:003B                 imask = $250
ROM:003C
ROM:003C loc_3C:                                 ; CODE XREF: TIMER+16↓j
ROM:003C                 ar = dm(byte_1003E33)
ROM:003D                 ar = ar - 2
ROM:003E                 if lt jump loc_3C
ROM:003F                 imask = $269
ROM:0040
ROM:0040 loc_40:                                 ; CODE XREF: TIMER+1A↓j
ROM:0040                 ar = dm(byte_1003F12)
ROM:0041                 ar = ar + 0
ROM:0042                 if eq jump loc_40
ROM:0043                 jump loc_6E
ROM:0044 ; ---------------------------------------------------------------------------
ROM:0044
ROM:0044 loc_44:                                 ; CODE XREF: TIMER+2F↓j
ROM:0044                                         ; TIMER+38↓j ...
ROM:0044                 ena timer
ROM:0045                 ay0 = dm(byte_1002CD2)
ROM:0046                 ax0 = dm(byte_1002CD3)
ROM:0047                 ar = ay0 - ax0
ROM:0048                 if ge jump loc_4B

Alpha Processor – NT COFF

Assembler code

.text:0000000080900A90
.text:0000000080900A90 # =============== S U B R O U T I N E =======================================
.text:0000000080900A90
.text:0000000080900A90
.text:0000000080900A90 sub_80900A90:                           # CODE XREF: start+360↑p
.text:0000000080900A90                                         # start+3A4↑p ...
.text:0000000080900A90                 beq     $17, locret_80900B2C
.text:0000000080900A94                 subq    $17, 4, $20
.text:0000000080900A98                 ldq_u   $28, 0($18)
.text:0000000080900A9C                 addq    $17, $18, $27
.text:0000000080900AA0                 andnot  $16, 3, $19
.text:0000000080900AA4                 bge     $20, loc_80900B30
.text:0000000080900AA8                 ldq_u   $27, -1($27)
.text:0000000080900AAC                 and     $16, 3, $16
.text:0000000080900AB0                 ldl     $17, 0($19)
.text:0000000080900AB4                 addq    $20, $16, $20
.text:0000000080900AB8                 extql   $28, $18, $28
.text:0000000080900ABC                 bgt     $20, loc_80900AF0
.text:0000000080900AC0                 extqh   $27, $18, $27
.text:0000000080900AC4                 addq    $20, 4, $20
.text:0000000080900AC8                 or      $27, $28, $28
.text:0000000080900ACC                 insql   $28, $16, $28
.text:0000000080900AD0                 mskql   $17, $16, $18
.text:0000000080900AD4                 mskql   $28, $20, $28
.text:0000000080900AD8                 mskqh   $17, $20, $17
.text:0000000080900ADC                 or      $18, $28, $28
.text:0000000080900AE0                 or      $17, $28, $28
.text:0000000080900AE4                 stl     $28, 0($19)
.text:0000000080900AE8                 addq    $19, $20, $16
.text:0000000080900AEC                 ret     $31, ($26), 4
.text:0000000080900AF0 # ---------------------------------------------------------------------------
.text:0000000080900AF0
.text:0000000080900AF0 loc_80900AF0:                           # CODE XREF: sub_80900A90+2C↑j
.text:0000000080900AF0                 extqh   $27, $18, $27
.text:0000000080900AF4                 ldl     $18, 4($19)

Alpha Processor – Unix ELF

Assembler code


.text:0000000120001F30                 br      loc_120001FD0
.text:0000000120001F34 # ---------------------------------------------------------------------------
.text:0000000120001F34
.text:0000000120001F34 loc_120001F34:                          # CODE XREF: main+274↑j
.text:0000000120001F34                 addq    $sp, 0xB8, $1 # '¸'
.text:0000000120001F38                 ldq     $16, 0x220+stream($sp) # stream
.text:0000000120001F3C                 ldq     $17, ((off_120103268 - 0x12010B130) and 0xFFFF)($gp)# off_120103268 # format
.text:0000000120001F40                 mov     $1, $18
.text:0000000120001F44                 ldq     $27, ((fscanf_ptr - 0x12010B130) and 0xFFFF)($gp)# fscanf_ptr
.text:0000000120001F48                 jsr     $26, ($27), 0x1620# fscanf
.text:0000000120001F4C                 ldah    $gp, 0x11($26)
.text:0000000120001F50                 lda     $gp, -0x6E1C($gp)
.text:0000000120001F54                 # gp = 000000012010B130
.text:0000000120001F54                 mov     $0, $1
.text:0000000120001F58                 subq    $1, 1, $2
.text:0000000120001F5C                 bne     $2, loc_120001FAC
.text:0000000120001F60                 addq    $sp, 0xB8, $1 # '¸'
.text:0000000120001F64                 mov     $1, $16         # s1
.text:0000000120001F68                 ldq     $17, ((s2 - 0x12010B130) and 0xFFFF)($gp)# s2 # s2
.text:0000000120001F6C                 ldq     $27, ((strcmp_ptr - 0x12010B130) and 0xFFFF)($gp)# strcmp_ptr
.text:0000000120001F70                 jsr     $26, ($27), 0x16DC# strcmp
.text:0000000120001F74                 ldah    $gp, 0x11($26)
.text:0000000120001F78                 lda     $gp, -0x6E44($gp)
.text:0000000120001F7C                 # gp = 000000012010B130
.text:0000000120001F7C                 mov     $0, $1
.text:0000000120001F80                 addq    $1, 0, $2
.text:0000000120001F84                 bne     $2, loc_120001F94
.text:0000000120001F88                 ldq     $1, ((clockport_ptr - 0x12010B130) and 0xFFFF)($gp)# clockport_ptr
.text:0000000120001F8C                 lda     $2, 0x170($31)
.text:0000000120001F90                 stl     $2, 0($1)
.text:0000000120001F94
.text:0000000120001F94 loc_120001F94:                          # CODE XREF: main+2CC↑j
.text:0000000120001F94                 ldq     $16, 0x220+stream($sp) # stream
.text:0000000120001F98                 ldq     $27, ((fclose_ptr - 0x12010B130) and 0xFFFF)($gp)# fclose_ptr
.text:0000000120001F9C                 jsr     $26, ($27), 0x1698# fclose

Android ARM Executables (.elf)

Assembler code

.text:00008270
.text:00008270 ; =============== S U B R O U T I N E =======================================
.text:00008270
.text:00008270 ; Attributes: library function noreturn bp-based frame
.text:00008270
.text:00008270                 EXPORT _start
.text:00008270 _start                                  ; DATA XREF: LOAD:00008018↑o
.text:00008270
.text:00008270 structors       = -0x14
.text:00008270 var_8           = -8
.text:00008270
.text:00008270                 LDR     R12, =(_GLOBAL_OFFSET_TABLE_ - 0x828C)
.text:00008274                 PUSH    {R11,LR}
.text:00008278                 LDR     R3, =(__PREINIT_ARRAY___ptr - 0x9FEC)
.text:0000827C                 ADD     R11, SP, #4
.text:00008280                 SUB     SP, SP, #0x10
.text:00008284                 ADD     R12, PC, R12    ; _GLOBAL_OFFSET_TABLE_
.text:00008288                 LDR     R3, [R12,R3]    ; __PREINIT_ARRAY__
.text:0000828C                 STR     R3, [R11,#structors]
.text:00008290                 LDR     R3, =(__INIT_ARRAY___ptr - 0x9FEC)
.text:00008294                 ADD     R0, R11, #4     ; raw_args
.text:00008298                 LDR     R3, [R12,R3]    ; __INIT_ARRAY__
.text:0000829C                 STR     R3, [R11,#structors.init_array]
.text:000082A0                 LDR     R3, =(__FINI_ARRAY___ptr - 0x9FEC)
.text:000082A4                 MOV     R1, #0          ; onexit
.text:000082A8                 LDR     R3, [R12,R3]    ; __FINI_ARRAY__
.text:000082AC                 STR     R3, [R11,#structors.fini_array]
.text:000082B0                 LDR     R3, =(__CTOR_LIST___ptr - 0x9FEC)
.text:000082B4                 LDR     R3, [R12,R3]    ; __CTOR_LIST__
.text:000082B8                 STR     R3, [R11,#var_8]
.text:000082BC                 LDR     R3, =(main_ptr - 0x9FEC)
.text:000082C0                 LDR     R2, [R12,R3]    ; main ; slingshot
.text:000082C4                 SUB     R3, R11, #-structors ; structors
.text:000082C8                 BL      __libc_init
.text:000082CC ; ---------------------------------------------------------------------------
.text:000082CC                 SUB     SP, R11, #4

ARC Processor

Assembler code

.text:0000109C
.text:0000109C # =============== S U B R O U T I N E =======================================
.text:0000109C
.text:0000109C # Attributes: bp-based frame
.text:0000109C
.text:0000109C                 .global ArcMain
.text:0000109C ArcMain:                                # CODE XREF: main+C↑p
.text:0000109C
.text:0000109C arg_0           =  0
.text:0000109C arg_4           =  4
.text:0000109C
.text:0000109C                 st      blink, [sp,arg_4]
.text:000010A0                 st      fp, [sp,arg_0]
.text:000010A4                 mov     fp, sp
.text:000010A8                 sub     sp, sp, 0x10
.text:000010AC                 mov     r0, state_ls
.text:000010B4                 bl.d    Core_LocalClear
.text:000010B8                 mov     r1, 0x18
.text:000010BC                 mov     r2, _stack_start
.text:000010C4                 mov     r0, 0x12345678
.text:000010CC                 sub     r1, r1, r1
.text:000010D0                 mov     lp_count, 0x20 # ' '
.text:000010D4                 lp      loc_10E4
.text:000010D8                 add     r12, r2, r1
.text:000010DC                 st      r0, [r12]
.text:000010E0                 add     r1, r1, 4
.text:000010E4
.text:000010E4 loc_10E4:                               # CODE XREF: ArcMain+38↑j
.text:000010E4                 mov     r0, 0xFFFFFFFF
.text:000010E8                 sr      r0, [0x23] # '#'
.text:000010EC                 sr      0, COUNT # '!' # Enhanced Timer 0  Timer 0 Count value
.text:000010F4                 sr      2, CONTROL # '"' # Enhanced Timer 0  Timer 0 Control value
.text:000010FC                 bl      Platform_Initialize
.text:00001100                 bl      Core_Loop
.text:00001104                 ld      blink, [fp,arg_4]

ARM Processor EPOC App

Assembler code

.text:8012235E                 MOVS    R4, R5
.text:80122360                 ADDS    R4, #0x4C ; 'L'
.text:80122362
.text:80122362 loc_80122362                            ; CODE XREF: sub_8012234E+C4↓j
.text:80122362                 LDR     R4, [R4,#4]
.text:80122364                 CMP     R4, #0
.text:80122366                 BNE     loc_8012236C
.text:80122368                 LDR     R4, [R5,#0x3C]
.text:8012236A                 B       loc_801223FA
.text:8012236C ; ---------------------------------------------------------------------------
.text:8012236C
.text:8012236C loc_8012236C                            ; CODE XREF: sub_8012234E+18↑j
.text:8012236C                 LDR     R0, [R5,#0x3C]
.text:8012236E                 CMP     R0, R4
.text:80122370                 BLS     loc_8012237C
.text:80122372                 LDR     R0, [R4,#4]
.text:80122374                 CMP     R0, #0
.text:80122376                 BEQ     loc_8012238E
.text:80122378                 CMP     R0, R4
.text:8012237A                 BHI     loc_8012238E
.text:8012237C
.text:8012237C loc_8012237C                            ; CODE XREF: sub_8012234E+22↑j
.text:8012237C                 LDR     R0, [SP,#0x28+var_24]
.text:8012237E                 BLX     arm_euser_eka2_1417
.text:80122382                 MOVS    R2, R4
.text:80122384                 MOVS    R1, #4
.text:80122386                 LDR     R0, [SP,#0x28+var_18]
.text:80122388                 LDR     R7, [SP,#0x28+var_1C]
.text:8012238A                 MOVS    R3, #0
.text:8012238C                 B       loc_801223F2
.text:8012238E ; ---------------------------------------------------------------------------
.text:8012238E
.text:8012238E loc_8012238E                            ; CODE XREF: sub_8012234E+28↑j
.text:8012238E                                         ; sub_8012234E+2C↑j
.text:8012238E                 LDR     R7, [R4]

ARM Processor EPOC PE File

Assembler code

.text:100097D8                 ADD     R4, R4, #0x38 ; '8'
.text:100097DC                 MOV     R2, #0x18
.text:100097E0                 MOV     R1, R4
.text:100097E4                 MOV     R0, R5
.text:100097E8                 BL      Copy__10TBufCBase8RC10TBufCBase8i ; TBufCBase8::Copy(TBufCBase8 const &,int)
.text:100097EC                 LDR     R3, [R4,#0x1C]
.text:100097F0                 STR     R3, [R5,#0x1C]
.text:100097F4                 LDR     R3, [R4,#0x20]
.text:100097F8                 STR     R3, [R5,#0x20]
.text:100097FC                 LDR     R3, [R4,#0x24]
.text:10009800                 STR     R3, [R5,#0x24]
.text:10009804                 ADD     LR, R7, #0x1540
.text:10009808                 ADD     LR, LR, #0x30 ; '0'
.text:1000980C                 ADD     R12, SP, #0x50+var_C
.text:10009810                 LDM     R12!, {R0-R3}
.text:10009814                 STM     LR!, {R0-R3}
.text:10009818                 MOV     R1, #4
.text:1000981C                 ADD     R0, R7, #0x18
.text:10009820                 BL      Connect__3RFsi  ; RFs::Connect(int)
.text:10009824                 BL      LeaveIfError__4Useri ; User::LeaveIfError(int)
.text:10009828                 BL      Static__7CCoeEnv ; CCoeEnv::Static(void)
.text:1000982C                 MOV     R1, R5
.text:10009830                 BL      CreateScreenFontL__7CCoeEnvRC9TFontSpec ; CCoeEnv::CreateScreenFontL(TFontSpec const &)
.text:10009834                 LDR     R3, =0x158C
.text:10009838                 STR     R0, [R7,R3]
.text:1000983C                 MOV     R1, #0
.text:10009840                 MOV     R0, #0x18
.text:10009844                 BL      __nw__5CBaseUi6TLeave ; CBase::__nw(uint,TLeave)
.text:10009848                 SUBS    R4, R0, #0
.text:1000984C                 BEQ     loc_1000986C
.text:10009850                 MOV     R3, #0xA
.text:10009854                 MOV     R2, #0x10
.text:10009858                 LDR     R1, =NewL__8CBufFlati ; CBufFlat::NewL(int)
.text:1000985C                 MOV     R0, R4
.text:10009860                 BL      __13CArrayFixBasePFi_P8CBufBaseii

ARM Processor EPOC ROMFile

Assembler code

.text:50292274                 B       sub_5029254C
.text:50292274 ; ---------------------------------------------------------------------------
.text:50292278 off_50292278    DCD start               ; DATA XREF: start+3C↑r
.text:5029227C ; ---------------------------------------------------------------------------
.text:5029227C                 MOV     R1, R0
.text:50292280                 LDR     R0, =start
.text:50292284                 B       sub_50292558
.text:50292284 ; ---------------------------------------------------------------------------
.text:50292288 off_50292288    DCD start               ; DATA XREF: start+4C↑r
.text:5029228C ; ---------------------------------------------------------------------------
.text:5029228C                 LDR     R0, =start
.text:50292290                 B       sub_50292564
.text:50292290 ; ---------------------------------------------------------------------------
.text:50292294 off_50292294    DCD start               ; DATA XREF: start+58↑r
.text:50292298 ; ---------------------------------------------------------------------------
.text:50292298                 LDR     R0, =start
.text:5029229C                 B       sub_50292570
.text:5029229C ; ---------------------------------------------------------------------------
.text:502922A0 off_502922A0    DCD start               ; DATA XREF: start+64↑r
.text:502922A4 ; ---------------------------------------------------------------------------
.text:502922A4                 LDR     R0, =start
.text:502922A8                 B       sub_5029257C
.text:502922A8 ; ---------------------------------------------------------------------------
.text:502922AC off_502922AC    DCD start               ; DATA XREF: start+70↑r
.text:502922B0 ; ---------------------------------------------------------------------------
.text:502922B0                 LDR     R0, =start
.text:502922B4                 B       sub_50292588
.text:502922B4 ; ---------------------------------------------------------------------------
.text:502922B8 off_502922B8    DCD start               ; DATA XREF: start+7C↑r
.text:502922BC ; ---------------------------------------------------------------------------
.text:502922BC                 MOV     R1, R0
.text:502922C0                 LDR     R0, =start
.text:502922C4                 B       sub_50292594
.text:502922C4 ; ---------------------------------------------------------------------------
.text:502922C8 off_502922C8    DCD start               ; DATA XREF: start+8C↑r

EPOC SIS File Handler

Assembler code

.text:100001CC                 BL      Open__5RFileR3RFsRC6TDesC8Ui ; RFile::Open(RFs &,TDesC8 const &,uint)
.text:100001D0                 CMP     R0, #0
.text:100001D4                 BEQ     loc_100001E8
.text:100001D8                 MOV     R0, R10
.text:100001DC                 BL      Close__11RHandleBase ; RHandleBase::Close(void)
.text:100001E0
.text:100001E0 loc_100001E0                            ; CODE XREF: sub_1000014C+6C↑j
.text:100001E0                                         ; sub_1000014C+F8↓j
.text:100001E0                 MOV     R0, #0xFFFFFFFF
.text:100001E4                 B       loc_100007C4
.text:100001E8 ; ---------------------------------------------------------------------------
.text:100001E8
.text:100001E8 loc_100001E8                            ; CODE XREF: sub_1000014C+88↑j
.text:100001E8                 ADD     R5, R10, #0xC
.text:100001EC                 ADD     R1, R10, #0x124
.text:100001F0                 MOV     R0, R5
.text:100001F4                 BL      Modified__C5RFileR5TTime ; RFile::Modified(TTime &)
.text:100001F8                 MOV     R3, #0x18
.text:100001FC                 STR     R3, [SP,#0x94+var_24]
.text:10000200                 ADD     R2, SP, #0x94+var_24
.text:10000204                 MOV     R1, #1
.text:10000208                 MOV     R0, R5
.text:1000020C                 BL      Seek__C5RFile5TSeekRi ; RFile::Seek(TSeek,int &)
.text:10000210                 ADD     R4, SP, #0x94+var_30
.text:10000214                 MOV     R3, #4
.text:10000218                 MOV     R2, R3
.text:1000021C                 ADD     R1, R10, #0x1C
.text:10000220                 MOV     R0, R4
.text:10000224                 BL      __5TPtr8PUcii
.text:10000228                 MOV     R1, R4
.text:1000022C                 MOV     R0, R5
.text:10000230                 BL      Read__C5RFileR5TDes8 ; RFile::Read(TDes8 &)
.text:10000234                 LDR     R0, [R10,#0x1C]
.text:10000238                 BL      __builtin_vec_new
.text:1000023C                 STR     R0, [R10,#0x20]

ARM Processor iOS (iPhone): Unlock

Assembler code

__text:00002914                 STR     R3, [SP,#0x14+var_8]
__text:00002918                 MOV     R3, #0
__text:0000291C                 STRB    R3, [SP,#0x14+var_1]
__text:00002920                 MOV     R0, #0xE
__text:00002924                 BL      __keymgr_get_and_lock_processwide_ptr
__text:00002928                 MOV     R3, R0
__text:0000292C                 STR     R3, [SP,#0x14+var_C]
__text:00002930                 LDR     R3, [SP,#0x14+var_C]
__text:00002934                 CMP     R3, #0
__text:00002938                 BEQ     loc_296C
__text:0000293C                 LDR     R3, [SP,#0x14+var_C]
__text:00002940                 LDRB    R3, [R3,#2]
__text:00002944                 STRB    R3, [SP,#0x14+var_1]
__text:00002948                 LDR     R2, [SP,#0x14+var_C]
__text:0000294C                 MOV     R3, #1
__text:00002950                 STRB    R3, [R2,#2]
__text:00002954                 LDR     R3, [SP,#0x14+var_C]
__text:00002958                 LDR     R3, [R3,#4]
__text:0000295C                 STR     R3, [SP,#0x14+var_8]
__text:00002960                 MOV     R0, #0xE
__text:00002964                 LDR     R1, [SP,#0x14+var_C]
__text:00002968                 BL      __keymgr_set_and_unlock_processwide_ptr
__text:0000296C
__text:0000296C loc_296C                                ; CODE XREF: sub_28F8+40↑j
__text:0000296C                 LDR     R3, [SP,#0x14+var_10]
__text:00002970                 LDR     R3, [R3,#4]
__text:00002974                 CMP     R3, #0
__text:00002978                 BEQ     loc_2998
__text:0000297C                 LDR     R3, [SP,#0x14+var_10]
__text:00002980                 LDR     R2, [R3]
__text:00002984                 LDR     R3, [SP,#0x14+var_10]
__text:00002988                 LDR     R3, [R3,#8]
__text:0000298C                 MOV     R0, R3
__text:00002990                 BLX     R2
__text:00002994                 B       loc_29A4

ARM Processor iOS (iPhone): Objective-C metadata

Assembler code

__text:0000309C
__text:0000309C ; =============== S U B R O U T I N E =======================================
__text:0000309C
__text:0000309C ; Attributes: bp-based frame
__text:0000309C
__text:0000309C ; void __cdecl -[SMSApplication showNextMessage](SMSApplication *self, SEL)
__text:0000309C __SMSApplication_showNextMessage_       ; DATA XREF: __objc_const:000101B8↓o
__text:0000309C                 PUSH            {R4-R7,LR}
__text:0000309E                 ADD             R7, SP, #0xC
__text:000030A0                 PUSH.W          {R8}
__text:000030A4                 SUB             SP, SP, #8
__text:000030A6                 MOV             R4, R0
__text:000030A8                 MOV             R0, #(selRef_sharedConversationList - 0x30BC)
__text:000030B0                 MOV             R2, #(classRef_CKConversationList - 0x30BE)
__text:000030B8                 ADD             R0, PC  ; selRef_sharedConversationList
__text:000030BA                 ADD             R2, PC  ; classRef_CKConversationList
__text:000030BC                 LDR             R1, [R0] ; "sharedConversationList"
__text:000030BE                 LDR             R0, [R2] ; _OBJC_CLASS_$_CKConversationList ; id
__text:000030C0                 BLX             _objc_msgSend
__text:000030C4                 MOV             R1, #(selRef_activeConversations - 0x30D0)
__text:000030CC                 ADD             R1, PC  ; selRef_activeConversations
__text:000030CE                 LDR             R1, [R1] ; "activeConversations"
__text:000030D0                 BLX             _objc_msgSend
__text:000030D4                 MOV             R5, #(dword_11F80 - 0x30E8)
__text:000030DC                 MOV             R1, #(selRef_objectAtIndex_ - 0x30EA)
__text:000030E4                 ADD             R5, PC  ; dword_11F80
__text:000030E6                 ADD             R1, PC  ; selRef_objectAtIndex_
__text:000030E8                 LDR             R2, [R5]
__text:000030EA                 LDR             R1, [R1] ; "objectAtIndex:"
__text:000030EC                 BLX             _objc_msgSend
__text:000030F0                 MOV             R6, R0
__text:000030F2                 MOV             R0, #(off_1011C - 0x30FE)
__text:000030FA                 ADD             R0, PC  ; off_1011C
__text:000030FC                 LDR.W           R8, [R0] ; CKMessagesController *_messagesController;
__text:00003100                 MOV             R0, #(selRef_currentConversation - 0x310C)

ARM Processor iOS (iPhone): Objective-C Instance variables

Assembler code

__objc_const:000106C0                 __objc2_meth <sel__clearFailureBadge, aV804, \ ; -[SMSApplication _clearFailureBadge] ...
__objc_const:000106C0                               __SMSApplication__clearFailureBadge_+1>
__objc_const:000106CC                 __objc2_meth <sel__mediaDidFinishSaving, aV804, \ ; -[SMSApplication _mediaDidFinishSaving] ...
__objc_const:000106CC                               __SMSApplication__mediaDidFinishSaving_+1>
__objc_const:000106D8                 __objc2_meth <sel__mediaDidStartSaving, aV804, \ ; -[SMSApplication _mediaDidStartSaving] ...
__objc_const:000106D8                               __SMSApplication__mediaDidStartSaving_+1>
__objc_const:000106E4 _OBJC_INSTANCE_VARIABLES_SMSApplication __objc2_ivar_list <0x14, 0xF>
__objc_const:000106E4                                         ; DATA XREF: __objc_const:SMSApplication_$classData↑o
__objc_const:000106EC                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._waitToSendFinishLaunching, \ ; char _waitToSendFinishLaunching;
__objc_const:000106EC                               aWaittosendfini, aC, 0, 1>
__objc_const:00010700                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._isLocked, aIslocked_0, aC, \ ; char _isLocked;
__objc_const:00010700                               0, 1>
__objc_const:00010714                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._isSuspended, aIssuspended, \ ; char _isSuspended;
__objc_const:00010714                               aC, 0, 1>
__objc_const:00010728                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._hasEmail, aHasemail, aC, 0,\ ; char _hasEmail;
__objc_const:00010728                               1>
__objc_const:0001073C                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._window, aWindow_0, \ ; UIWindow *_window;
__objc_const:0001073C                               aUiwindow, 2, 4>
__objc_const:00010750                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._messagesController, \ ; CKMessagesController *_messagesController;
__objc_const:00010750                               aMessagescontro, aCkmessagescont_7, 2, 4>
__objc_const:00010764                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._smsService, aSmsservice, \ ; CKService *_smsService;
__objc_const:00010764                               aCkservice, 2, 4>
__objc_const:00010778                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._madridService, \ ; CKService *_madridService;
__objc_const:00010778                               aMadridservice, aCkservice, 2, 4>
__objc_const:0001078C                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._delaySuspendCount, \ ; int _delaySuspendCount;
__objc_const:0001078C                               aDelaysuspendco, aI, 2, 4>
__objc_const:000107A0                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._backgroundTask, \ ; unsigned int _backgroundTask;
__objc_const:000107A0                               aBackgroundtask, aI_0, 2, 4>
__objc_const:000107B4                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._madridRegistrationController,\ ; CNFRegWizardController *_madridRegistrationController;
__objc_const:000107B4                               aMadridregistra_2, aCnfregwizardco, 2, 4>
__objc_const:000107C8                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._defaultPng, aDefaultpng_0, \ ; NSString *_defaultPng;
__objc_const:000107C8                               aNsstring, 2, 4>
__objc_const:000107DC                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._suspendTimeStatusBarStyle, \ ; int _suspendTimeStatusBarStyle;
__objc_const:000107DC                               aSuspendtimesta, aI, 2, 4>
__objc_const:000107F0                 __objc2_ivar <_OBJC_IVAR_$_SMSApplication._deferredLoadURL, \ ; NSURL *_deferredLoadURL;
__objc_const:000107F0                               aDeferredloadur_0, aNsurl, 2, 4>

ARM Processor iOS (iPhone): Parameter Identification & Tracking (PIT)

Assembler code


__text:00002CAC
__text:00002CAC ; =============== S U B R O U T I N E =======================================
__text:00002CAC
__text:00002CAC ; Attributes: bp-based frame
__text:00002CAC
__text:00002CAC sub_2CAC                                ; CODE XREF: sub_12FF8+18↓p
__text:00002CAC                 LDR     R0, =off_52014
__text:00002CB0                 PUSH    {R4,R7,LR}
__text:00002CB4                 MOV     R1, #0          ; __c
__text:00002CB8                 LDR     R4, =dword_52DBC
__text:00002CBC                 LDR     R3, =unk_52DC4
__text:00002CC0                 ADD     R7, SP, #4
__text:00002CC4                 MOV     R2, #0xE7 ; 'ç' ; __len
__text:00002CC8                 LDR     R0, [R0]        ; unk_53620 ; __b
__text:00002CCC                 STR     R3, [R4]
__text:00002CD0                 BL      _memset
__text:00002CD4                 LDR     R3, =off_52018
__text:00002CD8                 MOV     R1, #0
__text:00002CDC                 LDR     R2, [R3]        ; byte_53610
__text:00002CE0                 MOV     R3, R2
__text:00002CE4                 STRB    R1, [R2,#(byte_53611 - 0x53610)]
__text:00002CE8                 STRB    R1, [R3],#1
__text:00002CEC                 LDR     R2, [R4]
__text:00002CF0                 ADD     R3, R3, #1
__text:00002CF4                 ADD     R0, R2, #0x84 ; '„'
__text:00002CF8                 STRB    R1, [R3],#1
__text:00002CFC                 STRB    R1, [R3],#1
__text:00002D00                 STRB    R1, [R3],#1
__text:00002D04                 STRB    R1, [R3],#1
__text:00002D08                 STRB    R1, [R3]
__text:00002D0C                 MOV     R3, R2
__text:00002D10
__text:00002D10 loc_2D10                                ; CODE XREF: sub_2CAC+70↓j
__text:00002D10                 STR     R1, [R3,#8]
__text:00002D14                 ADD     R3, R3, #4

ARM Processor iOS (iPhone): Start

Assembler code

__text:00002274
__text:00002274 ; =============== S U B R O U T I N E =======================================
__text:00002274
__text:00002274 ; Attributes: noreturn bp-based frame
__text:00002274
__text:00002274 sub_2274                                ; CODE XREF: start+14↑p
__text:00002274
__text:00002274 var_10          = -0x10
__text:00002274
__text:00002274                 PUSH    {R4-R7,LR}
__text:00002278                 ADD     R7, SP, #0xC
__text:0000227C                 SUB     SP, SP, #4
__text:00002280                 MOV     R6, R0
__text:00002284                 MOV     R5, R1
__text:00002288                 MOV     R4, R2
__text:0000228C                 LDR     R3, =(_NXArgc - 0x2298)
__text:00002290                 STR     R0, [PC,R3]     ; _NXArgc
__text:00002294                 LDR     R3, =(_NXArgv - 0x22A0)
__text:00002298                 STR     R1, [PC,R3]     ; _NXArgv
__text:0000229C                 LDR     R3, =(_environ - 0x22A8)
__text:000022A0                 STR     R2, [PC,R3]     ; _environ
__text:000022A4                 LDR     R3, =(_mach_init_routine_ptr - 0x22B0)
__text:000022A8                 LDR     R3, [PC,R3]     ; _mach_init_routine
__text:000022AC                 LDR     R3, [R3]
__text:000022B0                 CMP     R3, #0
__text:000022B4                 BLXNE   R3
__text:000022B8                 LDR     R3, =(__cthread_init_routine_ptr - 0x22C4)
__text:000022BC                 LDR     R3, [PC,R3]     ; __cthread_init_routine
__text:000022C0                 LDR     R3, [R3]
__text:000022C4                 CMP     R3, #0
__text:000022C8                 BLXNE   R3
__text:000022CC                 BL      ___keymgr_dwarf2_register_sections
__text:000022D0                 BL      sub_23C4
__text:000022D4                 LDR     R0, =(aDyldModTermFun - 0x22E0) ; "__dyld_mod_term_funcs"
__text:000022D8                 ADD     R0, PC, R0      ; "__dyld_mod_term_funcs"

ARM Processor iOS (iPhone): Switch statements

Assembler code

__text:00003B48                 STR     R3, [R4,#0xE8]
__text:00003B4C                 LDR     R3, [R4,#0x38]
__text:00003B50                 CMP     R3, #0x27       ; switch 40 cases
__text:00003B54                 LDRLS   PC, [PC,R3,LSL#2] ; switch jump
__text:00003B58                 B       def_3B54        ; jumptable 00003B54 default case, cases 2-6,8,11,12,15,16,20-22,27,32-38
__text:00003B58 ; ---------------------------------------------------------------------------
__text:00003B5C jpt_3B54        DCD loc_3C0C            ; jump table for switch statement
__text:00003B5C                 DCD loc_3C0C
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3C1C
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3C1C
__text:00003B5C                 DCD loc_3BFC
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3C24
__text:00003B5C                 DCD loc_3C2C
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3C14
__text:00003B5C                 DCD loc_3C2C
__text:00003B5C                 DCD loc_3C34
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3C14
__text:00003B5C                 DCD loc_3C2C
__text:00003B5C                 DCD loc_3C2C
__text:00003B5C                 DCD loc_3C2C
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3C3C
__text:00003B5C                 DCD loc_3C34
__text:00003B5C                 DCD loc_3C34
__text:00003B5C                 DCD loc_3C34
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD def_3B54
__text:00003B5C                 DCD loc_3BFC

ARM Processor iOS (iPhone): C++ signatures

Assembler code

__text:00015E90                 BL      _readdir
__text:00015E94                 SUBS    R1, R0, #0
__text:00015E98                 BEQ     loc_15F2C
__text:00015E9C                 MOV     R3, #2
__text:00015EA0                 LDRB    R2, [R1,#7]
__text:00015EA4                 ADD     R0, SP, #0xA8+var_64
__text:00015EA8                 STR     R3, [SP,#0xA8+fctx.call_site]
__text:00015EAC                 ADD     R1, R1, #8
__text:00015EB0                 ADD     R3, SP, #0xA8+var_5D
__text:00015EB4                 BL      __ZNSsC1EPKcmRKSaIcE ; std::string::string(char const*,ulong,std::allocator<char> const&)
__text:00015EB8                 MOV     R3, #1
__text:00015EBC                 STR     R3, [SP,#0xA8+fctx.call_site]
__text:00015EC0                 ADD     R0, SP, #0xA8+var_64
__text:00015EC4                 LDR     R3, [SP,#0xA8+var_A4]
__text:00015EC8                 BLX     R3
__text:00015ECC                 CMP     R0, #0
__text:00015ED0                 BNE     loc_15F1C
__text:00015ED4                 MOV     R3, #0xFFFFFFFF
__text:00015ED8                 ADD     R0, SP, #0xA8+var_64 ; this
__text:00015EDC                 STR     R3, [SP,#0xA8+fctx.call_site]
__text:00015EE0                 BL      __ZNSsD2Ev      ; std::string::~string()
__text:00015EE4                 B       loc_15E84
__text:00015EE8 ; ---------------------------------------------------------------------------
__text:00015EE8 ;   cleanup() // owned by 15E64
__text:00015EE8                 LDR     R3, [SP,#0xA8+fctx.data]
__text:00015EEC                 STR     R3, [SP,#0xA8+lpuexcpt]
__text:00015EF0                 LDR     R3, [SP,#0xA8+fctx.call_site]
__text:00015EF4                 CMP     R3, #1
__text:00015EF8                 BEQ     loc_15F0C
__text:00015EFC                 MOV     R3, #0
__text:00015F00                 ADD     R0, SP, #0xA8+var_64 ; this
__text:00015F04                 STR     R3, [SP,#0xA8+fctx.call_site]
__text:00015F08                 BL      __ZNSsD2Ev      ; std::string::~string()
__text:00015F0C
__text:00015F0C loc_15F0C                               ; CODE XREF: sub_15E1C+DC↑j
__text:00015F0C                 MOV     R3, #0xFFFFFFFF

ARM Processor iOS (iPhone): Write

Assembler code

__text:00004424                 BHI     loc_440C
__text:00004428
__text:00004428 loc_4428                                ; CODE XREF: sub_43CC+24↑j
__text:00004428                                         ; sub_43CC+3C↑j
__text:00004428                 LDR     R3, =___stderrp_ptr
__text:0000442C                 LDR     R0, =aSynchronized ; "synchronized\n"
__text:00004430                 MOV     R1, #1          ; __size
__text:00004434                 LDR     R3, [R3]        ; ___stderrp
__text:00004438                 MOV     R2, #0xD        ; __nitems
__text:0000443C                 LDR     R3, [R3]        ; __stream
__text:00004440                 BL      _fwrite
__text:00004444                 MOV     R3, #0x12
__text:00004448
__text:00004448 loc_4448                                ; CODE XREF: sub_43CC+34↑j
__text:00004448                                         ; sub_43CC+4C↑j
__text:00004448                 STR     R3, [R4,#0x38]
__text:0000444C                 LDR     R3, [R4,#0xE4]
__text:00004450                 STR     R3, [R4,#0xE0]
__text:00004454                 MOV     R3, #9
__text:00004458                 STR     R3, [R4,#0xE4]
__text:0000445C                 LDR     R3, [R4,#0xEC]
__text:00004460                 STR     R3, [R4,#0xE8]
__text:00004464                 MOV     R3, #0
__text:00004468                 STR     R3, [R4,#0xEC]
__text:0000446C                 POP     {R4,R7,PC}
__text:0000446C ; End of function sub_43CC
__text:0000446C
__text:0000446C ; ---------------------------------------------------------------------------
__text:00004470 off_4470        DCD dword_52E70         ; DATA XREF: sub_43CC↑r
__text:00004474 off_4474        DCD ___stderrp_ptr      ; DATA XREF: sub_43CC:loc_4428↑r
__text:00004478 ; void *const _ptr
__text:00004478 __ptr           DCD aSynchronized       ; DATA XREF: sub_43CC+60↑r
__text:00004478                                         ; "synchronized\n"
__text:0000447C
__text:0000447C ; =============== S U B R O U T I N E =======================================
__text:0000447C
__text:0000447C
__text:0000447C sub_447C                                ; DATA XREF: sub_4820+47C↓o
__text:0000447C                                         ; __text:off_50A8↓o
__text:0000447C                 UXTB    R0, R0

ARM Processor: Linux ELF

Assembler code

.text:0000107E                 VLDR            D0, [SP,#0x5E8+var_450]
.text:00001082                 VMOV            R2, R3, D0
.text:00001086                 VLDR            D0, [SP,#0x5E8+var_448]
.text:0000108A                 VMOV            R0, R1, D0
.text:0000108E                 BL              __aeabi_ddiv
.text:00001092                 VMOV            D0, R0, R1
.text:00001096                 VSTR            D0, [SP,#0x5E8+var_440]
.text:0000109A                 VLDR            D0, [SP,#0x5E8+var_440]
.text:0000109E                 VMOV            R0, R1, D0
.text:000010A2                 BL              __aeabi_d2f
.text:000010A6                 LDR             R1, =Usart1_out_DATA
.text:000010A8                 STR             R0, [R1,#0x7C] ; `vtable for'__cxxabiv1::__si_class_type_info
.text:000010AA                 LDR.W           R0, [SP,#0x5E8+var_18]
.text:000010AE                 ADDW            R0, R0, #0xCC8
.text:000010B2                 ADD.W           R0, R0, #0x400
.text:000010B6                 VLDR            D0, [R0,#0x300]
.text:000010BA                 VSTR            D0, [SP,#0x5E8+var_450]
.text:000010BE                 VLDR            D0, [SP,#0x5E8+var_450]
.text:000010C2                 BL              __hardfp_sqrt
.text:000010C6                 VSTR            D0, [SP,#0x5E8+var_448]
.text:000010CA                 LDR             R0, =glv
.text:000010CC                 VLDR            D0, [R0,#0x48]
.text:000010D0                 VSTR            D0, [SP,#0x5E8+var_450]
.text:000010D4                 VLDR            D0, [SP,#0x5E8+var_450]
.text:000010D8                 VMOV            R2, R3, D0
.text:000010DC                 VLDR            D0, [SP,#0x5E8+var_448]
.text:000010E0                 VMOV            R0, R1, D0
.text:000010E4                 BL              __aeabi_ddiv
.text:000010E8                 VMOV            D0, R0, R1
.text:000010EC                 VSTR            D0, [SP,#0x5E8+var_440]
.text:000010F0                 VLDR            D0, [SP,#0x5E8+var_440]
.text:000010F4                 VMOV            R0, R1, D0
.text:000010F8                 BL              __aeabi_d2f
.text:000010FC                 LDR             R1, =Usart1_out_DATA
.text:000010FE                 STR.W           R0, [R1,#0x80]

ARM Processor: AOF SDK

Assembler code

C$$code:00000024                 ADD             R0, R0, #1
C$$code:00000028                 CMP             R0, #0xC8 ; 'È'
C$$code:0000002C                 BLT             loc_20
C$$code:00000030                 ADD             R1, R1, #1
C$$code:00000034                 CMP             R1, #0x12C
C$$code:00000038                 BLT             loc_10
C$$code:0000003C                 MOV             R3, #1
C$$code:00000040
C$$code:00000040 loc_40                                  ; CODE XREF: x$litpool$0+90↓j
C$$code:00000040                 MOV             R1, #0
C$$code:00000044
C$$code:00000044 loc_44                                  ; CODE XREF: x$litpool$0+84↓j
C$$code:00000044                 ADD             R12, R1, R1,LSL#3
C$$code:00000048                 ADD             R12, R12, R1,LSL#4
C$$code:0000004C                 ADD             R12, R2, R12,LSL#5
C$$code:00000050                 MOV             R0, #0
C$$code:00000054
C$$code:00000054 loc_54                                  ; CODE XREF: x$litpool$0+78↓j
C$$code:00000054                 LDR             LR, [R12,R0,LSL#2]
C$$code:00000058                 MUL             LR, R3, LR
C$$code:0000005C                 STR             LR, [R12,R0,LSL#2]
C$$code:00000060                 ADD             LR, R12, R0,LSL#2
C$$code:00000064                 LDR             LR, [LR,#0x10]
C$$code:00000068                 MUL             LR, R3, LR
C$$code:0000006C                 STR             LR, [R12,R0,LSL#2]
C$$code:00000070                 ADD             R0, R0, #5
C$$code:00000074                 CMP             R0, #0xC3 ; 'Ã'
C$$code:00000078                 BLT             loc_54
C$$code:0000007C                 ADD             R1, R1, #1
C$$code:00000080                 CMP             R1, #0x12C
C$$code:00000084                 BLT             loc_44
C$$code:00000088                 ADD             R3, R3, #1
C$$code:0000008C                 CMP             R3, #0x32 ; '2'
C$$code:00000090                 BLT             loc_40
C$$code:00000094                 MOV             R0, #0

ARM Processor: Windows CE COFF Format

Assembler code

.text:00000078                 MOVS            R3, R0
.text:0000007C                 BNE             loc_58
.text:00000080                 MOV             R0, #0x200
.text:00000084                 ADD             R0, SP, R0
.text:00000088                 BL              OutputDebugStringW
.text:0000008C                 CMP             R6, #0
.text:00000090                 MOV             R0, R6
.text:00000094                 MOVLE           R0, #0
.text:00000098                 ADD             SP, SP, #0x600
.text:0000009C                 LDMFD           SP, {R4-R6,SP,PC}
.text:0000009C ; ---------------------------------------------------------------------------
.text:000000A0 off_A0          DCD __imp_vsprintf      ; DATA XREF: DbgPrint:$M4755↑r
.text:000000A0 ; End of function DbgPrint
.text:000000A0
.text:000000A0 ; .text         ends
.text:000000A0
.pdata:000000A4 ; ===========================================================================
.pdata:000000A4
.pdata:000000A4 ; Segment type: Pure data
.pdata:000000A4                 AREA .pdata, DATA, READONLY
.pdata:000000A4                 ; ORG 0xA4
.pdata:000000A4 ; COMDAT (pick associative to section at 10)
.pdata:000000A4 $T4757          DCD DbgPrint            ; Function start
.pdata:000000A8                 DCD 0x40002504          ; Function end: A4, prolog end: 20, 32-bit: 1, has EH: 0
.pdata:000000A8 ; .pdata        ends
.pdata:000000A8
UNDEF:000000B0 ; ===========================================================================
UNDEF:000000B0
UNDEF:000000B0 ; Segment type: Externs
UNDEF:000000B0                 IMPORT OutputDebugStringW
UNDEF:000000B0                                         ; CODE XREF: DbgPrint+78↑p
UNDEF:000000B4                 IMPORT __imp_vsprintf   ; DATA XREF: DbgPrint:$M4755↑o
UNDEF:000000B4                                         ; DbgPrint:off_A0↑o
UNDEF:000000B4
UNDEF:000000B4                 END

ARM Processor: Windows CE PE Format

Assembler code

.text:1001577C
.text:1001577C ; =============== S U B R O U T I N E =======================================
.text:1001577C
.text:1001577C
.text:1001577C ; BOOL __stdcall DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
.text:1001577C                 EXPORT DllEntryPoint
.text:1001577C DllEntryPoint                           ; DATA XREF: .pdata:1001BB70↓o
.text:1001577C                 PUSH    {R4-R8,LR}
.text:10015780                 MOV     R7, R2
.text:10015784                 MOV     R6, R1
.text:10015788                 MOV     R8, R0
.text:1001578C                 LDR     R5, =dword_1001AD20
.text:10015790                 CMP     R6, #1
.text:10015794                 BNE     loc_100157BC
.text:10015798                 LDR     R3, [R5]
.text:1001579C                 CMP     R3, #0
.text:100157A0                 BEQ     loc_100157B8
.text:100157A4                 MOV     R1, #1
.text:100157A8                 MOV     LR, PC
.text:100157AC                 BX      R3
.text:100157B0                 MOVS    R4, R0
.text:100157B4                 BEQ     loc_10015804
.text:100157B8
.text:100157B8 loc_100157B8                            ; CODE XREF: DllEntryPoint+24↑j
.text:100157B8                 BL      sub_100155D8
.text:100157BC
.text:100157BC loc_100157BC                            ; CODE XREF: DllEntryPoint+18↑j
.text:100157BC                 MOV     R2, R7
.text:100157C0                 MOV     R1, R6
.text:100157C4                 MOV     R0, R8
.text:100157C8                 BL      sub_10003C18
.text:100157CC                 MOV     R4, R0
.text:100157D0                 CMP     R6, #0
.text:100157D4                 BNE     loc_10015804
.text:100157D8                 BL      sub_10015760

ATMEL AVR Disassembler

Assembler code

.text:0000003B
.text:0000003B ; =============== S U B R O U T I N E =======================================
.text:0000003B
.text:0000003B
.text:0000003B                 ; public qsort
.text:0000003B qsort:                                  ; CODE XREF: sub_41+1DE↓p
.text:0000003B                 ldi     r26, 0xA
.text:0000003C                 ldi     r27, 0
.text:0000003D                 ldi     r30, (sub_41 & 0xFF)
.text:0000003E                 ldi     r31, (sub_41 >> 8)
.text:0000003F                 jmp     __prologue_saves__
.text:0000003F ; End of function qsort
.text:0000003F
.text:00000041
.text:00000041 ; =============== S U B R O U T I N E =======================================
.text:00000041
.text:00000041
.text:00000041 sub_41:                                 ; DATA XREF: qsort+2↑o
.text:00000041                                         ; qsort+3↑o
.text:00000041                 movw    r4, r24
.text:00000042                 movw    r8, r22
.text:00000043                 movw    r6, r20
.text:00000044                 movw    r2, r18
.text:00000045                 std     Y+5, r20
.text:00000046                 std     Y+6, r7
.text:00000047                 clr     r18
.text:00000048                 clr     r19
.text:00000049                 sub     r18, r20
.text:0000004A                 sbc     r19, r21
.text:0000004B                 std     Y+8, r19
.text:0000004C                 std     Y+7, r18
.text:0000004D
.text:0000004D loc_4D:                                 ; CODE XREF: sub_41+1EB↓j
.text:0000004D                 ldi     r19, 7
.text:0000004E                 cp      r8, r19

C166 Processor

Assembler code

ROM:00005920
ROM:00005920 ; =============== S U B R O U T I N E =======================================
ROM:00005920
ROM:00005920
ROM:00005920 sub_5920:                               ; CODE XREF: ROM:00005A1A↓P
ROM:00005920                                         ; ROM:00005ADC↓P
ROM:00005920                 mov     r4, r8
ROM:00005922                 cmpb    rl4, #0
ROM:00005924                 jmpr    cc_NZ, loc_5932
ROM:00005926                 mov     r5, #4
ROM:00005928                 or      dword_18+4, ZEROS
ROM:0000592C                 or      dword_18+6, r5
ROM:00005930                 jmpr    cc_UC, loc_593E
ROM:00005932 ; ---------------------------------------------------------------------------
ROM:00005932
ROM:00005932 loc_5932:                               ; CODE XREF: sub_5920+4↑j
ROM:00005932                 mov     r5, #0FFFBh
ROM:00005936                 and     dword_18+4, ONES
ROM:0000593A                 and     dword_18+6, r5
ROM:0000593E
ROM:0000593E loc_593E:                               ; CODE XREF: sub_5920+10↑j
ROM:0000593E                 mov     r4, r9
ROM:00005940                 cmpb    rl4, #0
ROM:00005942                 jmpr    cc_NZ, loc_5950
ROM:00005944                 mov     r5, #8
ROM:00005946                 or      dword_18+4, ZEROS
ROM:0000594A                 or      dword_18+6, r5
ROM:0000594E                 jmpr    cc_UC, loc_595C
ROM:00005950 ; ---------------------------------------------------------------------------
ROM:00005950
ROM:00005950 loc_5950:                               ; CODE XREF: sub_5920+22↑j
ROM:00005950                 mov     r5, #0FFF7h
ROM:00005954                 and     dword_18+4, ONES
ROM:00005958                 and     dword_18+6, r5
ROM:0000595C
ROM:0000595C loc_595C:                               ; CODE XREF: sub_5920+2E↑j
ROM:0000595C                 mov     r4, dword_18+4

C166 Processor with ELF file

Assembler code

code_libc:00C00D9C ; ===========================================================================
code_libc:00C00D9C
code_libc:00C00D9C ; Segment type: Pure code
code_libc:00C00D9C code_libc       section CODE word public
code_libc:00C00D9C proccode_libc proc
code_libc:00C00D9C                 ; assume dpp0: 1 (page 0x4000)
code_libc:00C00D9C                 ; assume dpp1: 1 (page 0x4000)
code_libc:00C00D9C                 ; assume dpp2: 2 (page 0x8000)
code_libc:00C00D9C                 ; assume dpp3: 3 (page 0xC000)
code_libc:00C00D9C
code_libc:00C00D9C ; =============== S U B R O U T I N E =======================================
code_libc:00C00D9C
code_libc:00C00D9C
code_libc:00C00D9C _$cocofun_7:                            ; CODE XREF: _$cocofun_2+A↓J
code_libc:00C00D9C                                         ; _$cocofun_6_0+6↓J
code_libc:00C00D9C                 mov     r4, r0
code_libc:00C00D9E                 calls   0C0h, __emitchar
code_libc:00C00DA2                 mov     r11, #0
code_libc:00C00DA4                 cmp     r11, r8
code_libc:00C00DA6                 subc    r8, #0
code_libc:00C00DA8                 rets
code_libc:00C00DA8 ; End of function _$cocofun_7
code_libc:00C00DA8
code_libc:00C00DA8 proccode_libc endp
code_libc:00C00DA8 code_libc       ends
code_libc:00C00DA8
code_libc:00C00DAA ; ===========================================================================
code_libc:00C00DAA
code_libc:00C00DAA ; Segment type: Pure code
code_libc:00C00DAA code_libc       section CODE word public
code_libc:00C00DAA proccode_libc proc
code_libc:00C00DAA                 ; assume dpp0: 1 (page 0x4000)
code_libc:00C00DAA                 ; assume dpp1: 1 (page 0x4000)
code_libc:00C00DAA                 ; assume dpp2: 2 (page 0x8000)
code_libc:00C00DAA                 ; assume dpp3: 3 (page 0xC000)
code_libc:00C00DAA
code_libc:00C00DAA ; =============== S U B R O U T I N E =======================================
code_libc:00C00DAA
code_libc:00C00DAA
code_libc:00C00DAA _$cocofun_2:                            ; CODE XREF: code_libc:00C0050C↑P
code_libc:00C00DAA                                         ; code_libc:00C0055C↑P
code_libc:00C00DAA                 calls   0C0h, _$cocofun_6_0

Rockwell C39

Assembler code

ROM:E520
ROM:E520 ; =============== S U B R O U T I N E =======================================
ROM:E520
ROM:E520
ROM:E520 sub_E520:                               ; CODE XREF: JSB0__0+9↓j
ROM:E520                                         ; sub_E581↓p ...
ROM:E520                 STI     #0x70, 0x0018 ; 'p' ; Bank switch register 0000-1FFF (R/W)
ROM:E523                 STI     #0x71, 0x0019 ; 'q' ; Bank switch register 2000-3FFF (R/W)
ROM:E526                 STI     #0x72, 0x001A ; 'r' ; Bank switch register 4000-5FFF (R/W)
ROM:E529                 STI     #0x73, 0x001B ; 's' ; Bank switch register 6000-7FFF (R/W)
ROM:E52C                 RTS
ROM:E52C ; End of function sub_E520
ROM:E52C
ROM:E52D
ROM:E52D ; =============== S U B R O U T I N E =======================================
ROM:E52D
ROM:E52D
ROM:E52D sub_E52D:                               ; CODE XREF: sub_E5B8↓p
ROM:E52D                 STI     #0x74, 0x0018 ; 't' ; Bank switch register 0000-1FFF (R/W)
ROM:E530                 STI     #0x75, 0x0019 ; 'u' ; Bank switch register 2000-3FFF (R/W)
ROM:E533                 STI     #0x76, 0x001A ; 'v' ; Bank switch register 4000-5FFF (R/W)
ROM:E536                 RTS
ROM:E536 ; End of function sub_E52D
ROM:E536
ROM:E537
ROM:E537 ; =============== S U B R O U T I N E =======================================
ROM:E537
ROM:E537
ROM:E537 sub_E537:                               ; CODE XREF: sub_E5EF↓p
ROM:E537                 STI     #0x78, 0x0018 ; 'x' ; Bank switch register 0000-1FFF (R/W)
ROM:E53A                 STI     #0x79, 0x0019 ; 'y' ; Bank switch register 2000-3FFF (R/W)
ROM:E53D                 STI     #0x7A, 0x001A ; 'z' ; Bank switch register 4000-5FFF (R/W)
ROM:E540                 STI     #0x7B, 0x001B ; '{' ; Bank switch register 6000-7FFF (R/W)
ROM:E543                 RTS
ROM:E543 ; End of function sub_E537
ROM:E543

Microsoft .NET CLI Disassembler. VisualBasic library

Assembler code

conv.i8
    mul.ovf
    stloc.0
    ldarg.0
    ldfld    class [mscorlib]System.IO.FileStream Microsoft.VisualBasic.CompilerServices.VB6File::m_file
    ldloc.1
    ldloc.0
    callvirt instance void [mscorlib]System.IO.FileStream::Lock(int64, int64)
    ret
  }

  .method public hidebysig virtual instance void Unlock(int64 lStart, int64 lEnd)
  {
    .maxstack 3
    .locals init (int64 V0,
                  int64 V1)
    ldarg.1
    ldarg.2
    ble.s    loc_439
    ldstr    aArgumentInvali            // "Argument_InvalidValue1"
    ldstr    aStart                     // "Start"
    call     string Microsoft.VisualBasic.CompilerServices.Utils::GetResourceString(string ResourceKey, string Parm1)
    newobj   instance void [mscorlib]System.ArgumentException::.ctor(string)
    throw

loc_439:                                // CODE XREF: Microsoft.VisualBasic.CompilerServices.VB6RandomFile__Unlock+2↑j
    ldarg.1
    ldc.i8   1
    sub.ovf
    ldarg.0
    ldfld    int32 Microsoft.VisualBasic.CompilerServices.VB6File::m_lRecordLen
    conv.i8
    mul.ovf
    stloc.1
    ldarg.2

CR16

Assembler code

ROM:4B66                 .byte 0xCE ; Î
ROM:4B67                 .byte 0x15
ROM:4B68                 .byte 0xFE ; þ
ROM:4B69                 .byte 0x2E ; .
ROM:4B6A ; ---------------------------------------------------------------------------
ROM:4B6A                 bal     r6, sub_E8BA
ROM:4B6E                 movw    $0xEE36, r7
ROM:4B72                 movw    $0x25A8, r8
ROM:4B76                 movw    $0xEE4F, r9
ROM:4B7A                 movw    $0xEE4A, r10
ROM:4B7E                 movw    $0xEE4C, r11
ROM:4B82                 movw    $0xEE4D, r12
ROM:4B86                 movw    $0xEE4E, r13
ROM:4B8A                 loadb   0x00(r2), r0
ROM:4B8C                 cmpb    $0xFF98, r0
ROM:4B90                 bne     loc_4B98
ROM:4B92                 loadb   byte_EE49, r0
ROM:4B96                 storb   r0, 0x00(r2)
ROM:4B98
ROM:4B98 loc_4B98:                               ; CODE XREF: ROM:4B90↑j
ROM:4B98                 loadb   0x00(r2), r6
ROM:4B9A                 bal     r0, sub_E68A
ROM:4B9E                 addb    $-0x10, r0
ROM:4BA0                 mulw    $0x0B, r3
ROM:4BA2                 loadw   0x0002(r2), r4
ROM:4BA4                 loadb   0x04(r3), r9
ROM:4BA6                 mulw    $0xF2, r7
ROM:4BA8                 addb    $0x07, r4
ROM:4BAA                 loadb   0x09(r3), r1
ROM:4BAC                 mulw    $0x0F, r8
ROM:4BAE                 orw     $0x09, r4
ROM:4BB0                 loadb   0x0B(r3), r1
ROM:4BB2                 mulw    $0x04, r10
ROM:4BB4                 adduw   r5, r12
ROM:4BB6                 loadb   0x0D(r3), r1

Android Dalvik Executables (.dex)

Assembler code

CODE:000065D0 # Source file: AlarmReceiver.java
CODE:000065D0 public void com.android.alarmclock.AlarmReceiver.onReceive(
CODE:000065D0       android.content.Context p0,
CODE:000065D0       android.content.Intent p1)
CODE:000065D0 this = v11
CODE:000065D0 p0 = v12
CODE:000065D0 p1 = v13
CODE:000065D0                 const/4                         v2, -1
CODE:000065D2                 const/4                         v8, 0
CODE:000065D4                 const-class                     v10, <t: AlarmAlert>
CODE:000065D8                 const-string                    v9, aIntentExtraAla # "intent.extra.alarm"
CODE:000065DC                 .prologue_end
CODE:000065DC                 .line 45
CODE:000065DC                 const-string                    v0, aAlarmKilled # "alarm_killed"
CODE:000065E0                 +invoke-virtual-quick           {p1}, [0x12]
CODE:000065E6                 move-result-object              v1
CODE:000065E8                 +execute-inline                 {v0, v1}, [3]
CODE:000065EE                 move-result                     v0
CODE:000065F0                 if-eqz                          v0, loc_6618
CODE:000065F4                 const-string                    v0, aIntentExtraAla # "intent.extra.alarm"
CODE:000065F8                 +invoke-virtual-quick           {p1, v9}, [0x32]
CODE:000065FE                 move-result-object              v0
CODE:00006600                 check-cast                      v0, <t: Alarm>
CODE:00006604                 const-string                    v1, aAlarmKilledTim # "alarm_killed_timeout"
CODE:00006608                 +invoke-virtual-quick           {p1, v1, v2}, [0x2B]
CODE:0000660E                 move-result                     v1
CODE:00006610                 invoke-direct                   {this, p0, v0, v1}, <void AlarmReceiver.updateNotification(ref, ref, int) AlarmReceiver_updateNotification@VLLI>
CODE:00006616
CODE:00006616 locret:                                 # CODE XREF: AlarmReceiver_onReceive@VLL+6A↓j
CODE:00006616                                         # AlarmReceiver_onReceive@VLL+B4↓j ...
CODE:00006616                 .line 154
CODE:00006616                 return-void
CODE:00006618 # ---------------------------------------------------------------------------
CODE:00006618
CODE:00006618 loc_6618:                               # CODE XREF: AlarmReceiver_onReceive@VLL+20↑j
CODE:00006618                 .line 51
CODE:00006618                 const-string                    v0, aCancelSnooze # "cancel_snooze"

Microsoft .NET CLI Disassembler

The IDA disassembler can disassemble a portable executable (PE) file that contains Microsoft intermediate language (MSIL) code. The Common Language Infrastructure (CLI) is the ECMA standard that describes the core of the .NET Framework world.

Assembler code

.method private hidebysig instance void UpdateDocumentRelatedTools()
                                        // CODE XREF: Infragistics.Win.Printing.UltraPrintPreviewDialog__UltraPrintPreviewDialog_Load+F6↑p
                                        // Infragistics.Win.Printing.UltraPrintPreviewDialog__ultraPrintPreviewControl1_PropertyChanged+43↑p
  {
    .maxstack 2
    .locals init (bool V0,
                  bool V1)
    ldarg.0
    ldfld    class [Infragistics2.Win.Misc.v10.1]Infragistics.Win.Printing.UltraPrintPreviewControl Infragistics.Win.Printing.UltraPrintPreviewDialog::ultraPrintPreviewControl1
    callvirt instance class [System.Drawing]System.Drawing.Printing.PrintDocument [Infragistics2.Win.Misc.v10.1]Infragistics.Win.Printing.UltraPrintPreviewControl::get_Document()
    ldnull
    ceq
    ldc.i4.0
    ceq
    stloc.0
    ldloc.0
    brfalse.s loc_588C
    ldarg.0
    ldfld    class [Infragistics2.Win.Misc.v10.1]Infragistics.Win.Printing.UltraPrintPreviewControl Infragistics.Win.Printing.UltraPrintPreviewDialog::ultraPrintPreviewControl1
    callvirt instance class [System.Drawing]System.Drawing.Printing.PrintDocument [Infragistics2.Win.Misc.v10.1]Infragistics.Win.Printing.UltraPrintPreviewControl::get_Document()
    callvirt instance class [System.Drawing]System.Drawing.Printing.PrinterSettings [System.Drawing]System.Drawing.Printing.PrintDocument::get_PrinterSettings()
    callvirt instance bool [System.Drawing]System.Drawing.Printing.PrinterSettings::get_IsValid()
    br.s     loc_588D

loc_588C:                               // CODE XREF: Infragistics.Win.Printing.UltraPrintPreviewDialog__UpdateDocumentRelatedTools+13↑j
    ldc.i4.0

loc_588D:                               // CODE XREF: Infragistics.Win.Printing.UltraPrintPreviewDialog__UpdateDocumentRelatedTools+2A↑j
    stloc.1
    ldarg.0
    ldfld    class [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.UltraToolbarsManager Infragistics.Win.Printing.UltraPrintPreviewDialog::ultraToolbarsManager1
    callvirt instance class [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.RootToolsCollection [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.UltraToolbarsManager::get_Tools()
    ldstr    aPrint                     // "Print"
    callvirt instance class [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.ToolBase [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.ToolsCollectionBase::get_Item(string)
    callvirt instance class [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.SharedProps [Infragistics2.Win.UltraWinToolbars.v10.1]Infragistics.Win.UltraWinToolbars.ToolBase::get_SharedProps()

DSP56K

Assembler code

ROM:00000100
ROM:00000100 ; =============== S U B R O U T I N E =======================================
ROM:00000100
ROM:00000100
ROM:00000100                 global start
ROM:00000100 start:                                  ; CODE XREF: ROM:00000000↑j
ROM:00000100                                         ; start+3↓j ...
ROM:00000100                 clr     a
ROM:00000101                 move    r5,a
ROM:00000102                 tst     a
ROM:00000103                 jne     <start
ROM:00000104                 move    #$14,r5
ROM:00000105                 movec   #$13F,m6
ROM:00000107                 movec   #$13F,m4
ROM:00000109                 move    r2,r1
ROM:0000010A                 move    #$7000,r6
ROM:0000010C                 move    #$7400,r4
ROM:0000010E                 move    (r1)+n1
ROM:0000010F                 move    x:(r1)+,x0  y:(r6)+,y0
ROM:00000110                 do      #$140,ROM_115
ROM:00000112                 mpyr    y0,x0,a     x:(r1)+,x0    y:(r6)+,y0
ROM:00000113                 nop
ROM:00000114                 move    a,x:(r4)+
ROM:00000115
ROM:00000115 ROM_115:                                ; CODE XREF: start+10↑j
ROM:00000115                 movec   #$FFFF,m4
ROM:00000117                 movec   #$FFFF,m6
ROM:00000119                 move    #$72B0,r3
ROM:0000011B                 move    #$72A8,r4
ROM:0000011D                 move    #$72A0,r6
ROM:0000011F                 move    #$7156,r7
ROM:00000121                 do      #8,ROM_129
ROM:00000123                 jsr     ROM_12A
ROM:00000125                 nop
ROM:00000126                 nop

Fujitsu FR (.elf)

Assembler code

.text:00000114
.text:00000114 ; =============== S U B R O U T I N E =======================================
.text:00000114
.text:00000114 ; Attributes: bp-based frame
.text:00000114
.text:00000114                 .globl main
.text:00000114                 .type main, @function
.text:00000114 main:
.text:00000114
.text:00000114 var_4           = -4
.text:00000114
.text:00000114                 st      rp, @-r15
.text:00000116                 enter   #8
.text:00000118                 ldi:32  #0x170, r4
.text:0000011E                 ldi:32  #printf, r1
.text:00000124                 call    @r1
.text:00000126                 ldi:8   #1, r4
.text:00000128                 ldi:8   #2, r5
.text:0000012A                 ldi:8   #3, r6
.text:0000012C                 ldi:32  #plok1, r1
.text:00000132                 call    @r1
.text:00000134                 mov     r4, r2
.text:00000136                 ldi:8   #var_4, r1
.text:00000138                 extsb   r1
.text:0000013A                 addn    r14, r1
.text:0000013C                 st      r2, @r1
.text:0000013E                 ldi:8   #var_4, r1
.text:00000140                 extsb   r1
.text:00000142                 addn    r14, r1
.text:00000144                 ld      @r1, r4
.text:00000146                 ldi:32  #plok2, r1
.text:0000014C                 call    @r1
.text:0000014E                 ldi:8   #0x61, r4 ; 'a'
.text:00000150                 ldi:32  #plok3, r1
.text:00000156                 call    @r1

Gameboy

Assembler code

ROM:0ABF                 db  23h ; #
ROM:0AC0                 db  10h
ROM:0AC1                 db 0EEh ; î
ROM:0AC2                 db 0C9h ; É
ROM:0AC3 ; ---------------------------------------------------------------------------
ROM:0AC3                 ld      a, (4DA4h)
ROM:0AC6                 and     a
ROM:0AC7                 ret     nz
ROM:0AC8                 ld      ix, 4C00h
ROM:0ACC                 ld      iy, 4DC8h
ROM:0AD0                 ld      de, 100h
ROM:0AD3                 cp      (iy+0)
ROM:0AD6                 jp      nz, loc_BD2
ROM:0AD9                 ld      (iy+0), 0Eh
ROM:0ADD                 ld      a, (4DA6h)
ROM:0AE0                 and     a
ROM:0AE1                 jr      z, loc_AFE
ROM:0AE3                 ld      hl, (4DCBh)
ROM:0AE6                 and     a
ROM:0AE7                 sbc     hl, de
ROM:0AE9                 jr      nc, loc_AFE
ROM:0AEB                 ld      hl, 4EACh
ROM:0AEE                 set     7, (hl)
ROM:0AF0                 ld      a, 9
ROM:0AF2                 cp      (ix+0Bh)
ROM:0AF5                 jr      nz, loc_AFB
ROM:0AF7                 res     7, (hl)
ROM:0AF9                 ld      a, 9
ROM:0AFB
ROM:0AFB loc_AFB:                                ; CODE XREF: ROM:0AF5↑j
ROM:0AFB                 ld      (4C0Bh), a
ROM:0AFE
ROM:0AFE loc_AFE:                                ; CODE XREF: ROM:0AE1↑j
ROM:0AFE                                         ; ROM:0AE9↑j
ROM:0AFE                 ld      a, (4DA7h)

H8 300: COFF FILE Format

Assembler code

.text:00000164                 beq     _L6:8
.text:00000166                 mov.w   @(var_6:16,r6), r0
.text:0000016A                 mov.w   @(var_4:16,r6), r1
.text:0000016E                 mov.w   r3, @(var_2:16,r6)
.text:00000172                 jsr     ___negsf2:16
.text:00000176                 mov.w   r0, @(var_6:16,r6)
.text:0000017A                 mov.w   r1, @(var_4:16,r6)
.text:0000017E                 mov.w   @(var_2:16,r6), r3
.text:00000182
.text:00000182 _L6:                                    ; CODE XREF: ___adjust+64↑j
.text:00000182                 mov.w   r3, r3
.text:00000184                 bne     _L7:8
.text:00000186                 mov.w   @(var_6:16,r6), r0
.text:0000018A                 mov.w   @(var_4:16,r6), r1
.text:0000018E                 bra     _L11:8
.text:00000190 ; ---------------------------------------------------------------------------
.text:00000190
.text:00000190 _L7:                                    ; CODE XREF: ___adjust+84↑j
.text:00000190                 mov.w   r3, r3
.text:00000192                 bge     _L8:8
.text:00000194                 mov.w   r3, r0
.text:00000196                 not.b   r0l
.text:00000198                 not.b   r0h
.text:0000019A                 adds    #1, r0
.text:0000019C                 jsr     ___exp10:16
.text:000001A0                 push.w  r1
.text:000001A2                 push.w  r0
.text:000001A4                 mov.w   @(var_6:16,r6), r0
.text:000001A8                 mov.w   @(var_4:16,r6), r1
.text:000001AC                 jsr     ___divsf3:16
.text:000001B0                 bra     _L12:8
.text:000001B2 ; ---------------------------------------------------------------------------
.text:000001B2
.text:000001B2 _L8:                                    ; CODE XREF: ___adjust+92↑j
.text:000001B2                 mov.w   r3, r0

H8 300s: COFF FILE Format

Assembler code

.text:00000114                 ble     _L2:8
.text:00000116                 mov.w   #0x22, r2 ; '"'
.text:0000011A                 mov.w   r2, @er0
.text:0000011C                 mov.l   @___infinity:32, er0
.text:00000124                 mov.w   r3, r3
.text:00000126                 beq     _L11:8
.text:00000128                 jsr     ___negsf2:24
.text:0000012C                 bra     _L11:8
.text:0000012E ; ---------------------------------------------------------------------------
.text:0000012E
.text:0000012E _L2:                                    ; CODE XREF: ___adjust+14↑j
.text:0000012E                 cmp.w   #0xFECC, r4
.text:00000132                 bge     _L4:8
.text:00000134                 mov.w   #0x22, r2 ; '"'
.text:00000138                 mov.w   r2, @er0
.text:0000013A                 mov.l   @_LC0:16, er0
.text:00000140                 bra     _L11:8
.text:00000142 ; ---------------------------------------------------------------------------
.text:00000142
.text:00000142 _L4:                                    ; CODE XREF: ___adjust+32↑j
.text:00000142                 mov.l   @er1, er5
.text:00000146                 mov.w   r3, r3
.text:00000148                 beq     _L6:8
.text:0000014A                 mov.l   er5, er0
.text:0000014C                 jsr     ___negsf2:24
.text:00000150                 mov.l   er0, er5
.text:00000152
.text:00000152 _L6:                                    ; CODE XREF: ___adjust+48↑j
.text:00000152                 mov.w   r4, r4
.text:00000154                 bne     _L7:8
.text:00000156                 mov.l   er5, er0
.text:00000158                 bra     _L11:8
.text:0000015A ; ---------------------------------------------------------------------------
.text:0000015A
.text:0000015A _L7:                                    ; CODE XREF: ___adjust+54↑j
.text:0000015A                 mov.w   r4, r4

H8 500

Assembler code

ROM:1082
ROM:1082 ! =============== S U B R O U T I N E =======================================
ROM:1082
ROM:1082
ROM:1082 sub_1082: ! near
ROM:1082                 mov:g.w @(0xC:8,r3), r0
ROM:1085                 mov:g.w @(0xA:8,r3), r2
ROM:1088                 bra     loc_109D:8
ROM:108A ! ---------------------------------------------------------------------------
ROM:108A
ROM:108A loc_108A:                               ! CODE XREF: sub_1082:loc_109D↓j
ROM:108A                 mov:g.w @r0+, r4
ROM:108C                 mov:g.w @r0+, r1
ROM:108E                 shlr.w  r1
ROM:1090                 sub.w   #1:16, r1
ROM:1094
ROM:1094 loc_1094:                               ! CODE XREF: sub_1082+14↓j
ROM:1094                 clr.w   @r4+
ROM:1096                 scb/f   r1, loc_1094:8
ROM:1099                 sub.w   #1:16, r2
ROM:109D
ROM:109D loc_109D:                               ! CODE XREF: sub_1082+6↑j
ROM:109D                 bne     loc_108A:8
ROM:109F                 mov:g.w @(0x10:8,r3), r4
ROM:10A2
ROM:10A2 loc_10A2:                               ! CODE XREF: sub_1082+34↓j
ROM:10A2                 mov:g.w @r4+, r0
ROM:10A4                 beq     loc_10B8:8
ROM:10A6                 mov:g.w @r4+, r1
ROM:10A8
ROM:10A8 loc_10A8:                               ! CODE XREF: sub_1082+2C↓j
ROM:10A8                 mov:g.b @r4+, r2
ROM:10AA                 mov:g.b r2, @r1+
ROM:10AC                 add:q.w #-1, r0
ROM:10AE                 bne     loc_10A8:8

HPPA Risc Processor : HP-UX SOM

Assembler code

$CODE$:00004768
$CODE$:00004768 # =============== S U B R O U T I N E =======================================
$CODE$:00004768
$CODE$:00004768 # THUNK
$CODE$:00004768
$CODE$:00004768 # __int32 __fastcall sigblock(__int32 mask)
$CODE$:00004768 sigblock:                               # CODE XREF: sub_47C8+118C↓p
$CODE$:00004768                                         # DATA XREF: sigblock↓o ...
$CODE$:00004768
$CODE$:00004768 es_rp           =  0x18
$CODE$:00004768
$CODE$:00004768                 ldw             -0x2D0(%dp), %r21 # .sigblock
$CODE$:0000476C                 ldw             -0x2CC(%dp), %r19 # dword_40001614
$CODE$:00004770                 ldsid           (%r21), %r1
$CODE$:00004774                 mtsp            %r1, %sr0
$CODE$:00004778                 be              0(%sr0,%r21)
$CODE$:0000477C                 stw             %rp, -es_rp(%sp)
$CODE$:0000477C
$CODE$:0000477C # End of function sigblock
$CODE$:0000477C
$CODE$:00004780
$CODE$:00004780 # =============== S U B R O U T I N E =======================================
$CODE$:00004780
$CODE$:00004780 # THUNK
$CODE$:00004780
$CODE$:00004780 # __int32 __fastcall sigsetmask(__int32 mask)
$CODE$:00004780 sigsetmask:                             # CODE XREF: sub_47C8+1218↓p
$CODE$:00004780                                         # DATA XREF: sigsetmask↓o ...
$CODE$:00004780
$CODE$:00004780 es_rp           =  0x18
$CODE$:00004780
$CODE$:00004780                 ldw             -0x368(%dp), %r21 # .sigsetmask
$CODE$:00004784                 ldw             -0x364(%dp), %r19 # dword_4000157C
$CODE$:00004788                 ldsid           (%r21), %r1
$CODE$:0000478C                 mtsp            %r1, %sr0

i51

Assembler code

code:0000006B
code:0000006B ; =============== S U B R O U T I N E =======================================
code:0000006B
code:0000006B ; External interrupt 6
code:0000006B
code:0000006B                 ; public IEX6
code:0000006B IEX6:
code:0000006B                 mov     R7, A
code:0000006C                 addc    A, RAM_0
code:0000006E                 addc    A, RESERVED00FF ; RESERVED
code:00000070                 addc    A, @R0
code:00000071                 addc    A, @R1
code:00000072                 addc    A, R0
code:00000073                 addc    A, R1
code:00000074                 addc    A, R2
code:00000075                 addc    A, R3
code:00000076                 addc    A, R4
code:00000077                 addc    A, R5
code:00000078                 addc    A, R6
code:00000079                 addc    A, R7
code:0000007A                 ajmp    IEX2+2          ; External interrupt 2
code:0000007A ; End of function IEX6
code:0000007A
code:0000007A ; ---------------------------------------------------------------------------
code:0000007C                 .byte 0x54 ; T
code:0000007D                 .byte    0
code:0000007E                 .word 0x54FF
code:00000080                 .byte 0x55, 0, 0x55
code:00000083
code:00000083 ; =============== S U B R O U T I N E =======================================
code:00000083
code:00000083 ; Serial channel 1
code:00000083
code:00000083                 ; public RI1_TI1
code:00000083 RI1_TI1:
code:00000083                 mov     R7, A

i860

Assembler code

.text:000011C0
.text:000011C0 // =============== S U B R O U T I N E =======================================
.text:000011C0
.text:000011C0
.text:000011C0                 // public _main
.text:000011C0 _main:                                  // CODE XREF: __main+120↓p
.text:000011C0                 addu            -0x20, r2, r2
.text:000011C4                 st.l            0x11(r2), r3
.text:000011C8                 addu            0x10, r2, r3
.text:000011CC                 st.l            5(r3), r1
.text:000011D0                 orh             0, r0, r31
.text:000011D4                 call            _printf
.text:000011D8                 or              0xA000, r31, r16
.text:000011DC                 adds            0x10, r3, r31
.text:000011E0                 ld.l            4(r3), r1
.text:000011E4                 ld.l            0(r3), r3
.text:000011E8                 bri             r1
.text:000011EC                 shl             r0, r31, r2
.text:000011EC // End of function _main
.text:000011EC
.text:000011F0 // ---------------------------------------------------------------------------
.text:000011F0                 shl             r0, r0, r0
.text:000011F4                 shl             r0, r0, r0
.text:000011F8                 shl             r0, r0, r0
.text:000011FC                 shl             r0, r0, r0
.text:00001200
.text:00001200 // =============== S U B R O U T I N E =======================================
.text:00001200
.text:00001200
.text:00001200                 // public _fclose
.text:00001200 _fclose:                                // CODE XREF: ___cleanup+68↓p
.text:00001200                 addu            -0x50, r2, r2
.text:00001204                 st.l            1(r2), r1
.text:00001208                 st.l            0x39(r2), r4
.text:0000120C                 st.l            0x3D(r2), r5

Intel i960

Assembler code

.text:00000020
.text:00000020 # =============== S U B R O U T I N E =======================================
.text:00000020
.text:00000020 # Attributes: library function
.text:00000020
.text:00000020                 .global __Ldoprnt
.text:00000020 __Ldoprnt:
.text:00000020                 lda     0xB0(sp), sp
.text:00000024                 st      g8, 0xE0(fp)
.text:00000028                 st      g9, 0xE4(fp)
.text:0000002C                 st      g10, 0xE8(fp)
.text:00000030                 st      g11, 0xEC(fp)
.text:00000034                 mov     g0, r12
.text:00000038                 mov     g1, r7
.text:0000003C                 mov     g2, r6
.text:00000040                 mov     0, g1
.text:00000044
.text:00000044 loc_44:                                 # DATA XREF: __Ldoprnt+3C↓o
.text:00000044                 mov     5, g2
.text:00000048                 lda     0x40(fp), g0
.text:0000004C
.text:0000004C loc_4C:                                 # DATA XREF: __Ldoprnt:loc_3AC↓o
.text:0000004C                 mov     g3, r3
.text:00000050                 st      g14, 0xA0(fp)
.text:00000054                 call    _memset
.text:00000058                 mov     0, g1
.text:0000005C                 lda     loc_44, g2
.text:00000060                 lda     0x50(fp), g0
.text:00000064                 call    _memset
.text:00000068
.text:00000068 loc_68:                                 # DATA XREF: __Ldoprnt:loc_3D0↓o
.text:00000068                 ldib    (r12), g4
.text:0000006C
.text:0000006C loc_6C:                                 # DATA XREF: __Ldoprnt+348↓o
.text:0000006C                 mov     g14, g5

Intel IA-64 (Itanium)

Assembler code

.text:0000000000421100
.text:0000000000421100 // =============== S U B R O U T I N E =======================================
.text:0000000000421100
.text:0000000000421100
.text:0000000000421100 sub_421100:                             // CODE XREF: sub_41FF40+3C↑p
.text:0000000000421100                 alloc r37 = ar.pfs, 0, 9, 2, 0
.text:0000000000421106                 mov r39 = pr
.text:000000000042110C                 adds sp = -32, sp
.text:0000000000421110                 or r40 = gp, r0;;
.text:0000000000421116                 cmp4.eq p14, p15 = 2, r32
.text:000000000042111C                 mov r36 = b0;;
.text:0000000000421120                 ld8.nta r3 = [sp]
.text:0000000000421126                 mov.i r38 = ar.lc       // loop count register
.text:000000000042112C   (p14)          br.cond.dpnt.few loc_4211D0;;
.text:0000000000421130                 cmp4.eq p14, p15 = 1, r0
.text:0000000000421136                 cmp4.eq p13, p0 = 15, r32
.text:000000000042113C                 cmp4.eq p12, p0 = 21, r32;;
.text:0000000000421140                 cmp4.eq.or.andcm p14, p15 = 4, r32
.text:0000000000421146                 cmp4.eq.or.andcm p14, p15 = 8, r32
.text:000000000042114C                 cmp4.eq.or.andcm p14, p15 = 11, r32
.text:0000000000421150   (p14)          br.cond.dpnt.few loc_4211B0
.text:0000000000421156   (p13)          br.cond.dpnt.few loc_4211A0
.text:000000000042115C   (p12)          br.cond.dpnt.few loc_421190;;
.text:0000000000421160                 cmp4.eq p14, p15 = 22, r32
.text:0000000000421166                 nop.f 0
.text:000000000042116C   (p14)          br.cond.dpnt.few loc_421180;;
.text:0000000000421170                 mov r8 = -1
.text:0000000000421176                 nop.f 0
.text:000000000042117C                 br.few loc_421430;;
.text:0000000000421180 // ---------------------------------------------------------------------------
.text:0000000000421180
.text:0000000000421180 loc_421180:                             // CODE XREF: sub_421100+6C↑j
.text:0000000000421180                 addl r28 = -2086752, gp // unk_4308A0
.text:0000000000421186                 nop.f 0
.text:000000000042118C                 br.few loc_4211E0;;

Java Bytecode

Assembler code

// Segment type: Pure code
  public synchronized void reset()
  max_stack 4
  max_locals 2
  {
    invokestatic java.security.IdentityScope.getSystemScope()
                                               // CODE XREF: <init>+5↑P
    astore_1 // met004_slot001
    aload_1 // met004_slot001
    instanceof sun.security.provider.IdentityDatabase
    ifeq met004_47
    aload_0 // met004_slot000
    aload_1 // met004_slot001
    checkcast sun.security.provider.IdentityDatabase
    putfield scope
    aload_0 // met004_slot000
    new java.lang.StringBuffer
    dup
    ldc "installing "
    invokespecial java.lang.StringBuffer.<init>(java.lang.String)
    aload_1 // met004_slot001
    invokevirtual java.lang.StringBuffer.append(java.lang.Object)
    ldc " as the scope for signers."
    invokevirtual java.lang.StringBuffer.append(java.lang.String)
    invokevirtual java.lang.StringBuffer.toString()
    invokevirtual debug(java.lang.String)
    goto met004_53

met004_47:                                     // CODE XREF: reset+8↑j
    aload_0 // met004_slot000
    ldc "no signer scope found."

Angstrem KR 1878

Assembler code

CODE:000F
CODE:000F ; =============== S U B R O U T I N E =======================================
CODE:000F
CODE:000F
CODE:000F                 global EEPWr
CODE:000F EEPWr:
CODE:000F                 movl    %c1 PCtlA,#0
CODE:0010                 ldr     SR0,#8
CODE:0011 ; assume a = 8
CODE:0011                 ldr     SR1,#9
CODE:0012 ; assume b = 9
CODE:0012                 ldr     SR2,#$E
CODE:0013 ; assume c = $E
CODE:0013                 ldr     SR5,#$40
CODE:0014                 movl    %b1 byte_100049,#0
CODE:0015                 movl    %b4 byte_10004C,#0
CODE:0016                 jsr     sub_29F
CODE:0017                 ldr     SR6,#$82
CODE:0018                 ldr     SR7,#7
CODE:0019                 movl    %c0 byte_100070,#$A
CODE:001A
CODE:001A loc_1A:                                 ; CODE XREF: EEPWr+F↓j
CODE:001A                 mov     %b0 byte_100048,%d7
CODE:001B                 jsr     sub_25F
CODE:001C                 jsr     sub_29F
CODE:001D                 subl    %c0 byte_100070,#1
CODE:001E                 jnz     loc_1A
CODE:001F                 swap    %b0 byte_100048
CODE:0020                 cmpl    %c1 byte_100071,#1
CODE:0021                 jnz     loc_23
CODE:0022                 btg     %b0 byte_100048,#$80
CODE:0023
CODE:0023 loc_23:                                 ; CODE XREF: EEPWr+12↑j
CODE:0023                 mov     %c4 byte_100074,%b0 byte_100048
CODE:0024                 movl    %b0 byte_100048,#$90

Renesas/Hitachi M16C

Assembler code

program:000E023C
program:000E023C ; =============== S U B R O U T I N E =======================================
program:000E023C
program:000E023C ; Attributes: bp-based frame
program:000E023C
program:000E023C                 ; public $_pput
program:000E023C $_pput:
program:000E023C
program:000E023C var_2           = -2
program:000E023C
program:000E023C                 ENTER   #2
program:000E023F                 MOV.W   R1, var_2[FB]
program:000E0242                 MOV.B   p4, R0L         ; Port P4 register
program:000E0245                 MOV.B   #0, R0H
program:000E0246                 BTST    #4, R0
program:000E0249                 JEQ/Z   loc_E024F
program:000E024B                 MOV.W   #-1, R0
program:000E024D                 EXITD
program:000E024F ; ---------------------------------------------------------------------------
program:000E024F
program:000E024F loc_E024F:                              ; CODE XREF: $_pput+D↑j
program:000E024F                                         ; $_pput+1A↓j
program:000E024F                 MOV.B   p4, R0L         ; Port P4 register
program:000E0252                 MOV.B   #0, R0H
program:000E0253                 BTST    #5, R0
program:000E0256                 JEQ/Z   loc_E024F
program:000E0258                 MOV.B   var_2[FB], p5   ; Port P5 register
program:000E025D                 MOV.W   #0, var_2[FB]
program:000E0260
program:000E0260 loc_E0260:                              ; CODE XREF: $_pput+2F↓j
program:000E0260                 CMP.W   #0Ah, var_2[FB]
program:000E0265                 JGE     loc_E026D
program:000E0268                 ADD.W   #1, var_2[FB]
program:000E026B                 JMP.B   loc_E0260
program:000E026D ; ---------------------------------------------------------------------------
program:000E026D
program:000E026D loc_E026D:                              ; CODE XREF: $_pput+29↑j
program:000E026D                 MOV.B   #8, p4          ; Port P4 register

Renesas/Hitachi M32R

Assembler code

P:000000C0 ; ===========================================================================
P:000000C0
P:000000C0 ; Segment type: Pure code
P:000000C0 .section P
P:000000C0
P:000000C0 ; =============== S U B R O U T I N E =======================================
P:000000C0
P:000000C0
P:000000C0 sub_C0:
P:000000C0                 addi    sp, #-0x20 || nop
P:000000C4                 seth    R0, #0x3F80
P:000000C8                 or3     R0, R0, #0
P:000000CC                 st      R0, @(0x1C, sp)
P:000000D0                 seth    R0, #0x4000
P:000000D4                 or3     R0, R0, #0
P:000000D8                 st      R0, @(0x18, sp)
P:000000DC                 ld      R0, @(0x1C, sp)
P:000000E0                 ld      R1, @(0x18, sp)
P:000000E4                 fadd    R0, R0, R1
P:000000E8                 seth    R1, #0x4000
P:000000EC                 or3     R1, R1, #0
P:000000F0                 fdiv    R0, R0, R1
P:000000F4                 st      R0, @(0x14, sp)
P:000000F8                 ld      R0, @(0x14, sp)
P:000000FC                 ld      R1, @(0x18, sp)
P:00000100                 ld      R2, @(0x1C, sp)
P:00000104                 fmul    R1, R1, R2
P:00000108                 fsub    R0, R0, R1
P:0000010C                 st      R0, @(0x10, sp)
P:00000110                 ld      R0, @(0x10, sp)
P:00000114                 ftoi    R0, R0
P:00000118                 st      R0, @(0xC, sp)
P:0000011C                 ld      R0, @(0xC, sp)
P:00000120                 srai    R0, #2 || nop
P:00000124                 itof    R0, R0

M740

Assembler Code

seg000:81D8
seg000:81D8 ; =============== S U B R O U T I N E =======================================
seg000:81D8
seg000:81D8
seg000:81D8 sub_81D8:                               ; CODE XREF: seg000:8F8C↓p
seg000:81D8                 lda     3, X
seg000:81DA                 pha
seg000:81DB                 jsr     sub_815F
seg000:81DE                 jsr     sub_818C
seg000:81E1                 lda     $FB, X
seg000:81E3                 sta     0, X
seg000:81E5                 lda     $FC, X
seg000:81E7                 sta     1, X
seg000:81E9                 pla
seg000:81EA                 bpl     locret_81FD
seg000:81EC                 lda     0, X
seg000:81EE                 eor     #$FF
seg000:81F0                 clc
seg000:81F1                 adc     #1
seg000:81F3                 sta     0, X
seg000:81F5                 lda     1, X
seg000:81F7                 eor     #$FF
seg000:81F9                 adc     #0
seg000:81FB                 sta     1, X
seg000:81FD
seg000:81FD locret_81FD:                            ; CODE XREF: sub_81D8+12↑j
seg000:81FD                 rts
seg000:81FD ; End of function sub_81D8
seg000:81FD
seg000:81FE
seg000:81FE ; =============== S U B R O U T I N E =======================================
seg000:81FE
seg000:81FE
seg000:81FE sub_81FE:                               ; CODE XREF: seg000:8C2B↓p
seg000:81FE                                         ; sub_9D0C+1↓j
seg000:81FE                 lda     3, X

M7700

Assembler Code

seg000:00008051                 lda     A, word_815B
seg000:00008054                 pha
seg000:00008055                 pea     #0
seg000:00008058                 pea     #80h ; '€'
seg000:0000805B                 pea     #0
seg000:0000805E                 pea     #817Ch
seg000:00008061                 jsrl    sub_1800D
seg000:00008065                 lda     A, #6B7h
seg000:00008068                 tas
seg000:00008069                 lda     A, word_8151
seg000:0000806C                 pha
seg000:0000806D                 lda     A, word_814F
seg000:00008070                 pha
seg000:00008071                 pea     #1
seg000:00008074                 pea     #2010h
seg000:00008077                 jsrl    sub_1803F
seg000:0000807B                 lda     A, word_8155
seg000:0000807E                 pha
seg000:0000807F                 lda     A, word_8153
seg000:00008082                 pha
seg000:00008083                 pea     #1
seg000:00008086                 pea     #2014h
seg000:00008089                 jsrl    sub_1803F
seg000:0000808D                 lda     A, word_8165
seg000:00008090                 pha
seg000:00008091                 lda     A, word_8163
seg000:00008094                 pha
seg000:00008095                 pea     #1
seg000:00008098                 pea     #2000h
seg000:0000809B                 pea     #1
seg000:0000809E                 pea     #0AED5h
seg000:000080A1                 jsrl    sub_1800D
seg000:000080A5                 lda     A, word_8161
seg000:000080A8                 pha
seg000:000080A9                 lda     A, word_815F

M7900

Assembler code

ROM_:8000 ; ===========================================================================
ROM_:8000
ROM_:8000 ; Segment type: Pure data
ROM_:8000                 SEGMENT ROM_
ROM_:8000                 .org 8000h
ROM_:8000
ROM_:8000 ; =============== S U B R O U T I N E =======================================
ROM_:8000
ROM_:8000
ROM_:8000                 ; public __RESET
ROM_:8000 __RESET:                                ; DATA XREF: USER_VEC:FFFE↓o
ROM_:8000                 ldt     #2
ROM_:8003                 ldd     0,#0
ROM_:8007                 ldd     1,#1000h
ROM_:800B                 ldd     2,#2000h
ROM_:800F                 ldd     3,#3000h
ROM_:8013                 sem
ROM_:8014                 abs.b   A
ROM_:8015                 abs.b   B
ROM_:8017                 clm
ROM_:8018                 abs     A
ROM_:8019                 abs     B
ROM_:801B                 absd.d  E
ROM_:801D                 sem
ROM_:801E                 adc.b   A,#12h
ROM_:8021                 clm
ROM_:8022                 adc     A,#1234h
ROM_:8026                 adc     A,DP3:word_300F
ROM_:8029                 adc     A,DP3:word_300F,X
ROM_:802C                 adc     A,(DP3:word_3006)
ROM_:802F                 adc     A,(DP3:word_3006,X)
ROM_:8032                 adc     A,(DP3:word_3006),Y
ROM_:8035                 adc     A,L(DP3:tbyte_3009)
ROM_:8038                 adc     A,L(DP3:tbyte_3009),Y
ROM_:803B                 adc     A,12h,S

MIPS Processor : Nintendo N64

Assembler code

CODE:80148710                 lrv     $v13[0], 2($t5)
CODE:80148714
CODE:80148714 loc_80148714:                            # CODE XREF: CODE:80148840↓j
CODE:80148714                 addi    $s4, 9
CODE:80148718                 vmudn   $v30, $v3, $v23[0]
CODE:8014871C                 addi    $s5, 9
CODE:80148720                 vmadn   $v30, $v4, $v23[0]
CODE:80148724                 ldv     $v1[0], 0($s4)
CODE:80148728                 vmudn   $v29, $v5, $v23[0]
CODE:8014872C                 lbu     $at, 0($s5)
CODE:80148730                 vmadn   $v29, $v6, $v23[0]
CODE:80148734                 blez    $t6, loc_80148744
CODE:80148738                 andi    $a7, $at, 0xF
CODE:8014873C                 vmudm   $v30, $v22[8]
CODE:80148740                 vmudm   $v29, $v22[8]
CODE:80148744
CODE:80148744 loc_80148744:                            # CODE XREF: CODE:80148734↑j
CODE:80148744                 sll     $a7, 5
CODE:80148748                 vand    $v3, $v25, $v1[8]
CODE:8014874C                 add     $t5, $a7, $t7
CODE:80148750                 vand    $v4, $v24, $v1[9]
CODE:80148754                 vand    $v5, $v25, $v1[10]
CODE:80148758                 vand    $v6, $v24, $v1[11]
CODE:8014875C                 srl     $t6, $at, 4
CODE:80148760                 vmudh   $v2, $v21, $v27[14]
CODE:80148764                 li      $v0, 0xC
CODE:80148768                 vmadh   $v2, $v20, $v27[15]
CODE:8014876C                 sub     $t6, $v0, $t6
CODE:80148770                 vmadh   $v2, $v19, $v30[8]
CODE:80148774                 addi    $v0, $t6, -1
CODE:80148778                 vmadh   $v2, $v18, $v30[9]
CODE:8014877C                 li      $v1, 1
CODE:80148780                 vmadh   $v2, $v17, $v30[10]
CODE:80148784                 sll     $v1, 15
CODE:80148788                 vmadh   $v2, $v16, $v30[11]

MIPS R5900 Processor : Sony bin

Assembler code

.text:001A5498
.text:001A5498  # =============== S U B R O U T I N E =======================================
.text:001A5498
.text:001A5498
.text:001A5498                 .globl SysTimerGet
.text:001A5498 SysTimerGet:
.text:001A5498
.text:001A5498 var_s0          =  0
.text:001A5498
.text:001A5498                 addiu   $sp, -0x10
.text:001A549C                 lui     $a0, 0x41  # 'A'
.text:001A54A0                 sd      $ra, var_s0($sp)
.text:001A54A4                 li      $a0, sysTimerVarG
.text:001A54A8                 lui     $a1, 0x1000
.text:001A54AC                 lw      $v0, (dword_416244 - 0x416238)($a0)
.text:001A54B0                 lw      $v1, 0x10000000
.text:001A54B4                 lwu     $a2, (dword_416240 - 0x416238)($a0)
.text:001A54B8                 sll     $v0, 21
.text:001A54BC                 dsll32  $v0, 0
.text:001A54C0                 li      $a1, 0x3D86
.text:001A54C4                 daddu   $v1, $a2
.text:001A54C8                 dsrl32  $v0, 0
.text:001A54CC                 daddu   $v1, $v0
.text:001A54D0                 dsll    $a0, $v1, 5
.text:001A54D4                 dsubu   $a0, $v1
.text:001A54D8                 dsll    $a0, 2
.text:001A54DC                 daddu   $a0, $v1
.text:001A54E0                 jal     __divdi3
.text:001A54E4                 dsll    $a0, 3
.text:001A54E8                 ld      $ra, var_s0($sp)
.text:001A54EC                 dsll32  $v0, 0
.text:001A54F0                 dsra32  $v0, 0
.text:001A54F4                 jr      $ra
.text:001A54F8                 addiu   $sp, 0x10
.text:001A54F8  # End of function SysTimerGet
.text:001A54F8
.text:001A54F8  # ---------------------------------------------------------------------------

MIPS Processor : Sony ELF

Assembler code

.text:0000073C
.text:0000073C  # =============== S U B R O U T I N E =======================================
.text:0000073C
.text:0000073C
.text:0000073C sub_73C:                                 # CODE XREF: sub_0+154↑p
.text:0000073C                                          # DATA XREF: .rodata.sceResident:00003910↓o
.text:0000073C
.text:0000073C var_s0          =  0
.text:0000073C var_s4          =  4
.text:0000073C var_s8          =  8
.text:0000073C var_sC          =  0xC
.text:0000073C
.text:0000073C                 addiu   $sp, -0x10
.text:00000740                 sw      $s0, var_s0($sp)
.text:00000744                 lui     $v0, 0x8002
.text:00000748                 move    $s0, $a0
.text:0000074C                 sltiu   $a0, 0x43  # 'C'
.text:00000750                 sw      $s1, var_s4($sp)
.text:00000754                 ori     $v1, $v0, 0x65  # 'e'
.text:00000758                 move    $s1, $zero
.text:0000075C                 sw      $ra, var_sC($sp)
.text:00000760                 beqz    $a0, loc_7A8
.text:00000764                 sw      $s2, var_s8($sp)
.text:00000768                 jal     sub_3180
.text:0000076C                 nop
.text:00000770                 sll     $a5, $s0, 3
.text:00000774                 subu    $a4, $a5, $s0
.text:00000778                 lui     $a3, %hi(unk_3C14)
.text:0000077C                 sll     $a1, $a4, 3
.text:00000780                 addiu   $a2, $a3, %lo(unk_3C14)
.text:00000784                 addu    $a0, $a1, $a2
.text:00000788                 lw      $v1, 0($a0)
.text:0000078C                 bnez    $v1, loc_7C4
.text:00000790                 move    $s2, $v0
.text:00000794                 lui     $a6, 0x8002

MIPS Processor : Sony PSX

Assembler code

.text:00003E68
.text:00003E68  # =============== S U B R O U T I N E =======================================
.text:00003E68
.text:00003E68
.text:00003E68 sub_3E68:                                # CODE XREF: McGuiSave+64↓p
.text:00003E68                                          # McGuiLoad+64↓p
.text:00003E68
.text:00003E68 var_s0          =  0
.text:00003E68 var_s4          =  4
.text:00003E68 var_s8          =  8
.text:00003E68 var_sC          =  0xC
.text:00003E68 var_s10         =  0x10
.text:00003E68
.text:00003E68                 addiu   $sp, -0x28
.text:00003E6C                 lw      $a0, side
.text:00003E74                 li      $a1, 0x10
.text:00003E78                 sw      $s1, 0x10+var_s4($sp)
.text:00003E7C                 li      $s1, ot
.text:00003E84                 sw      $ra, 0x10+var_s10($sp)
.text:00003E88                 sw      $s3, 0x10+var_sC($sp)
.text:00003E8C                 sw      $s2, 0x10+var_s8($sp)
.text:00003E90                 sw      $s0, 0x10+var_s0($sp)
.text:00003E94                 sll     $a0, 6
.text:00003E98                 jal     ClearOTag
.text:00003E9C                 addu    $a0, $s1
.text:00003EA0                 li      $v1, (sDraw+0x17A)
.text:00003EA8                 lh      $v0, (aSsvabtransferF+6 - 0x282)($v1)  # "ransfer failed (%d)\n"
.text:00003EAC                 nop
.text:00003EB0                 blez    $v0, loc_3F7C
.text:00003EB4                 nop
.text:00003EB8                 move    $s0, $v1
.text:00003EBC                 li      $s3, disp
.text:00003EC4                 li      $s2, draw
.text:00003ECC
.text:00003ECC loc_3ECC:                                # CODE XREF: sub_3E68+10C↓j
.text:00003ECC                 lhu     $v0, 0($s0)

MIPS Processor : Sony PSX

Assembler code

.text:00003E68
.text:00003E68  # =============== S U B R O U T I N E =======================================
.text:00003E68
.text:00003E68
.text:00003E68 sub_3E68:                                # CODE XREF: McGuiSave+64↓p
.text:00003E68                                          # McGuiLoad+64↓p
.text:00003E68
.text:00003E68 var_s0          =  0
.text:00003E68 var_s4          =  4
.text:00003E68 var_s8          =  8
.text:00003E68 var_sC          =  0xC
.text:00003E68 var_s10         =  0x10
.text:00003E68
.text:00003E68                 addiu   $sp, -0x28
.text:00003E6C                 lw      $a0, side
.text:00003E74                 li      $a1, 0x10
.text:00003E78                 sw      $s1, 0x10+var_s4($sp)
.text:00003E7C                 li      $s1, ot
.text:00003E84                 sw      $ra, 0x10+var_s10($sp)
.text:00003E88                 sw      $s3, 0x10+var_sC($sp)
.text:00003E8C                 sw      $s2, 0x10+var_s8($sp)
.text:00003E90                 sw      $s0, 0x10+var_s0($sp)
.text:00003E94                 sll     $a0, 6
.text:00003E98                 jal     ClearOTag
.text:00003E9C                 addu    $a0, $s1
.text:00003EA0                 li      $v1, (sDraw+0x17A)
.text:00003EA8                 lh      $v0, (aSsvabtransferF+6 - 0x282)($v1)  # "ransfer failed (%d)\n"
.text:00003EAC                 nop
.text:00003EB0                 blez    $v0, loc_3F7C
.text:00003EB4                 nop
.text:00003EB8                 move    $s0, $v1
.text:00003EBC                 li      $s3, disp
.text:00003EC4                 li      $s2, draw
.text:00003ECC
.text:00003ECC loc_3ECC:                                # CODE XREF: sub_3E68+10C↓j
.text:00003ECC                 lhu     $v0, 0($s0)

MIPS Processor : Unix COFF File Format

Assembler code

.text:00400838
.text:00400838  # =============== S U B R O U T I N E =======================================
.text:00400838
.text:00400838
.text:00400838 sub_400838:                              # CODE XREF: sub_400700+3C↑p
.text:00400838                                          # sub_400778+44↑p ...
.text:00400838
.text:00400838 var_s0          =  0
.text:00400838 var_s4          =  4
.text:00400838
.text:00400838                 addiu   $sp, -0x20
.text:0040083C                 sw      $s0, 0x18+var_s0($sp)
.text:00400840                 move    $s0, $a0
.text:00400844                 bnez    $s0, loc_400894
.text:00400848                 sw      $ra, 0x18+var_s4($sp)
.text:0040084C                 la      $t6, unk_10000A94
.text:00400850                 li      $t7, unk_10000455
.text:00400858                 lui     $s0, 0x1000
.text:0040085C                 sltu    $at, $t6, $t7
.text:00400860                 bnez    $at, loc_40088C
.text:00400864                 li      $s0, unk_10000454
.text:00400868
.text:00400868 loc_400868:                              # CODE XREF: sub_400838+4C↓j
.text:00400868                 beqz    $s0, loc_400878
.text:0040086C                 nop
.text:00400870                 jal     sub_400838
.text:00400874                 move    $a0, $s0
.text:00400878
.text:00400878 loc_400878:                              # CODE XREF: sub_400838:loc_400868↑j
.text:00400878                 la      $t8, unk_10000A94
.text:0040087C                 addiu   $s0, 0x10
.text:00400880                 sltu    $at, $s0, $t8
.text:00400884                 bnez    $at, loc_400868
.text:00400888                 nop
.text:0040088C
.text:0040088C loc_40088C:                              # CODE XREF: sub_400838+28↑j
.text:0040088C                 b       loc_400970

MIPS Processor : Unix ELF File Format

Assembler code

.text:5FFE29A8                 li      $s1, 1
.text:5FFE29AC
.text:5FFE29AC $L137:                                   # CODE XREF: read_logfile(char const *)+138↑j
.text:5FFE29AC                                          # read_logfile(char const *)+158↑j
.text:5FFE29AC                 beqz    $s1, $L134
.text:5FFE29B0                 nop
.text:5FFE29B4
.text:5FFE29B4 $Lb69:                                   # Alternative name is 'LM268'
.text:5FFE29B4                 addiu   $v0, $fp, 0x750+var_428
.text:5FFE29B8                 move    $a0, $v0         # char *
.text:5FFE29BC                 jal     get_time__FPCc   # get_time(char const *)
.text:5FFE29C0                 nop
.text:5FFE29C4                 sw      $v0, 0x750+var_110($fp)
.text:5FFE29C8                 lw      $v0, 0x750+var_110($fp)
.text:5FFE29CC                 nop
.text:5FFE29D0                 bnez    $v0, $L138
.text:5FFE29D4                 nop
.text:5FFE29D8
.text:5FFE29D8 LM269:
.text:5FFE29D8                 li      $v0, $LC37       # "Illegal time"
.text:5FFE29E0                 sw      $v0, 0x750+var_11C($fp)
.text:5FFE29E4
.text:5FFE29E4 LM270:
.text:5FFE29E4                 j       $L139
.text:5FFE29E8                 nop
.text:5FFE29EC  # ---------------------------------------------------------------------------
.text:5FFE29EC
.text:5FFE29EC $L138:                                   # CODE XREF: read_logfile(char const *)+188↑j
.text:5FFE29EC                 lw      $v0, from_time   # Alternative name is 'LM271'
.text:5FFE29F0                 lw      $v1, 0x750+var_110($fp)
.text:5FFE29F4                 nop
.text:5FFE29F8                 sltu    $v0, $v1
.text:5FFE29FC                 bnez    $v0, $L140
.text:5FFE2A00                 nop
.text:5FFE2A04                 j       LM259

MIPS Processor: Windows CE PE File Format

Assembler code

.text:10001140                 lw      $a0, 0x58+var_18($sp)
.text:10001144                 lw      $a1, 0x58+var_14($sp)
.text:10001148                 jal     memcpy
.text:1000114C                 li      $a2, 0x400
.text:10001150                 lw      $t7, ReleaseMutex
.text:10001158                 lw      $a0, 0x58+var_1C($sp)
.text:1000115C                 jalr    $t7
.text:10001160                 nop
.text:10001164                 lw      $t8, CloseHandle
.text:1000116C                 lw      $a0, 0x58+var_1C($sp)
.text:10001170                 jalr    $t8
.text:10001174                 nop
.text:10001178                 jal     LoadLibraryW
.text:1000117C                 lw      $a0, 0x58+var_18($sp)
.text:10001180                 beqz    $v0, loc_100011D0
.text:10001184                 move    $a0, $v0
.text:10001188                 lw      $t9, GetProcAddressW
.text:10001190                 li      $a1, aCreatetranspor  # "CreateTransport"
.text:10001198                 jalr    $t9
.text:1000119C                 nop
.text:100011A0                 jalr    $v0
.text:100011A4                 nop
.text:100011A8                 sw      $v0, dword_100030C4
.text:100011B0                 lw      $t1, 0($v0)
.text:100011B4                 lw      $t0, 0x58+var_18($sp)
.text:100011B8                 move    $a0, $v0
.text:100011BC                 lw      $t2, 4($t1)
.text:100011C0                 addiu   $a1, $t0, 0x20C
.text:100011C4                 lw      $a2, 0x208($t0)
.text:100011C8                 jalr    $t2
.text:100011CC                 nop
.text:100011D0
.text:100011D0 loc_100011D0:                            # CODE XREF: CreateStream+180↑j
.text:100011D0                 jal     UnmapViewOfFile
.text:100011D4                 lw      $a0, 0x58+var_18($sp)

MIPS Processor: Windows CE PE2 File Format

Assembler code

.text:10001088
.text:10001088 loc_10001088:                            # DATA XREF: .pdata:10004028↓o
.text:10001088                 lw      $t6, 8($s0)
.text:1000108C                 beqzl   $t6, loc_100010F4
.text:10001090                 li      $v0, 1
.text:10001094                 sw      $zero, 8($s0)
.text:10001098                 jal     closesocket
.text:1000109C                 lw      $a0, 4($s0)
.text:100010A0                 lw      $a0, 0x14($s0)
.text:100010A4                 li      $t7, 0xFFFFFFFF
.text:100010A8                 sw      $t7, 4($s0)
.text:100010AC                 beqz    $a0, loc_100010CC
.text:100010B0                 sw      $zero, 8($s0)
.text:100010B4                 lw      $t8, 0x10($s0)
.text:100010B8                 move    $a1, $zero
.text:100010BC                 beql    $t8, $a0, loc_100010D0
.text:100010C0                 lw      $a0, 0x10($s0)
.text:100010C4                 jal     VirtualFree
.text:100010C8                 li      $a2, 0xC000
.text:100010CC
.text:100010CC loc_100010CC:                            # CODE XREF: sub_10001078+34↑j
.text:100010CC                 lw      $a0, 0x10($s0)
.text:100010D0
.text:100010D0 loc_100010D0:                            # CODE XREF: sub_10001078+44↑j
.text:100010D0                 move    $a1, $zero
.text:100010D4                 jal     VirtualFree
.text:100010D8                 li      $a2, 0xC000
.text:100010DC                 lw      $v0, 0x1C($s0)
.text:100010E0                 beqzl   $v0, loc_100010F4
.text:100010E4                 li      $v0, 1
.text:100010E8                 jal     ??3@YAXPAX@Z     # operator delete(void *)
.text:100010EC                 move    $a0, $v0
.text:100010F0                 li      $v0, 1
.text:100010F4
.text:100010F4 loc_100010F4:                            # CODE XREF: sub_10001078+14↑j
.text:100010F4                                          # sub_10001078+68↑j
.text:100010F4                 lw      $s0, 0x18+var_s0($sp)

Panasonic MN102

Assembler code

IROM:00080008
IROM:00080008 ; =============== S U B R O U T I N E =======================================
IROM:00080008
IROM:00080008 ; IRQ Manager
IROM:00080008
IROM:00080008                 ; public IRQMANAGER_
IROM:00080008 IRQMANAGER_:
IROM:00080008                 ADD     0x000000E2, SP ; 'â'
IROM:0008000A                 MOVX    D3, (0x00000008,SP)
IROM:0008000D                 MOV     A0, (0x00000018,SP)
IROM:0008000F                 MOV     MDR, D3
IROM:00080011                 MOV     D3, (0x0000001C,SP)
IROM:00080013                 MOVX    D0, (0x00000014,SP)
IROM:00080016                 MOVX    D1, (0x00000010,SP)
IROM:00080019                 MOVX    D2, (0x0000000C,SP)
IROM:0008001C                 MOV     A1, (0x00000004,SP)
IROM:0008001E                 MOV     A2, (0x00000000,SP)
IROM:00080020                 MOV     0x00000001, D3
IROM:00080022                 MOVB    D3, (0x00000003,SP)
IROM:00080025                 MOV     SP, A2
IROM:00080027                 MOV     PSW, D3
IROM:00080029                 MOV     (IAGR), D0      ; Interrupt accept group number register
IROM:0008002C                 ADD     off_80368, D0
IROM:00080031                 MOV     D0, A0
IROM:00080033                 MOV     (0x00000000,A0), A0
IROM:00080035                 AND     0x0000EFFF, PSW
IROM:00080039                 BTST    0x00002000, D3
IROM:0008003D                 BNE     loc_80058
IROM:0008003F                 OR      0x00001000, PSW
IROM:00080043                 MOV     (tbyte_8000), A1
IROM:00080047                 ADD     0x00000000, A1
IROM:00080049                 BEQ     loc_80054
IROM:0008004B                 MOV     (tbyte_8000), A1
IROM:0008004F                 MOV     SP, (0x00000008,A1)
IROM:00080051                 MOV     unk_8186, SP

Atmel OAK DSP

Assembler code

ROM:0020
ROM:0020 ; =============== S U B R O U T I N E =======================================
ROM:0020
ROM:0020 ; Attributes: bp-based frame
ROM:0020
ROM:0020 RESET_0:                                ; CODE XREF: RESET↑j
ROM:0020
ROM:0020 ; FUNCTION CHUNK AT ROM:00CB SIZE 00000001 BYTES
ROM:0020
ROM:0020                 mov     #$35F,sp
ROM:0022                 mov     #$D,st0
ROM:0024                 mov     #1,st1
ROM:0026 ; assume page = 1
ROM:0026                 cntx    s
ROM:0027                 mov     #1,st0
ROM:0029                 mov     #0,st1
ROM:002B ; assume page = 0
ROM:002B                 mov     #$40,st2
ROM:002D                 cntx    r
ROM:002E                 mov     #$40,st2
ROM:0030                 mov     #0,cfgi
ROM:0032                 mov     #0,cfgj
ROM:0034                 mov     #$DD,a0
ROM:0036                 brr     loc_3E, eq
ROM:0037                 mov     #$C8DF,r0
ROM:0039                 mov     #$F955,r1
ROM:003B                 sub     #1,a0
ROM:003C                 rep     a0l
ROM:003D                 movp    (r0)+1,(r1)+1
ROM:003E
ROM:003E loc_3E:                                 ; CODE XREF: RESET_0+16↑j
ROM:003E                 call    sub_91
ROM:0040                 br      loc_CB
ROM:0040 ; End of function RESET_0
ROM:0040

80×86 Architecture : DOS Extender

Assembler code

00003F20
00003F20 ; =============== S U B R O U T I N E =======================================
00003F20
00003F20
00003F20                 public start
00003F20 start           proc far
00003F20                 call    sub_1050
00003F25                 or      eax, eax
00003F27                 jz      loc_3F3E
00003F2D                 lea     edx, large aDpmiServerInit ; "DPMI server initialization error -- out"...
00003F33                 mov     ah, 9
00003F35                 int     21h             ; DOS - PRINT STRING
00003F35                                         ; DS:DX -> string terminated by "$"
00003F37                 xor     eax, eax
00003F39                 jmp     locret_3F44
00003F3E ; ---------------------------------------------------------------------------
00003F3E
00003F3E loc_3F3E:                               ; CODE XREF: start+7↑j
00003F3E                 lea     eax, large SetVectors
00003F44
00003F44 locret_3F44:                            ; CODE XREF: start+19↑j
00003F44                 retf
00003F44 start           endp
00003F44
00003F44 _text           ends
00003F44
00003F44
00003F44                 end start

80×86 Architecture : Watcom Runtime

Assembler code

0010600C                 jmp     loc_105F29
00106011 ; ---------------------------------------------------------------------------
00106011
00106011 loc_106011:                             ; DATA XREF: .text:00105E2E↑o
00106011                 mov     edx, offset aNew ; "new"
00106016                 jmp     loc_105F29
0010601B ; ---------------------------------------------------------------------------
0010601B
0010601B loc_10601B:                             ; DATA XREF: .text:00105E66↑o
0010601B                 mov     edx, offset aNew_0 ; "new []"
00106020                 jmp     loc_105F29
00106025 ; ---------------------------------------------------------------------------
00106025
00106025 loc_106025:                             ; DATA XREF: .text:00105E32↑o
00106025                 mov     edx, offset aDelete ; "delete"
0010602A                 jmp     loc_105F29
0010602F ; ---------------------------------------------------------------------------
0010602F
0010602F loc_10602F:                             ; DATA XREF: .text:00105E62↑o
0010602F                 mov     edx, offset aDelete_0 ; "delete []"
00106034                 jmp     loc_105F29
00106039 ; ---------------------------------------------------------------------------
00106039
00106039 loc_106039:                             ; DATA XREF: .text:00105E36↑o
00106039                 movzx   edx, byte_10D7FC
00106040                 jmp     loc_105EC9
00106045 ; ---------------------------------------------------------------------------
00106045
00106045 loc_106045:                             ; DATA XREF: .text:00105E56↑o
00106045                 test    byte ptr [ecx+34h], 8
00106049                 jz      short loc_106052
0010604B                 mov     eax, ecx
0010604D                 call    sub_105D68
00106052
00106052 loc_106052:                             ; CODE XREF: .text:00106049↑j
00106052                 mov     edx, offset asc_10D83F ; "::"

80×86 Architecture: Geos APP

Assembler code

seg003:0244                     jmp     ObjMessage      ; Jump
seg003:0249     ; ---------------------------------------------------------------------------
seg003:0249
seg003:0249     loc_49_249:                             ; DATA XREF: seg001:0084↑o
seg003:0249                     push    ax
seg003:024A                     push    cx
seg003:024B                     push    dx
seg003:024C                     push    bp
seg003:024D                     call    ContactSIMNumber ; Call Procedure
seg003:0252                     mov     ax, 6181h
seg003:0255                     cmp     cx, dx          ; Compare Two Operands
seg003:0257                     jz      short loc_49_25C ; Jump if Zero (ZF=1)
seg003:0259                     mov     ax, 6180h
seg003:025C
seg003:025C     loc_49_25C:                             ; CODE XREF: seg003:0257↑j
seg003:025C                     push    dx
seg003:025D                     mov     bx, seg seg007
seg003:0260                     mov     si, 24h ; '$'
seg003:0263                     mov     di, 8000h
seg003:0266                     mov     dl, 2
seg003:0268                     call    ObjMessage      ; Call Procedure
seg003:026D                     pop     dx
seg003:026E                     mov     ax, 6181h
seg003:0271                     or      dx, dx          ; Logical Inclusive OR
seg003:0273                     jz      short loc_49_278 ; Jump if Zero (ZF=1)
seg003:0275                     mov     ax, 6180h
seg003:0278
seg003:0278     loc_49_278:                             ; CODE XREF: seg003:0273↑j
seg003:0278                     push    ax
seg003:0279                     mov     bx, seg seg007
seg003:027C                     mov     si, 48h ; 'H'
seg003:027F                     mov     di, 8000h
seg003:0282                     mov     dl, 2
seg003:0284                     call    ObjMessage      ; Call Procedure
seg003:0289                     pop     ax

80×86 Architecture: Geos DRV

Assembler code

seg003:0A36                 push    si
seg003:0A37                 push    di
seg003:0A38                 mov     [bp+var_C], 0
seg003:0A3D                 mov     [bp+fDocDir], 0
seg003:0A42                 call    FILEPUSHDIR     ; void pascal FilePushDir(void) in file.h
seg003:0A47                 test    byte_9E, 1
seg003:0A4C                 jz      short loc_410D
seg003:0A4E                 mov     [bp+fDocDir], 8
seg003:0A53                 push    [bp+fDocDir]    ; fDocDir
seg003:0A56                 call    FOAMSETDOCUMENTDIR ; void pascal FoamSetDocumentDir(FDocumentDir fDocDir) in foam.goh
seg003:0A5B                 jmp     short loc_411A
seg003:0A5D ; ---------------------------------------------------------------------------
seg003:0A5D
seg003:0A5D loc_410D:                               ; CODE XREF: sub_40E0+1C↑j
seg003:0A5D                 mov     [bp+var_C], 31h ; '1'
seg003:0A62                 push    [bp+var_C]      ; sp
seg003:0A65                 call    FILESETSTANDARDPATH ; void pascal FileSetStandardPath(StandardPath sp) in file.h
seg003:0A6A
seg003:0A6A loc_411A:                               ; CODE XREF: sub_40E0+2B↑j
seg003:0A6A                 push    0
seg003:0A6C                 push    0C800h
seg003:0A6F                 call    sub_5B83
seg003:0A74                 mov     [bp+var_16], ax
seg003:0A77                 cmp     [bp+var_16], 0
seg003:0A7B                 jz      short loc_419E
seg003:0A7D                 test    byte_9E, 1
seg003:0A82                 jz      short loc_4148
seg003:0A84                 push    word ptr [bp+name+2]
seg003:0A87                 push    word ptr [bp+name] ; name
seg003:0A8A                 call    FILEDELETE      ; word pascal FileDelete(const char *name) in file.h
seg003:0A8F                 les     bx, [bp+name]
seg003:0A92                 mov     byte ptr es:[bx], 0
seg003:0A96                 jmp     short loc_4188
seg003:0A98 ; ---------------------------------------------------------------------------
seg003:0A98
seg003:0A98 loc_4148:                               ; CODE XREF: sub_40E0+52↑j
seg003:0A98                 xor     si, si

80×86 Architecture: Geos LIB

Assembler code

seg001:02BA                 call    near ptr VisCheckIfVisGrown
seg001:02BD                 jnb     short loc_C3B
seg001:02BF                 push    di
seg001:02C0                 push    es
seg001:02C1                 mov     di, seg seg087
seg001:02C4                 mov     es, di
seg001:02C6                 assume es:seg087
seg001:02C6                 mov     di, 1548h
seg001:02C9                 call    ObjIsObjectInClass
seg001:02CE                 pop     es
seg001:02CF                 assume es:nothing
seg001:02CF                 pop     di
seg001:02D0                 jb      short loc_C1A
seg001:02D2                 call    FatalError
seg001:02D7                 mov     ax, 31h ; '1'
seg001:02DA
seg001:02DA loc_C1A:                                ; CODE XREF: GenClass_24967+2F↑j
seg001:02DA                 mov     di, [si]
seg001:02DC                 add     di, [di+4]
seg001:02DF                 test    byte ptr [di+9], 1
seg001:02E3                 jz      short loc_C3B
seg001:02E5                 push    cx
seg001:02E6                 mov     cx, 0FFFFh
seg001:02E9                 push    cs
seg001:02EA                 call    near ptr GenClass_24967
seg001:02ED                 pop     cx
seg001:02EE                 jb      short loc_C38
seg001:02F0                 call    FatalError
seg001:02F5                 mov     ax, 31h ; '1'
seg001:02F8
seg001:02F8 loc_C38:                                ; CODE XREF: GenClass_24967+4D↑j
seg001:02F8                 stc
seg001:02F9                 jnz     short loc_C60
seg001:02FB
seg001:02FB loc_C3B:                                ; CODE XREF: GenClass_24967+16↑j
seg001:02FB                                         ; GenClass_24967+1C↑j ...
seg001:02FB                 mov     ax, si

80×86 Architecture: GNU COFF Format

Assembler code

.text:00000178
.text:00000178 loc_178:                                ; CODE XREF: XDPSCreateStandardColormaps+53↑j
.text:00000178                 test    esi, esi
.text:0000017A                 jnz     short loc_19C
.text:0000017C                 lea     eax, [ebp+var_84]
.text:00000182                 push    eax
.text:00000183                 push    [ebp+arg_4]
.text:00000186                 push    [ebp+arg_0]
.text:00000189                 call    XGetWindowAttributes
.text:0000018E                 add     esp, 0Ch
.text:00000191                 test    eax, eax
.text:00000193                 jz      loc_21C
.text:00000199                 mov     esi, [ebp+var_6C]
.text:0000019C
.text:0000019C loc_19C:                                ; CODE XREF: XDPSCreateStandardColormaps+57↑j
.text:0000019C                                         ; XDPSCreateStandardColormaps+62↑j
.text:0000019C                 cmp     dword ptr [edi], 0
.text:0000019F                 jnz     short loc_1A7
.text:000001A1                 cmp     [ebp+arg_4], 0
.text:000001A5                 jz      short loc_21C
.text:000001A7
.text:000001A7 loc_1A7:                                ; CODE XREF: XDPSCreateStandardColormaps+87↑j
.text:000001A7                 push    [ebp+arg_0]
.text:000001AA                 call    FindDpyRec
.text:000001AF                 mov     large ds:75E4h, eax
.text:000001B4                 add     esp, 4
.text:000001B7                 test    eax, eax
.text:000001B9                 jz      loc_570
.text:000001BF                 push    esi
.text:000001C0                 call    XVisualIDFromVisual
.text:000001C5                 mov     [ebp+var_24], eax
.text:000001C8                 lea     eax, [ebp+var_88]
.text:000001CE                 push    eax
.text:000001CF                 lea     eax, [ebp+var_28]
.text:000001D2                 push    eax

80×86 Architecture: OS/2 Linear Executable Format

Assembler code

cseg01:000102E1                 lea     eax, [ebp+var_44]
cseg01:000102E4                 push    5
cseg01:000102E6                 push    eax
cseg01:000102E7                 push    esi
cseg01:000102E8                 call    WinFillRect
cseg01:000102ED                 add     esp, 0Ch
cseg01:000102F0                 mov     [ebp+var_38], 0FAh ; 'ú'
cseg01:000102F7                 mov     [ebp+var_40], 0E9h ; 'é'
cseg01:000102FE                 lea     eax, [ebp+var_84]
cseg01:00010304                 push    eax
cseg01:00010305                 push    40h ; '@'
cseg01:00010307                 push    2Bh ; '+'
cseg01:00010309                 push    0
cseg01:0001030B                 push    dword_20874
cseg01:00010311                 call    WinLoadString
cseg01:00010316                 add     esp, 14h
cseg01:00010319                 lea     eax, [ebp+var_84]
cseg01:0001031F                 lea     edx, [ebp+var_44]
cseg01:00010322                 push    100h
cseg01:00010327                 push    0
cseg01:00010329                 push    0FFFFFFFFh
cseg01:0001032B                 push    edx
cseg01:0001032C                 push    eax
cseg01:0001032D                 push    0FFFFFFFFh
cseg01:0001032F                 push    esi
cseg01:00010330                 call    WinDrawText
cseg01:00010335                 add     esp, 1Ch
cseg01:00010338                 push    esi
cseg01:00010339                 call    WinEndPaint
cseg01:0001033E                 add     esp, 4
cseg01:00010341                 mov     eax, 1
cseg01:00010346                 pop     esi
cseg01:00010347                 pop     edi
cseg01:00010348                 pop     ebx
cseg01:00010349                 leave

80×86 Architecture: Netware NLM

Assembler code

.bss:000000CA
.bss:000000CA loc_CA:                                 ; CODE XREF: nlm_start+33↑j
.bss:000000CA                                         ; nlm_start+A1↑j ...
.bss:000000CA                 mov     dword_E150, edi
.bss:000000D0                 push    54524C41h
.bss:000000D5                 push    offset aAllocMemory ; "Alloc Memory"
.bss:000000DA                 push    edi
.bss:000000DB                 call    AllocateResourceTag
.bss:000000E0                 mov     dword_E018, eax
.bss:000000E5                 push    544D4E43h
.bss:000000EA                 push    offset aNonMovableMemo ; "Non Movable Memory"
.bss:000000EF                 push    edi
.bss:000000F0                 call    AllocateResourceTag
.bss:000000F5                 mov     dword_E020, eax
.bss:000000FA                 push    53435250h
.bss:000000FF                 push    offset aProcesses ; "Processes"
.bss:00000104                 push    edi
.bss:00000105                 call    AllocateResourceTag
.bss:0000010A                 mov     dword_E15C, eax
.bss:0000010F                 push    4C4B5344h
.bss:00000114                 push    offset aDiskLocks ; "Disk Locks"
.bss:00000119                 push    edi
.bss:0000011A                 call    AllocateResourceTag
.bss:0000011F                 mov     dword_E01C, eax
.bss:00000124                 push    4E524353h
.bss:00000129                 push    offset aScreens ; "Screens"
.bss:0000012E                 push    edi
.bss:0000012F                 call    AllocateResourceTag
.bss:00000134                 add     esp, 3Ch
.bss:00000137                 mov     dword_E158, eax
.bss:0000013C                 push    504D4553h
.bss:00000141                 push    offset aSemaphores ; "Semaphores"
.bss:00000146                 push    edi
.bss:00000147                 call    AllocateResourceTag
.bss:0000014C                 mov     dword_E160, eax

80×86 Architecture: QNX Executable

Assembler code

cseg_01:0000A3A1                 mov     [ebp-8], edx
cseg_01:0000A3A4                 mov     edx, 0Eh
cseg_01:0000A3A9                 call    __setmagicvar_
cseg_01:0000A3AE                 mov     eax, cs
cseg_01:0000A3B0                 mov     edx, 0Dh
cseg_01:0000A3B5                 mov     [ebp-8], ax
cseg_01:0000A3B9                 lea     eax, [ebp-8]
cseg_01:0000A3BC                 mov     ebx, 0A34Ah
cseg_01:0000A3C1                 call    __setmagicvar_
cseg_01:0000A3C6                 mov     eax, 1
cseg_01:0000A3CB                 mov     off_C304, ebx
cseg_01:0000A3D1                 call    __InitRtns
cseg_01:0000A3D6                 mov     eax, dword_C314
cseg_01:0000A3DB                 add     eax, 3
cseg_01:0000A3DE                 and     al, 0FCh
cseg_01:0000A3E0                 xor     edx, edx
cseg_01:0000A3E2                 sub     esp, eax
cseg_01:0000A3E4                 mov     ecx, esp
cseg_01:0000A3E6                 mov     ebx, dword_C314
cseg_01:0000A3EC                 mov     eax, ecx
cseg_01:0000A3EE                 call    memset_
cseg_01:0000A3F3                 mov     eax, ecx
cseg_01:0000A3F5                 mov     edx, [ebp-4]
cseg_01:0000A3F8                 call    __QNXInit_
cseg_01:0000A3FD                 mov     ebx, esi
cseg_01:0000A3FF                 mov     eax, 0FFh
cseg_01:0000A404                 mov     ecx, 2000h
cseg_01:0000A409                 call    __InitRtns
cseg_01:0000A40E                 mov     dword_C318, ecx
cseg_01:0000A414                 mov     eax, edi
cseg_01:0000A416                 push    ds
cseg_01:0000A417                 pop     es
cseg_01:0000A418                 assume es:dseg_01
cseg_01:0000A418                 call    sub_A010
cseg_01:0000A41D                 call    exit_

80×86 Architecture: Watcom Runtime

Assembler code

cseg01:1044
cseg01:1044 ; =============== S U B R O U T I N E =======================================
cseg01:1044
cseg01:1044 ; Attributes: library function
cseg01:1044
cseg01:1044 __MemFree       proc far                ; CODE XREF: _ffree_+1A↓p
cseg01:1044                                         ; _nfree_+31↓p ...
cseg01:1044
cseg01:1044 ; FUNCTION CHUNK AT cseg01:1041 SIZE 00000003 BYTES
cseg01:1044
cseg01:1044                 push    si
cseg01:1045                 push    di
cseg01:1046                 push    cx
cseg01:1047                 push    ds
cseg01:1048                 mov     ds, dx
cseg01:104A                 or      ax, ax
cseg01:104C                 jz      short loc_1041
cseg01:104E                 mov     si, ax
cseg01:1050                 sub     si, 2
cseg01:1053                 mov     ax, [si]
cseg01:1055                 test    al, 1
cseg01:1057                 jz      short loc_1041
cseg01:1059                 and     al, 0FEh
cseg01:105B                 mov     di, si
cseg01:105D                 add     di, ax
cseg01:105F                 test    word ptr [di], 1
cseg01:1063                 jnz     short loc_1084
cseg01:1065                 cmp     di, [bx+6]
cseg01:1068                 jnz     short loc_106D
cseg01:106A                 mov     [bx+6], si
cseg01:106D
cseg01:106D loc_106D:                               ; CODE XREF: __MemFree+24↑j
cseg01:106D                 add     ax, [di]
cseg01:106F                 mov     [si], ax
cseg01:1071                 push    bx

80×86 Architecture: Windows OMF

Assembler code

VIRDEF01:00000020 ; VIRDEF, segment _TEXT
VIRDEF01:00000020 ; NOTE: VIRDEF records cannot be represented in assembly!
VIRDEF01:00000020 ; ===========================================================================
VIRDEF01:00000020
VIRDEF01:00000020 ; Segment type: Pure code
VIRDEF01:00000020 VIRDEF01        segment dword public 'CODE' use32
VIRDEF01:00000020                 assume cs:VIRDEF01
VIRDEF01:00000020                 ;org 20h
VIRDEF01:00000020                 assume es:nothing, ss:nothing, ds:DGROUP, fs:nothing, gs:nothing
VIRDEF01:00000020
VIRDEF01:00000020 ; =============== S U B R O U T I N E =======================================
VIRDEF01:00000020
VIRDEF01:00000020 ; Attributes: bp-based frame
VIRDEF01:00000020
VIRDEF01:00000020                 public lread
VIRDEF01:00000020 lread           proc near
VIRDEF01:00000020
VIRDEF01:00000020 arg_0           = dword ptr  8
VIRDEF01:00000020 arg_4           = dword ptr  0Ch
VIRDEF01:00000020 arg_8           = dword ptr  10h
VIRDEF01:00000020
VIRDEF01:00000020                 push    ebp
VIRDEF01:00000021                 mov     ebp, esp
VIRDEF01:00000023                 push    ebx
VIRDEF01:00000024                 mov     ebx, [ebp+arg_8]
VIRDEF01:00000027                 push    ebx
VIRDEF01:00000028                 push    [ebp+arg_4]
VIRDEF01:0000002B                 push    [ebp+arg_0]
VIRDEF01:0000002E                 call    qlread
VIRDEF01:00000033                 cmp     ebx, eax
VIRDEF01:00000035                 jz      short loc_10072
VIRDEF01:00000037                 push    offset aReadError ; "read error\n"
VIRDEF01:0000003C                 call    @error$qpxce    ; error(char *,...)
VIRDEF01:00000041                 pop     ecx
VIRDEF01:00000042
VIRDEF01:00000042 loc_10072:                              ; CODE XREF: lread+15↑j
VIRDEF01:00000042                 pop     ebx

80×86 Architecture: Windows Portable Executable Format

Assembler code

.text:00401236
.text:00401236 ; =============== S U B R O U T I N E =======================================
.text:00401236
.text:00401236 ; Attributes: bp-based frame
.text:00401236
.text:00401236 ; void __cdecl sub_401236()
.text:00401236 sub_401236      proc near               ; DATA XREF: start+DB↑o
.text:00401236
.text:00401236 var_1C          = dword ptr -1Ch
.text:00401236 ms_exc          = CPPEH_RECORD ptr -18h
.text:00401236
.text:00401236 ; __unwind { // __SEH_prolog
.text:00401236                 push    0Ch
.text:00401238                 push    offset stru_402078
.text:0040123D                 call    __SEH_prolog
.text:00401242                 mov     [ebp+var_1C], offset unk_4020E0
.text:00401249
.text:00401249 loc_401249:                             ; CODE XREF: sub_401236+3C↓j
.text:00401249                 cmp     [ebp+var_1C], offset unk_4020E0
.text:00401250                 jnb     short loc_401274
.text:00401252 ;   __try { // __except at loc_401267
.text:00401252                 and     [ebp+ms_exc.registration.TryLevel], 0
.text:00401256                 mov     eax, [ebp+var_1C]
.text:00401259                 mov     eax, [eax]
.text:0040125B                 test    eax, eax
.text:0040125D                 jz      short loc_40126A
.text:0040125F                 call    eax
.text:00401261                 jmp     short loc_40126A
.text:00401263 ; ---------------------------------------------------------------------------
.text:00401263
.text:00401263 loc_401263:                             ; DATA XREF: .rdata:stru_402078↓o
.text:00401263 ;   __except filter // owned by 401252
.text:00401263                 xor     eax, eax
.text:00401265                 inc     eax
.text:00401266                 retn

80×86 Architecture: Windows Virtual Device Driver

Assembler code

ICOD:C001A45F
ICOD:C001A45F loc_C001A45F:                           ; CODE XREF: Locate_Byte_In_ROM+D↑j
ICOD:C001A45F                 xor     esi, esi
ICOD:C001A461                 mov     edi, offset aSystemrombreak ; "SystemRomBreakPoint"
ICOD:C001A466                 VMMCall Get_Profile_Boolean
ICOD:C001A46C                 test    eax, eax
ICOD:C001A46E                 jz      short loc_C001A495
ICOD:C001A470                 mov     al, 73h ; 's'
ICOD:C001A472                 VMMCall Get_Debug_Options
ICOD:C001A478                 jz      short loc_C001A495
ICOD:C001A47A                 mov     edi, 0FFFEFh
ICOD:C001A47F                 mov     ecx, 3FF0h
ICOD:C001A484                 mov     eax, [esp+20h+var_4]
ICOD:C001A488                 std
ICOD:C001A489                 repne scasb
ICOD:C001A48B                 jnz     short loc_C001A495
ICOD:C001A48D                 inc     edi
ICOD:C001A48E                 mov     [esp+20h+var_4], edi
ICOD:C001A492                 clc
ICOD:C001A493                 jmp     short loc_C001A496
ICOD:C001A495 ; ---------------------------------------------------------------------------
ICOD:C001A495
ICOD:C001A495 loc_C001A495:                           ; CODE XREF: Locate_Byte_In_ROM+23↑j
ICOD:C001A495                                         ; Locate_Byte_In_ROM+2D↑j ...
ICOD:C001A495                 stc
ICOD:C001A496
ICOD:C001A496 loc_C001A496:                           ; CODE XREF: Locate_Byte_In_ROM+48↑j
ICOD:C001A496                 cld
ICOD:C001A497                 popa
ICOD:C001A498                 retn
ICOD:C001A498 Locate_Byte_In_ROM endp
ICOD:C001A498
ICOD:C001A499 ; ---------------------------------------------------------------------------
ICOD:C001A499
ICOD:C001A499 loc_C001A499:                           ; CODE XREF: start+756↓p
ICOD:C001A499                 push    ebx

80×86 Architecture : Windows 16 bits DLL

Assembler code

cseg07:039A                 add     sp, 8
cseg07:039D
cseg07:039D loc_80E_39D:                            ; CODE XREF: @BMPCAPWN@0WMCREATE$QM8TMESSAGE+8D↑j
cseg07:039D                 les     bx, [bp+arg_2]
cseg07:03A0                 les     bx, es:[bx+5Ch]
cseg07:03A4                 push    word ptr es:[bx+0Ah] ; HWND
cseg07:03A8                 push    ss
cseg07:03A9                 lea     ax, [bp+LPCSTR]
cseg07:03AC                 push    ax              ; LPSTR
cseg07:03AD                 mov     ax, 50h ; 'P'
cseg07:03B0                 push    ax              ; int
cseg07:03B1                 call    GETWINDOWTEXT
cseg07:03B6                 les     bx, [bp+arg_2]
cseg07:03B9                 push    word ptr es:[bx+0Ah] ; HWND
cseg07:03BD                 push    ss
cseg07:03BE                 lea     ax, [bp+LPCSTR]
cseg07:03C1                 push    ax              ; LPCSTR
cseg07:03C2                 call    SETWINDOWTEXT
cseg07:03C7                 push    ss
cseg07:03C8                 lea     ax, [bp+var_12]
cseg07:03CB                 push    ax
cseg07:03CC                 call    sub_240_AEA
cseg07:03D1                 add     sp, 4
cseg07:03D4                 les     bx, [bp+arg_2]
cseg07:03D7                 les     bx, es:[bx+5Ch]
cseg07:03DB                 cmp     word ptr es:[bx+0Ah], 0
cseg07:03E0                 jz      short loc_80E_3FA
cseg07:03E2                 les     bx, [bp+arg_2]
cseg07:03E5                 les     bx, es:[bx+5Ch]
cseg07:03E9                 push    word ptr es:[bx+0Ah]
cseg07:03ED                 push    ss
cseg07:03EE                 lea     ax, [bp+var_12]
cseg07:03F1                 push    ax
cseg07:03F2                 nop
cseg07:03F3                 push    cs

X-Box Disassembler

Assembler code

.text:00402E61
.text:00402E61     loc_402E61:                             ; CODE XREF: sub_402DC4+8C↑j
.text:00402E61                                             ; sub_402DC4+98↑j
.text:00402E61 218                 lea     edi, [ebp+var_20C]
.text:00402E67 218                 or      ecx, 0FFFFFFFFh
.text:00402E6A 218                 xor     eax, eax
.text:00402E6C 218                 mov     esi, offset asc_401634 ; ")"
.text:00402E71 218                 repne scasb
.text:00402E73 218                 dec     edi
.text:00402E74 218                 movsw
.text:00402E76 218                 jmp     short loc_402E8E
.text:00402E78     ; ---------------------------------------------------------------------------
.text:00402E78
.text:00402E78     loc_402E78:                             ; CODE XREF: sub_402DC4+55↑j
.text:00402E78 218                 push    esi
.text:00402E79 21C                 push    offset aS       ; "%s"
.text:00402E7E
.text:00402E7E     loc_402E7E:                             ; CODE XREF: sub_402DC4+31↑j
.text:00402E7E 220                 lea     eax, [ebp+var_20C]
.text:00402E84 220                 push    eax
.text:00402E85 224                 call    ds:sprintf
.text:00402E8B 224                 add     esp, 0Ch
.text:00402E8E
.text:00402E8E     loc_402E8E:                             ; CODE XREF: sub_402DC4+B2↑j
.text:00402E8E 218                 mov     ecx, [ebp+var_4]
.text:00402E91 218                 lea     eax, [ebp+var_20C]
.text:00402E97 218                 push    eax             ; const char *
.text:00402E98 21C                 call    sub_402EA3
.text:00402E9D 218                 pop     edi
.text:00402E9E 214                 pop     esi
.text:00402E9F 210                 leave
.text:00402EA0 000                 retn    8
.text:00402EA0     sub_402DC4      endp
.text:00402EA0
.text:00402EA3
.text:00402EA3     ; =============== S U B R O U T I N E =======================================
.text:00402EA3
.text:00402EA3
.text:00402EA3     ; int __cdecl sub_402EA3(const char *)
.text:00402EA3     sub_402EA3      proc near               ; CODE XREF: sub_402DC4+D4↑p
.text:00402EA3                                             ; sub_4030B2:loc_403381↓p
.text:00402EA3
.text:00402EA3     arg_0           = dword ptr  8
.text:00402EA3
.text:00402EA3 000                 push    esi

PDP 11 : SAV File

Assembler code

seg001:002556
seg001:002556 ; =============== S U B R O U T I N E =======================================
seg001:002556
seg001:002556
seg001:002556                 .globl start
seg001:002556 start:                                  ; DATA XREF: asect:000040↑o
seg001:002556
seg001:002556 ; FUNCTION CHUNK AT seg001:001016 SIZE 00000158 BYTES
seg001:002556 ; FUNCTION CHUNK AT seg001:002742 SIZE 00000014 BYTES
seg001:002556
seg001:002556                 inc     word_1012
seg001:002562                 mov     word_1012, word_2554
seg001:002570                 call    sub_2640
seg001:002574                 mov     #700, R0
seg001:002600                 emt     351             ; .PRINT - Print String to Terminal
seg001:002602                 mov     #715, R0
seg001:002606                 emt     351             ; .PRINT - Print String to Terminal
seg001:002610                 jmp     loc_1016
seg001:002614 ; ---------------------------------------------------------------------------
seg001:002614
seg001:002614 loc_2614:                               ; CODE XREF: start:loc_1542↑J
seg001:002614                 mov     word_1014, word_2554
seg001:002622                 call    sub_2640
seg001:002626                 mov     #702, R0
seg001:002632                 emt     351             ; .PRINT - Print String to Terminal
seg001:002634                 clr     R0
seg001:002636                 emt     350             ; .EXIT - Terminate Program
seg001:002636 ; End of function start
seg001:002636
seg001:002640
seg001:002640 ; =============== S U B R O U T I N E =======================================
seg001:002640
seg001:002640
seg001:002640 sub_2640:                               ; CODE XREF: start+12↑P
seg001:002640                                         ; start+44↑P
seg001:002640                 mov     #57, R1 ; '/'

PIC

Assembler code

CODE:0004
CODE:0004 ; =============== S U B R O U T I N E =======================================
CODE:0004
CODE:0004 ; Interrupt Vector
CODE:0004
CODE:0004                 ; public ISR
CODE:0004 ISR:
CODE:0004                 movlp   0
CODE:0005                 btfss   BANK0:INTCON, T0IF
CODE:0006                  b       loc_CODE_8
CODE:0007                 b       loc_CODE_9
CODE:0008 ; ---------------------------------------------------------------------------
CODE:0008
CODE:0008 loc_CODE_8:                             ; CODE XREF: ISR+2↑j
CODE:0008                 b       loc_CODE_1A
CODE:0009 ; ---------------------------------------------------------------------------
CODE:0009
CODE:0009 loc_CODE_9:                             ; CODE XREF: ISR+3↑j
CODE:0009                 movlb   0
CODE:000A                 movfw   byte_DATA_24
CODE:000B                 xorlw   3
CODE:000C                 bnz     loc_CODE_F
CODE:000E                 b       loc_CODE_10
CODE:000F ; ---------------------------------------------------------------------------
CODE:000F
CODE:000F loc_CODE_F:                             ; CODE XREF: ISR+8↑j
CODE:000F                 b       loc_CODE_14
CODE:0010 ; ---------------------------------------------------------------------------
CODE:0010
CODE:0010 loc_CODE_10:                            ; CODE XREF: ISR+A↑j
CODE:0010                 movlp   5
CODE:0011 ; assume pclath = 5
CODE:0011                 call    sub_CODE_516
CODE:0012                 movlp   0
CODE:0013 ; assume pclath = 0
CODE:0013                 b       loc_CODE_14

PIC 12xx

Assembler code

CODE:0011 ; assume bank = 0
CODE:0011
CODE:0011 ; =============== S U B R O U T I N E =======================================
CODE:0011
CODE:0011
CODE:0011 sub_CODE_11:                            ; CODE XREF: RESET+189↓p
CODE:0011                 comf    BANK0:R9, w
CODE:0012                 xorwf   BANK0:R10, w
CODE:0013                 xorwf   BANK0:R11, w
CODE:0014                 movwf   BANK0:R15
CODE:0015                 call    sub_CODE_4
CODE:0016                 movwf   BANK0:R6
CODE:0017                 btfsc   BANK0:R5, 1
CODE:0018                  swapf   BANK0:R6, w
CODE:0019                 xorwf   BANK0:R15, f
CODE:001A                 comf    BANK0:R12, w
CODE:001B                 xorwf   BANK0:R13, w
CODE:001C                 xorwf   BANK0:R14, w
CODE:001D                 movwf   BANK0:R16
CODE:001E                 call    sub_CODE_5
CODE:001F                 movwf   BANK0:R6
CODE:0020                 btfsc   BANK0:R5, 0
CODE:0021                  swapf   BANK0:R6, w
CODE:0022                 xorwf   BANK0:R16, f
CODE:0023                 retlw   0
CODE:0023 ; End of function sub_CODE_11
CODE:0023
CODE:0024
CODE:0024 ; =============== S U B R O U T I N E =======================================
CODE:0024
CODE:0024
CODE:0024 sub_CODE_24:                            ; CODE XREF: RESET+C2↓p
CODE:0024                                         ; RESET+D7↓p ...
CODE:0024                 comf    BANK0:R9, w
CODE:0025                 xorlw   17

Power PC AIF ECOFF file Format

Assembler code

.text:00002054
.text:00002054 # =============== S U B R O U T I N E =======================================
.text:00002054
.text:00002054
.text:00002054 bpf_tap:
.text:00002054
.text:00002054 .set sender_sp, -0x50
.text:00002054 .set var_C, -0xC
.text:00002054 .set var_8, -8
.text:00002054 .set var_4, -4
.text:00002054 .set sender_lr,  8
.text:00002054
.text:00002054                 stw       r31, var_4(r1)
.text:00002058                 lwz       r31, 4(r3)
.text:0000205C                 mr        r6, r5
.text:00002060                 mflr      r0
.text:00002064                 cmpwi     r31, 0
.text:00002068                 lwz       r3, 0x28(r31)
.text:0000206C                 stw       r0, sender_lr(r1)
.text:00002070                 stwu      r1, sender_sp(r1)
.text:00002074                 addi      r0, r3, 1
.text:00002078                 stw       r5, 0x50+var_C(r1)
.text:0000207C                 lwz       r3, 0x24(r31)
.text:00002080                 stw       r4, 0x50+var_8(r1)
.text:00002084                 beq       loc_20EC
.text:00002088                 stw       r0, 0x28(r31)
.text:0000208C
.text:0000208C loc_208C:                               # CODE XREF: bpf_tap+80↓j
.text:0000208C                 bl        bpf_filter
.text:00002090                 nop
.text:00002094                 mr.       r6, r3
.text:00002098                 mr        r3, r31
.text:0000209C                 lwz       r4, 0x50+var_8(r1)
.text:000020A0                 lwz       r5, 0x50+var_C(r1)
.text:000020A4                 lwz       r7, off_4178  # off_40B4

Power PC Linux ELF

Assembler code

.text:01802348
.text:01802348 # =============== S U B R O U T I N E =======================================
.text:01802348
.text:01802348 # Attributes: noreturn
.text:01802348
.text:01802348 sub_1802348:                            # CODE XREF: sub_1802F9C:def_18030F4↓p
.text:01802348                                         # sub_1802F9C+2F4↓p
.text:01802348
.text:01802348 .set back_chain, -0x10
.text:01802348 .set var_8, -8
.text:01802348 .set var_4, -4
.text:01802348 .set sender_lr,  4
.text:01802348
.text:01802348                 stwu      r1, back_chain(r1)
.text:0180234C                 mflr      r0
.text:01802350                 stw       r30, 0x10+var_8(r1)
.text:01802354                 stw       r31, 0x10+var_4(r1)
.text:01802358                 stw       r0, 0x10+sender_lr(r1)
.text:0180235C                 bl        loc_1802360
.text:01802360
.text:01802360 loc_1802360:                            # DATA XREF: .text:off_1802344↑o
.text:01802360                 mflr      r30
.text:01802364                 lwz       r0, (off_1802344 - loc_1802360)(r30)
.text:01802368                 add       r30, r0, r30
.text:0180236C                 lwz       r3, (off_185CF04 - 0x1864F00)(r30) # _IO_stderr_ # stream
.text:01802370                 lwz       r9, (off_185CF00 - 0x1864F00)(r30) # off_185DE7C
.text:01802374                 lwz       r4, (off_185CF08 - 0x1864F00)(r30) # "Usage: %s [-panyrcdfvstFSV] [-b superbl"...
.text:01802378                 lwz       r5, (off_185DE7C - 0x185DE7C)(r9) # "e2fsck"
.text:0180237C                 bl        .fprintf
.text:01802380                 li        r3, 0x10      # status
.text:01802384                 bl        .exit
.text:01802384 # End of function sub_1802348
.text:01802384
.text:01802384 # ---------------------------------------------------------------------------
.text:01802388 off_1802388:    .long off_185CF00+0x8000 - loc_18023B0
.text:01802388                                         # DATA XREF: sub_180238C+28↓r

Mac OS PEF File

Assembler code

seg000:00002BDC
seg000:00002BDC # =============== S U B R O U T I N E =======================================
seg000:00002BDC
seg000:00002BDC # Attributes: noreturn
seg000:00002BDC
seg000:00002BDC                 .globl .start
seg000:00002BDC .start:                                 # DATA XREF: seg000:00003A60↓o
seg000:00002BDC                                         # seg001:start↓o
seg000:00002BDC
seg000:00002BDC .set sender_sp, -0x450
seg000:00002BDC .set saved_toc, -0x43C
seg000:00002BDC .set var_20, -0x20
seg000:00002BDC .set var_C, -0xC
seg000:00002BDC .set var_8, -8
seg000:00002BDC .set var_4, -4
seg000:00002BDC .set sender_lr,  8
seg000:00002BDC
seg000:00002BDC                 mflr      r0
seg000:00002BE0                 stw       r31, var_4(r1)
seg000:00002BE4                 stw       r30, var_8(r1)
seg000:00002BE8                 stw       r29, var_C(r1)
seg000:00002BEC                 stw       r0, sender_lr(r1)
seg000:00002BF0                 stwu      r1, sender_sp(r1)
seg000:00002BF4                 mr        r29, r3
seg000:00002BF8                 mr        r30, r4
seg000:00002BFC                 mr        r31, r5
seg000:00002C00                 lwz       r3, TC_argv_save # argv_save
seg000:00002C04                 cmplwi    r31, 0
seg000:00002C08                 lwz       r4, TC_environ # environ
seg000:00002C0C                 stw       r30, 0(r3)
seg000:00002C10                 stw       r31, 0(r4)
seg000:00002C14                 bne       loc_2C20
seg000:00002C18                 addi      r0, r2, (off_3E44 - 0x3A70) # "NO_ENVIRON=true"
seg000:00002C1C                 stw       r0, 0(r4)
seg000:00002C20
seg000:00002C20 loc_2C20:                               # CODE XREF: .start+38↑j
seg000:00002C20                 li        r3, 0

Mac OS X File

Assembler code

__text:000036F8
__text:000036F8 # =============== S U B R O U T I N E =======================================
__text:000036F8
__text:000036F8
__text:000036F8 sub_36F8:                               # CODE XREF: sub_3578:loc_3610↑p
__text:000036F8
__text:000036F8 .set sender_sp, -0x60
__text:000036F8 .set var_20, -0x20
__text:000036F8 .set var_4, -4
__text:000036F8 .set sender_lr,  8
__text:000036F8
__text:000036F8                 mflr      r0
__text:000036FC                 stw       r31, var_4(r1)
__text:00003700                 stw       r0, sender_lr(r1)
__text:00003704                 stwu      r1, sender_sp(r1)
__text:00003708                 bcl       20, 4*cr7+so, loc_370C
__text:0000370C
__text:0000370C loc_370C:
__text:0000370C                 mflr      r31
__text:00003710                 addis     r3, r31, (aDyldMakeDelaye - loc_370C)@ha
__text:00003714                 addi      r3, r3, (aDyldMakeDelaye - loc_370C)@l # "__dyld_make_delayed_module_initializer_"...
__text:00003718                 addi      r4, r1, 0x60+var_20
__text:0000371C                 bl        sub_3794
__text:00003720                 lwz       r12, 0x60+var_20(r1)
__text:00003724                 mtctr     r12
__text:00003728                 bctrl
__text:0000372C                 lwz       r0, 0x60+sender_lr(r1)
__text:00003730                 addi      r1, r1, 0x60
__text:00003734                 mtlr      r0
__text:00003738                 lwz       r31, var_4(r1)
__text:0000373C                 blr
__text:0000373C # End of function sub_36F8
__text:0000373C
__text:00003740
__text:00003740 # =============== S U B R O U T I N E =======================================
__text:00003740
__text:00003740
__text:00003740 sub_3740:                               # CODE XREF: sub_3578+24↑p
__text:00003740                 lis       r11, dword_140A0@ha

Windows NT PE File

Assembler code

.text:00011FE0
.text:00011FE0 # =============== S U B R O U T I N E =======================================
.text:00011FE0
.text:00011FE0
.text:00011FE0 sub_11FE0:                              # DATA XREF: .text:off_10464↑o
.text:00011FE0                                         # .pdata:00012B44↓o ...
.text:00011FE0
.text:00011FE0 .set sender_sp, -0xB0
.text:00011FE0 .set var_78, -0x78
.text:00011FE0 .set var_70, -0x70
.text:00011FE0 .set var_60, -0x60
.text:00011FE0 .set var_58, -0x58
.text:00011FE0 .set var_50, -0x50
.text:00011FE0 .set var_44, -0x44
.text:00011FE0 .set sender_lr,  8
.text:00011FE0
.text:00011FE0 # FUNCTION CHUNK AT .text:0001257C SIZE 000000B0 BYTES
.text:00011FE0 # FUNCTION CHUNK AT .text:00012834 SIZE 00000038 BYTES
.text:00011FE0
.text:00011FE0                 stw       r15, var_44(r1)
.text:00011FE4                 mflr      r15
.text:00011FE8                 bl        _save32gpr_16
.text:00011FEC                 mr        r27, r3
.text:00011FF0                 mr        r23, r4
.text:00011FF4                 stw       r2, sender_lr(r1)
.text:00011FF8                 stwu      r1, sender_sp(r1)
.text:00011FFC
.text:00011FFC loc_11FFC:                              # DATA XREF: .pdata:00012B58↓o
.text:00011FFC                 lwz       r10, 0x60(r23)
.text:00012000                 lis       r11, 7
.text:00012004                 mr        r21, r10
.text:00012008                 lwz       r9, 0xC(r21)
.text:0001200C                 ori       r11, r11, 0x14 # 0x70014
.text:00012010                 cmplw     cr1, r9, r11
.text:00012014                 lwz       r24, 0x28(r27)

Hitachi SH-1 Processor

Assembler code

seg001:0A227704                 cmp/eq  #1, r0          ; Compare: Equal
seg001:0A227706                 bf      loc_A227718     ; Branch if False
seg001:0A227708                 mov.l   #h'210907D, r3  ; Move Immediate Long Data
seg001:0A22770A                 mov.b   @r3, r2         ; Move Byte Data
seg001:0A22770C                 tst     r2, r2          ; Test Logical
seg001:0A22770E                 bf      loc_A227718     ; Branch if False
seg001:0A227710                 mov.l   #h'210907D, r1  ; Move Immediate Long Data
seg001:0A227712                 mov.l   #h'A23C5E0, r3  ; Move Immediate Long Data
seg001:0A227714                 jsr     @r3 ; sub_A23C5E0 ; Jump to Subroutine
seg001:0A227716                 mov.b   r10, @r1        ; Move Byte Data
seg001:0A227718
seg001:0A227718 loc_A227718:                            ; CODE XREF: sub_A227018+6EE↑j
seg001:0A227718                                         ; sub_A227018+6F6↑j
seg001:0A227718                 mov     r8, r0          ; Move Data
seg001:0A22771A                 mov.b   @(9,r0), r0     ; Move Structure Byte Data
seg001:0A22771C                 tst     #h'10, r0       ; Test Logical
seg001:0A22771E                 movt    r0              ; Move T Bit
seg001:0A227720                 add     #-1, r0         ; Add binary
seg001:0A227722                 neg     r0, r0          ; Negate
seg001:0A227724                 cmp/eq  #1, r0          ; Compare: Equal
seg001:0A227726                 bt      loc_A22772C     ; Branch if True
seg001:0A227728                 bra     loc_A2278AE     ; Branch
seg001:0A22772A                 nop                     ; No Operation
seg001:0A22772C ; ---------------------------------------------------------------------------
seg001:0A22772C
seg001:0A22772C loc_A22772C:                            ; CODE XREF: sub_A227018+70E↑j
seg001:0A22772C                 mov     r11, r0         ; Move Data
seg001:0A22772E                 mov.b   @r0, r0         ; Move Byte Data
seg001:0A227730                 tst     #4, r0          ; Test Logical
seg001:0A227732                 bt      loc_A227740     ; Branch if True
seg001:0A227734                 mov.l   #h'21094BA, r1  ; Move Immediate Long Data
seg001:0A227736                 mov.b   @r1, r3         ; Move Byte Data
seg001:0A227738                 mov.l   #h'21094B5, r0  ; Move Immediate Long Data
seg001:0A22773A                 mov.b   r3, @r0         ; Move Byte Data
seg001:0A22773C                 mov.l   #h'21094B1, r2  ; Move Immediate Long Data

Hitachi SH-3 Processor : Windows CE COFF format

Assembler code

Hitachi SH-3 Processor : Windows CE PE format

Assembler code

.text:100011B4 ; Exported entry   1. CreateTransport
.text:100011B4
.text:100011B4 ; =============== S U B R O U T I N E =======================================
.text:100011B4
.text:100011B4
.text:100011B4                 .export CreateTransport
.text:100011B4 CreateTransport:                        ; DATA XREF: .rdata:off_100021C8↓o
.text:100011B4                                         ; .pdata:10004028↓o
.text:100011B4                 sts.l   pr, @-r15
.text:100011B6                 add     #-h'10, r15
.text:100011B8                 mov.l   #??2@YAPAXI@Z, r0 ; operator new(uint)
.text:100011BA                 jsr     @r0 ; ??2@YAPAXI@Z ; operator new(uint)
.text:100011BC                 mov     #h'1C, r4
.text:100011BE                 mov     r0, r4
.text:100011C0                 tst     r4, r4
.text:100011C2                 bt      loc_100011CC
.text:100011C4                 bsr     sub_10001190
.text:100011C6                 nop
.text:100011C8                 bra     loc_100011CE
.text:100011CA                 mov     r0, r4
.text:100011CC ; ---------------------------------------------------------------------------
.text:100011CC
.text:100011CC loc_100011CC:                           ; CODE XREF: CreateTransport+E↑j
.text:100011CC                 mov     #0, r4
.text:100011CE
.text:100011CE loc_100011CE:                           ; CODE XREF: CreateTransport+14↑j
.text:100011CE                 mov     r4, r0
.text:100011D0                 add     #h'10, r15
.text:100011D2                 lds.l   @r15+, pr
.text:100011D4                 rts
.text:100011D6                 nop
.text:100011D6 ; ---------------------------------------------------------------------------
.text:100011D8 off_100011D8:   .data.l ??2@YAPAXI@Z    ; DATA XREF: CreateTransport+4↑r
.text:100011D8                                         ; operator new(uint)
.text:100011DC off_100011DC:   .data.l off_10002030    ; DATA XREF: sub_100011A8+4↑r

Hitachi SH-4 Processor : ELF File Format

Assembler code

LOAD:08041080
LOAD:08041080 ; =============== S U B R O U T I N E =======================================
LOAD:08041080
LOAD:08041080
LOAD:08041080 sub_8041080:                            ; CODE XREF: LOAD:08040F1A↑p
LOAD:08041080                                         ; DATA XREF: LOAD:08040F18↑o ...
LOAD:08041080                 mov.l   r8, @-r15
LOAD:08041082                 mov.l   r9, @-r15
LOAD:08041084                 mov.l   r10, @-r15
LOAD:08041086                 mov.l   r14, @-r15
LOAD:08041088                 sts.l   pr, @-r15
LOAD:0804108A                 mov     r15, r14
LOAD:0804108C                 mov     r4, r8
LOAD:0804108E                 mov     r5, r10
LOAD:08041090                 mov     r6, r9
LOAD:08041092                 mov     #h'C, r4
LOAD:08041094                 mov.l   #malloc, r1
LOAD:08041096                 jsr     @r1 ; malloc
LOAD:08041098                 nop
LOAD:0804109A                 tst     r0, r0
LOAD:0804109C                 bf      loc_80410A4
LOAD:0804109E                 mov     #h'FFFFFFFF, r0
LOAD:080410A0                 bra     loc_80410F6
LOAD:080410A2                 nop
LOAD:080410A4 ; ---------------------------------------------------------------------------
LOAD:080410A4
LOAD:080410A4 loc_80410A4:                            ; CODE XREF: sub_8041080+1C↑j
LOAD:080410A4                 mov.l   r10, @(4,r0)
LOAD:080410A6                 mov.l   r9, @(8,r0)
LOAD:080410A8                 mov     r8, r1
LOAD:080410AA                 add     #h'40, r1 ; '@'
LOAD:080410AC                 mov.l   @(h'34,r1), r1
LOAD:080410AE                 tst     r1, r1
LOAD:080410B0                 bt      loc_80410B8
LOAD:080410B2                 mov.l   @(8,r1), r1

Hitachi SH-4 Processor : Windows CE PE File Format

Assembler code

.text:00011A10
.text:00011A10 ; =============== S U B R O U T I N E =======================================
.text:00011A10
.text:00011A10
.text:00011A10 sub_11A10:                              ; DATA XREF: sub_11A88+20↓o
.text:00011A10                                         ; sub_11A88:off_11B2C↓o ...
.text:00011A10                 mov.l   r8, @-r15
.text:00011A12                 sts.l   pr, @-r15
.text:00011A14                 add     #-h'10, r15
.text:00011A16                 mov.l   #h'C350, r1
.text:00011A18                 add     r1, r4
.text:00011A1A                 mov     r4, r8
.text:00011A1C
.text:00011A1C loc_11A1C:                              ; CODE XREF: sub_11A10+24↓j
.text:00011A1C                 mov.l   #_WaitForSingleObject, r0
.text:00011A1E                 mov     r8, r5
.text:00011A20                 mov.l   #unk_1512C, r1
.text:00011A22                 jsr     @r0 ; _WaitForSingleObject
.text:00011A24                 mov.l   @r1, r4
.text:00011A26                 mov     r0, r4
.text:00011A28                 mov.w   #h'102, r1
.text:00011A2A                 cmp/eq  r1, r4
.text:00011A2C                 bt      loc_11A36
.text:00011A2E                 mov.l   #unk_1513C, r1
.text:00011A30                 mov.l   @r1, r1
.text:00011A32                 tst     r1, r1
.text:00011A34                 bf      loc_11A1C
.text:00011A36
.text:00011A36 loc_11A36:                              ; CODE XREF: sub_11A10+1C↑j
.text:00011A36                 mov.l   #_EnterCriticalSection, r0
.text:00011A38                 mov.l   #unk_176A8, r4
.text:00011A3A                 jsr     @r0 ; _EnterCriticalSection
.text:00011A3C                 nop
.text:00011A3E                 mov.l   #unk_1513C, r1
.text:00011A40                 mov.l   @r1, r1

Super Nintendo Entertainement System (SNES)

Assembler code

.C0:0019 .A8
.C0:0019 .I16
.C0:0019 ; ds=0 B=0 e=0
.C0:0019
.C0:0019 ; =============== S U B R O U T I N E =======================================
.C0:0019
.C0:0019
.C0:0019 sub_C00019:                             ; CODE XREF: Emulation_mode_RESET+3↓J
.C0:0019
.C0:0019 ; FUNCTION CHUNK AT .C0:C62B SIZE 00000088 BYTES
.C0:0019
.C0:0019                 SEI
.C0:001A                 CLC
.C0:001B                 XCE
.C0:001C                 SEP     #$20 ; ' '
.C0:001E                 REP     #$10
.C0:0020                 LDX     #$15FF
.C0:0023                 TXS
.C0:0024                 LDX     #0
.C0:0027                 PHX
.C0:0028                 PLD
.C0:0029                 TDC
.C0:002A                 PHA
.C0:002B                 PLB
.C0:002C                 LDA     #1
.C0:002E                 STA     MEMSEL          ; Memory-2 Waitstate Control (0000000a a: 0 = 2.68 MHz, 1 = 3.58 MHz
.C0:0031                 STZ     MDMAEN          ; Select General Purpose DMA Channel(s) and Start Transfer (abcdefgh a = Channel 7...h = Channel 0: 1 = Enable 0 = Disable
.C0:0034                 STZ     HDMAEN          ; Select H-Blank DMA (H-DMA) Channel(s) (abcdefgh a = Channel 7 .. h = Channel 0: 1 = Enable 0 = Disable
.C0:0037                 LDA     #$8F
.C0:0039                 STA     INIDISP         ; Display Control 1 (a000bbbb a: 0=screen on 1=screen off, b = brightness)
.C0:003C                 STZ     NMITIMEN        ; Interrupt Enable and Joypad Request (a0bc000d a = NMI b = V-Count c = H-Count d = Joypad)
.C0:003F                 JSR     sub_C00525
.C0:0042                 LDX     #0
.C0:0045                 STX     D, word_7E0000
.C0:0047                 LDX     #$FFFF

SPARC Solaris COFF

Assembler code

.text:0000010C ! ---------------------------------------------------------------------------
.text:0000010C
.text:0000010C loc_10C:                                ! CODE XREF: disassemble+A0↑j
.text:0000010C                                         ! DATA XREF: disassemble:jpt_E4↑o
.text:0000010C                 ld      [%fp+var_18], %o0 ! jumptable 000000E4 case 0
.text:00000110                 set     0x3FFFFF, %o1
.text:00000118                 and     %o0, %o1, %o0
.text:0000011C                 st      %o0, [%fp+var_24]
.text:00000120                 ld      [%fp+var_18], %o0
.text:00000124                 set     0x3FFFFF, %o1
.text:0000012C                 and     %o0, %o1, %o0
.text:00000130                 st      %o0, [%fp+var_28]
.text:00000134                 set     aUnimp, %o0     ! "UNIMP"
.text:0000013C                 st      %o0, [%fp+var_2C]
.text:00000140                 ld      [%fp+var_28], %o0
.text:00000144                 call    lookup
.text:00000148                 nop
.text:0000014C                 mov     %o0, %o2
.text:00000150                 set     aSS, %o0        ! "%s %s\n"
.text:00000158                 ld      [%fp+var_2C], %o1
.text:0000015C                 call    printf
.text:00000160                 nop
.text:00000164                 ba      loc_704
.text:00000168                 nop
.text:0000016C ! ---------------------------------------------------------------------------
.text:0000016C
.text:0000016C loc_16C:                                ! CODE XREF: disassemble+A0↑j
.text:0000016C                                         ! DATA XREF: disassemble:jpt_E4↑o
.text:0000016C                 set     aSomeInst, %o0  ! jumptable 000000E4 cases 1,3,5
.text:00000174                 call    printf
.text:00000178                 nop
.text:0000017C                 ba      loc_704
.text:00000180                 nop
.text:00000184 ! ---------------------------------------------------------------------------
.text:00000184
.text:00000184 loc_184:                                ! CODE XREF: disassemble+A0↑j
.text:00000184                                         ! DATA XREF: disassemble:jpt_E4↑o
.text:00000184                 ld      [%fp+var_18], %o1 ! jumptable 000000E4 case 2

SPARC Solaris ELF

Assembler code

.text:0001171C ! ===========================================================================
.text:0001171C
.text:0001171C ! Segment type: Pure code
.text:0001171C                 .text
.text:0001171C
.text:0001171C ! =============== S U B R O U T I N E =======================================
.text:0001171C
.text:0001171C
.text:0001171C                 .global _start
.text:0001171C _start:                                 ! DATA XREF: LOAD:00010018↑o
.text:0001171C                                         ! LOAD:00010628↑o ...
.text:0001171C
.text:0001171C arg_40          =  0x40
.text:0001171C arg_44          =  0x44
.text:0001171C
.text:0001171C                 mov     0, %fp          ! Alternative name is '_ex_text0'
.text:00011720                 ld      [%sp+arg_40], %l0
.text:00011724                 add     %sp, arg_44, %l1
.text:00011728                 sethi   %hi(___Argv), %o1
.text:0001172C                 st      %l1, [%o1+%lo(___Argv)]
.text:00011730                 sll     %l0, 2, %l2
.text:00011734                 inc     4, %l2
.text:00011738                 add     %l1, %l2, %l2
.text:0001173C                 sethi   %hi(environ), %l3
.text:00011740                 st      %l2, [%l3+%lo(environ)]
.text:00011744                 set     0, %l5
.text:0001174C                 tst     %l5
.text:00011750                 be      loc_117BC
.text:00011754                 nop
.text:00011758                 sll     %l5, 2, %l6
.text:0001175C                 and     %l6, 0x300, %l7
.text:00011760                 and     %l5, 0x3F, %l6
.text:00011764                 bset    %l6, %l7
.text:00011768                 sll     %l7, 22, %l5
.text:0001176C                 set     __crt_scratch, %l4

SPARC Sun ELF

Assembler code

.text:000BA990                 bl      loc_BA968
.text:000BA994                 mov     %l5, %o0        ! uid
.text:000BA998
.text:000BA998 loc_BA998:                              ! CODE XREF: perform_flag_actions+2C↑j
.text:000BA998                 ldsh    [%i0], %l7
.text:000BA99C                 btst    1, %l7
.text:000BA9A0                 be      loc_BA9F8
.text:000BA9A4                 mov     0x7F, %i2
.text:000BA9A8                 call    getgid
.text:000BA9AC                 nop
.text:000BA9B0                 call    setgid
.text:000BA9B4                 nop
.text:000BA9B8                 tst     %o0
.text:000BA9BC                 bne     loc_BA9EC
.text:000BA9C0                 nop
.text:000BA9C4                 call    getuid
.text:000BA9C8                 nop
.text:000BA9CC                 call    setuid
.text:000BA9D0                 nop
.text:000BA9D4                 tst     %o0
.text:000BA9D8                 bne     loc_BA9EC
.text:000BA9DC                 nop
.text:000BA9E0                 ldsh    [%i0], %l7
.text:000BA9E4                 ba      loc_BA9FC
.text:000BA9E8                 btst    2, %l7
.text:000BA9EC ! ---------------------------------------------------------------------------
.text:000BA9EC
.text:000BA9EC loc_BA9EC:                              ! CODE XREF: perform_flag_actions+A4↑j
.text:000BA9EC                                         ! perform_flag_actions+C0↑j
.text:000BA9EC                 call    _private_exit
.text:000BA9F0                 mov     %i2, %o0        ! pid
.text:000BA9F4                 ldsh    [%i0], %l7
.text:000BA9F8
.text:000BA9F8 loc_BA9F8:                              ! CODE XREF: perform_flag_actions+88↑j
.text:000BA9F8                 btst    2, %l7

SPARC Sun ELF SO

Assembler code

.text:00003978
.text:00003978 ! =============== S U B R O U T I N E =======================================
.text:00003978
.text:00003978 ! Attributes: bp-based frame
.text:00003978
.text:00003978 strnicmp:                               ! CODE XREF: DoTheReads+48↓p
.text:00003978                 save    %sp, -0x70, %sp ! Alternative name is 'gcc2_compiled.'
.text:0000397C                 ba      loc_39B0
.text:00003980                 inc     -1, %i2
.text:00003984 ! ---------------------------------------------------------------------------
.text:00003984
.text:00003984 loc_3984:                               ! CODE XREF: strnicmp+3C↓j
.text:00003984                 call    _toupper
.text:00003988                 inc     %i0
.text:0000398C                 mov     %o0, %l0
.text:00003990                 ldsb    [%i1], %o0      ! c
.text:00003994                 call    _toupper
.text:00003998                 inc     %i1
.text:0000399C                 cmp     %l0, %o0
.text:000039A0                 be      loc_39B0
.text:000039A4                 inc     -1, %i2
.text:000039A8                 ba      locret_39C0
.text:000039AC                 mov     1, %i0
.text:000039B0 ! ---------------------------------------------------------------------------
.text:000039B0
.text:000039B0 loc_39B0:                               ! CODE XREF: strnicmp+4↑j
.text:000039B0                                         ! strnicmp+28↑j
.text:000039B0                 cmp     %i2, -1
.text:000039B4                 bne,a   loc_3984
.text:000039B8                 ldsb    [%i0], %o0
.text:000039BC                 mov     0, %i0
.text:000039C0
.text:000039C0 locret_39C0:                            ! CODE XREF: strnicmp+30↑j
.text:000039C0                 ret
.text:000039C4                 restore
.text:000039C4 ! End of function strnicmp
.text:000039C4

ST 20C4

Assembler code

ROM:26ECB
ROM:26ECB ; =============== S U B R O U T I N E =======================================
ROM:26ECB
ROM:26ECB
ROM:26ECB sub_26ECB:
ROM:26ECB
ROM:26ECB ; FUNCTION CHUNK AT ROM:18AD1 SIZE 00000003 BYTES
ROM:26ECB
ROM:26ECB                 xor
ROM:26ECD                 ldc     0
ROM:26ECE                 stl     2
ROM:26ECF                 ldc     0
ROM:26ED0                 ldlp    2
ROM:26ED1                 gajw
ROM:26ED3                 ldlp    2
ROM:26ED4                 ldc     43h ; 'C'
ROM:26ED6                 ldl     1
ROM:26ED7                 fcall   loc_18A48
ROM:26EDB                 ldlp    2
ROM:26EDC                 dup
ROM:26EDD                 cj      loc_26EE4
ROM:26EDE                 ldc     0
ROM:26EDF                 ldlp    2
ROM:26EE0                 gajw
ROM:26EE2                 j       loc_26EF8
ROM:26EE4 ; ---------------------------------------------------------------------------
ROM:26EE4
ROM:26EE4 loc_26EE4:                              ; CODE XREF: sub_26ECB+12↑j
ROM:26EE4                 ldlp    2
ROM:26EE5                 ldc     2Eh ; '.'
ROM:26EE7                 ldl     1
ROM:26EE8                 fcall   loc_18A48
ROM:26EEC                 ldlp    2
ROM:26EED                 dup
ROM:26EEE                 cj      loc_26EF4

ST 7

Assembler code

seg000:1235 ; ---------------------------------------------------------------------------
seg000:1235                 sub     a, ($77,x)
seg000:1237                 cp      a, ($77,y)
seg000:123A                 sbc     a, ($77,y)
seg000:123D                 cp      y, ($77,y)
seg000:1240                 and     a, ($77,y)
seg000:1243                 bcp     a, ($77,y)
seg000:1246                 ld      a, ($77,y)
seg000:1249                 ld      ($77,y), a
seg000:124C                 xor     a, ($77,y)
seg000:124F                 adc     a, ($77,y)
seg000:1252                 or      a, ($77,y)
seg000:1255                 add     a, ($77,y)
seg000:1258                 jp      ($77,y)
seg000:125B ; ---------------------------------------------------------------------------
seg000:125B                 call    ($77,y)
seg000:125E                 ld      y, ($77,y)
seg000:1261                 ld      ($77,y), y
seg000:1264                 sub     a, (y)
seg000:1266                 cp      a, (y)
seg000:1268                 sbc     a, (y)
seg000:126A                 cp      y, (y)
seg000:126C                 and     a, (y)
seg000:126E                 bcp     a, (y)
seg000:1270                 ld      a, (y)
seg000:1272                 ld      (y), a
seg000:1274                 xor     a, (y)
seg000:1276                 adc     a, (y)
seg000:1278                 or      a, (y)
seg000:127A                 add     a, (y)
seg000:127C                 jp      (y)
seg000:127E ; ---------------------------------------------------------------------------
seg000:127E                 call    (y)
seg000:1280                 ld      y, (y)
seg000:1282                 ld      (y), y

ST 9

Assembler code

.init:00000107
.init:00000107 ; =============== S U B R O U T I N E =======================================
.init:00000107
.init:00000107
.init:00000107                 .global ___Reset
.init:00000107                 .desc ___Reset, near
.init:00000107                 .proc ___Reset
.init:00000107 ___Reset:
.init:00000107                 spp     #0              ; Alternative name is '___Reset'
.init:00000107                                         ; __Reset
.init:00000109 ; Register page: 0
.init:00000109                 ld      R252, #0x40 ; '@' ; Wait Control Register
.init:0000010C                 ld      R235, #0x20 ; ' ' ; Mode Register
.init:0000010F                 ld      R230, #0x8F ; Central Interrupt Control Register
.init:00000112                 srp     #0x1A           ; r0 -> R208, r1 -> R209, r2 -> R210, r3 -> R211, r4 -> R212, r5 -> R213, r6 -> R214, r7 -> R215,
.init:00000112                                         ; r8 -> R216, r9 -> R217, r10 -> R218, r11 -> R219, r12 -> R220, r13 -> R221, r14 -> R222, r15 -> R223
.init:00000114 ; Register window: (26, 26)
.init:00000114                 sdm
.init:00000115                 ldw     RR238, #0x284 ; System Stack Pointer
.init:00000119                 spp     #0x15           ; Registers R240-R255 will now be referred to the page 21 of paged registers
.init:0000011B ; Register page: 21
.init:0000011B                 ld      r0, #0x88 ; 'ˆ'
.init:0000011D                 or      r0, r0
.init:0000011F                 jpeq    loc_190
.init:00000122                 ld      R242, #0 ; Data Page Register 2
.init:00000125                 ldw     rr10, #0x28C
.init:00000129                 or      r10, #0x80 ; '€'
.init:0000012C
.init:0000012C loc_12C:                                ; CODE XREF: ___Reset:loc_190↓j
.init:0000012C                 ld      r8, (rr10)+
.init:0000012F                 btjf    r8.1, loc_149
.init:00000132                 ld      R240, (rr10)+ ; Data Page Register 0
.init:00000135                 ldw     rr0, (rr10)+
.init:00000138                 ldw     rr4, (rr10)+
.init:0000013B                 ld      R241, (rr10)+ ; Data Page Register 1

Toshiba TLCS 900

Assembler code

IROM:00008100
IROM:00008100 ; =============== S U B R O U T I N E =======================================
IROM:00008100
IROM:00008100
IROM:00008100                 ; public RESET_
IROM:00008100 RESET_:                                 ; DATA XREF: IROM:00008000↑o
IROM:00008100                 DEC     0x02, XSP
IROM:00008102                 DI
IROM:00008104                 LD      (P3), 0x00      ; Port 3
IROM:00008107                 LD      (P3CR), 0xF4 ; 'ô' ; Port 3 Control
IROM:0000810A                 LD      (P3FC), 0x00    ; Port 3 Function
IROM:0000810D                 LD      (SYSCR0), 0xA0 ; ' ' ; System Clock Register 0
IROM:00008110                 LD      (SYSCR1), 0x00  ; System Clock Contol Register 1
IROM:00008113                 LD      (B0CS), 0x99 ; '™' ; Block 0 CS/WAIT Control Register
IROM:00008116                 LD      (B1CS), 0x9A ; 'š' ; Block 1 CS/WAIT Control Register
IROM:00008119                 LD      (B2CS), 0x8F    ; Block 2 CS/WAIT Control Register
IROM:0000811C                 LD      XSP, 0x0000087F
IROM:00008121                 LD      (WDMOD), 0x00   ; Watch Dog Timer Mode
IROM:00008124                 LD      (WDCR), 0xB1 ; '±' ; Watch Dog Control Register
IROM:00008127                 LD      XHL, 0x00000080 ; '€'
IROM:0000812C                 LD      BC, 0x0800
IROM:0000812F                 LD      A, 0x00
IROM:00008131
IROM:00008131 loc_8131:                               ; CODE XREF: RESET_+35↓j
IROM:00008131                 LD      (XHL), A
IROM:00008133                 INC     0x01, HL
IROM:00008135                 DJNZ    BC, (loc_8131)
IROM:00008138                 LD      (P0), 0x00      ; Port 0
IROM:0000813B                 LD      (P0CR), 0xFF    ; Port 0 Control
IROM:0000813E                 LD      (P1), 0x00      ; Port 1
IROM:00008141                 LD      (P1CR), 0xFF    ; Port 1 Control
IROM:00008144                 LD      (P1FC), 0x00    ; Port 1 Function
IROM:00008147                 LD      (P2), 0x00      ; Port 2
IROM:0000814A                 LD      (P2CR), 0xFF    ; Port 2 Control
IROM:0000814D                 LD      (P2FC), 0x00    ; Port 2 Function

TMS 320c2 COFF

Assembler code

cseg:0017
cseg:0017 ; =============== S U B R O U T I N E =======================================
cseg:0017
cseg:0017
cseg:0017 sub_cseg_17:
cseg:0017                 banz    unk_dseg_EDB, *-
cseg:0019                 banz    unk_dseg_EED, *+
cseg:001B                 bbnz    unk_dseg_F9C
cseg:001D                 bbz     unk_dseg_F55
cseg:001F                 bc      unk_dseg_F18
cseg:0021                 bgez    unk_dseg_FD3
cseg:0023                 bgz     unk_dseg_F0C
cseg:0025                 bioz    unk_dseg_EED
cseg:0027                 bit     drr, 8          ; Data receive register
cseg:0028                 bit     *, 1
cseg:0029                 bit     *, 2
cseg:002A                 bit     *, 3
cseg:002B                 bit     *, 4
cseg:002C                 bit     *, 5
cseg:002D                 bit     *, 8
cseg:002E                 bitt    drr             ; Data receive register
cseg:002F                 bitt    *
cseg:0030                 blez    unk_dseg_ED1
cseg:0032                 rptk    2
cseg:0033                 blkd    byte_dseg_F400, *+
cseg:0035                 rptk    2
cseg:0036                 blkp    byte_dseg_FD30, *+
cseg:0038                 blz     unk_dseg_F12
cseg:003A                 bnc     unk_dseg_F55
cseg:003C                 bnv     unk_dseg_FBE
cseg:003E                 bnz     unk_dseg_F81, ar6
cseg:0040                 bv      unk_dseg_F15
cseg:0042                 bz      unk_dseg_F8B
cseg:0044                 cala
cseg:0045                 call    unk_dseg_F27

TMS 320c5

Assembler code

cseg:0030
cseg:0030 ; =============== S U B R O U T I N E =======================================
cseg:0030
cseg:0030
cseg:0030 sub_cseg_30:
cseg:0030                 bitt    *br0+, ar7
cseg:0031                 bldd    #Reserved_0, byte_dseg_7F
cseg:0033                 bldd    #Reserved_0, *br0+, ar7
cseg:0035                 bldd    byte_dseg_7F, #Reserved_0
cseg:0037                 bldd    *br0+, #Reserved_0, ar7
cseg:0039                 bldd    bmar, byte_dseg_7F
cseg:003A                 bldd    bmar, *br0+, ar7
cseg:003B                 bldd    byte_dseg_7F, bmar
cseg:003C                 bldd    *br0+, bmar, ar7
cseg:003D                 bldp    byte_dseg_7F
cseg:003E                 bldp    *br0+, ar7
cseg:003F                 blpd    #start, byte_dseg_7F
cseg:0041                 blpd    #start, *br0+, ar7
cseg:0043                 blpd    bmar, byte_dseg_7F
cseg:0044                 blpd    bmar, *br0+, ar7
cseg:0045                 bsar    16
cseg:0046                 cala
cseg:0047                 calad
cseg:0048                  call    start, *br0+, ar7
cseg:004A                 calld   start, *br0+, ar7
cseg:004C                  cc      start, geq,bio
cseg:004E                 ccd     start, eq,bio
cseg:0050                  clrc    ovm
cseg:0051                  clrc    sxm
cseg:0052                 clrc    hm
cseg:0053                 clrc    tc
cseg:0054                 clrc    c
cseg:0055                 clrc    cnf
cseg:0056                 clrc    intm
cseg:0057                 clrc    xf

TMS 320c54

Assembler code

.text:0000003A                 call    11Ch
.text:0000003C                 calld   11Ch
.text:0000003E                 nop
.text:0000003F                 nop
.text:00000040                 cc      11Ch, tc
.text:00000042                 ccd     11Ch, aeq
.text:00000044                 nop
.text:00000045                 nop
.text:00000046                 cmpl    B, A
.text:00000047                 cmpm    *AR0+, #1
.text:00000049                 cmpr    lt, AR1
.text:0000004A                 cmps    A, *AR2+
.text:0000004B                 dadd    *AR3-, A, B
.text:0000004C                 dadst   *AR4-, A
.text:0000004D                 delay   *AR5+
.text:0000004E                 dld     *AR6-, A
.text:0000004F                 drsub   *AR7-, B
.text:00000050                 dsadt   *AR0-, A
.text:00000051                 dst     A, *AR1-
.text:00000052                 dsub    *AR2-, B
.text:00000053                 dsubt   *AR3-, A
.text:00000054                 exp     A
.text:00000055                 firs    *AR3+, *AR4+, 11Ch
.text:00000057                 frame   -80h
.text:00000058                 idle    2
.text:00000059                 intr    0Fh
.text:0000005A                 ld      *AR0+, A
.text:0000005B                 ld      *AR1+, TS, A
.text:0000005C                 ld      *AR2+, 16, A
.text:0000005D                 ld      *AR3+, 1, A
.text:0000005E                 ld      *AR4+, 1, A
.text:0000005F                 ld      #1, B
.text:00000060                 ld      #7FFFh, 1, A
.text:00000062                 ld      #7FFFh, 16, A
.text:00000064                 ld      A, ASM, B

TMS 320c6 COFF File Format

Assembler code

.text:00008FC0
.text:00008FC0 ; =============== S U B R O U T I N E =======================================
.text:00008FC0
.text:00008FC0
.text:00008FC0 _main:                                  ; CODE XREF: start:loc_8EB8↑p
.text:00008FC0           B       .S1    _printf
.text:00008FC4           NOP            2
.text:00008FC8
.text:00008FC8           MVK     .S1    0FFFF9148h, A0
.text:00008FCC   ||      STW     .D2    B3, *B15--[3]
.text:00008FD0
.text:00008FD0           STW     .D2    A10, *B15[2]
.text:00008FD4   ||      MVKH    .S1    0, A0
.text:00008FD8   ||      MVK     .S2    (loc_8FE8 & 0FFFFh), B3
.text:00008FDC   ||      NOP
.text:00008FE0
.text:00008FE0           STW     .D2    A0, *B15[1]
.text:00008FE4   ||      MVKH    .S2    (loc_8FE8 >> 16), B3
.text:00008FE4         ; CALL _printf OCCURS
.text:00008FE8
.text:00008FE8 loc_8FE8:                               ; DATA XREF: _main+18↑o
.text:00008FE8                                         ; _main+24↑o
.text:00008FE8           ZERO    .L1    A10
.text:00008FEC           MV      .L1    A10, A4
.text:00008FF0           LDW     .D2    *B15[2], A10
.text:00008FF4           LDW     .D2    *++B15[3], B3
.text:00008FF8           NOP            4
.text:00008FFC           B       .S2    B3
.text:00009000           NOP            5
.text:00009000         ; BRANCH OCCURS
.text:00009000 ; End of function _main
.text:00009000
.text:00009000 ; ---------------------------------------------------------------------------
.text:00009004         .align 20h
.text:00009020 ; [00000038 BYTES: COLLAPSED FUNCTION _strchr. PRESS CTRL-NUMPAD+ TO EXPAND]

TRICORE

Assembler code

PFLASH:800000EC
PFLASH:800000EC ; =============== S U B R O U T I N E =======================================
PFLASH:800000EC
PFLASH:800000EC
PFLASH:800000EC                 .global asm_clear_endinit
PFLASH:800000EC asm_clear_endinit:                      ; CODE XREF: _start+1C↑p
PFLASH:800000EC                 ld32.w          d0, WDT_CON0 ; Watchdog Timer Control Register 0
PFLASH:800000F0                 ld32.w          d1, WDT_CON1 ; Watchdog Timer Control Register 1
PFLASH:800000F4                 movh            d2, #0
PFLASH:800000F8                 addi            d2, d2, #-0xFF
PFLASH:800000FC                 and16           d0, d2
PFLASH:800000FE                 or32            d0, d0, #0xF0 ; 'ð'
PFLASH:80000102                 and32           d4, d1, #0xC
PFLASH:80000106                 or16            d0, d4
PFLASH:80000108                 st32.w          WDT_CON0, d0 ; Watchdog Timer Control Register 0
PFLASH:8000010C                 movh            d4, #0
PFLASH:80000110                 addi            d4, d4, #-0x10
PFLASH:80000114                 and16           d0, d4
PFLASH:80000116                 or32            d0, d0, #2
PFLASH:8000011A                 isync
PFLASH:8000011E                 st32.w          WDT_CON0, d0 ; Watchdog Timer Control Register 0
PFLASH:80000122                 ld32.w          d0, WDT_CON0 ; Watchdog Timer Control Register 0
PFLASH:80000126                 nop16
PFLASH:80000128                 ji16            a11
PFLASH:80000128 ; End of function asm_clear_endinit
PFLASH:80000128
PFLASH:8000012A
PFLASH:8000012A ; =============== S U B R O U T I N E =======================================
PFLASH:8000012A
PFLASH:8000012A
PFLASH:8000012A                 .global _disable_wdt
PFLASH:8000012A _disable_wdt:                           ; CODE XREF: _start:__no_board_init↑p
PFLASH:8000012A                 movh            d2, #0
PFLASH:8000012E                 addi            d2, d2, #-0xFD
PFLASH:80000132                 movh            d5, #0


SunPlus unSP

Assembler code

ROM:41B3
ROM:41B3 ; =============== S U B R O U T I N E =======================================
ROM:41B3
ROM:41B3
ROM:41B3 sub_41B3:
ROM:41B3                 sp  = $27FF
ROM:41B5                 r1  = $4000
ROM:41B7                 r2  = [r1++]
ROM:41B8                 jmp      loc_41CA
ROM:41B9 ; ---------------------------------------------------------------------------
ROM:41B9
ROM:41B9 loc_41B9:                               ; CODE XREF: sub_41B3+18↓j
ROM:41B9                 push     r2, r2 to [sp]
ROM:41BA                 r3  = [r1++]
ROM:41BB                 r4  = [r1++]
ROM:41BC                 r4  = r4 lsl 4
ROM:41BD                 r4  = r4 lsl 4
ROM:41BE                 r4  = r4 lsl 2
ROM:41BF                 sr  = r4
ROM:41C0                 r4  = [r1++]
ROM:41C1                 bp  = [r1++]
ROM:41C2                 jmp      loc_41C6
ROM:41C3 ; ---------------------------------------------------------------------------
ROM:41C3
ROM:41C3 loc_41C3:                               ; CODE XREF: sub_41B3+14↓j
ROM:41C3                 r2  = ds:[r4++]
ROM:41C4                 [r3++]  = r2
ROM:41C5                 bp -= 1
ROM:41C6
ROM:41C6 loc_41C6:                               ; CODE XREF: sub_41B3+F↑j
ROM:41C6                 cmp      bp, 0
ROM:41C7                 jne      loc_41C3
ROM:41C8                 pop      r2, r2 from [sp]
ROM:41C9                 r2 -= 1
ROM:41CA
ROM:41CA loc_41CA:                               ; CODE XREF: sub_41B3+5↑j
ROM:41CA                 cmp      r2, 0

NEC V850

Assembler code

.text:000007A6
.text:000007A6 -- =============== S U B R O U T I N E =======================================
.text:000007A6
.text:000007A6
.text:000007A6                 .globl _systeminit
.text:000007A6 _systeminit:                            -- CODE XREF: __start+7C↑p
.text:000007A6                 prepare {lp}, 0
.text:000007AA                 mov     0x9F4, r6
.text:000007B0                 mov     -1, r7
.text:000007B2                 jarl    __rcopy, lp
.text:000007B6                 di
.text:000007BA                 jarl    _CG_ReadResetSource, lp
.text:000007BE                 jarl    __startend, lp
.text:000007C2                 jarl    _TMP0_Init, lp
.text:000007C6                 ei
.text:000007CA                 dispose 0, {lp}, [lp]
.text:000007CA -- End of function _systeminit
.text:000007CA
.text:000007CE
.text:000007CE -- =============== S U B R O U T I N E =======================================
.text:000007CE
.text:000007CE
.text:000007CE                 .globl _f1
.text:000007CE _f1:                                    -- CODE XREF: _complex1+B6↓p
.text:000007CE                 ld.w    -0x8000[gp], r10
.text:000007D2                 add     r6, r10
.text:000007D4                 add     1, r10
.text:000007D6                 jmp     [lp]
.text:000007D6 -- End of function _f1
.text:000007D6
.text:000007D8
.text:000007D8 -- =============== S U B R O U T I N E =======================================
.text:000007D8
.text:000007D8
.text:000007D8                 .globl _f2
.text:000007D8 _f2:                                    -- CODE XREF: _complex1+B0↓p
.text:000007D8                 ld.w    -0x8000[gp], r10

Z180 COFF File Format

Assembler code

seg000:000E                 dec     bc
seg000:000F                 inc     c
seg000:0010
seg000:0010 loc_10:                                 ; CODE XREF: seg000:010F↓p
seg000:0010                 dec     c
seg000:0011                 ld      c, 88h ; 'ˆ'
seg000:0013                 rrca
seg000:0014                 djnz    sub_0
seg000:0016                 djnz    loc_1B
seg000:0018
seg000:0018 loc_18:                                 ; CODE XREF: seg000:011C↓p
seg000:0018                 ld      de, 9876h
seg000:001B
seg000:001B loc_1B:                                 ; CODE XREF: sub_0+16↑j
seg000:001B                 ld      (de), a
seg000:001C                 inc     de
seg000:001D                 inc     d
seg000:001E                 dec     d
seg000:001F
seg000:001F loc_1F:                                 ; CODE XREF: seg000:0129↓p
seg000:001F                 ld      d, 88h ; 'ˆ'
seg000:0021                 rla
seg000:0022                 jp      loc_88
seg000:0025 ; ---------------------------------------------------------------------------
seg000:0025                 add     hl, de
seg000:0026                 ld      a, (de)
seg000:0027                 dec     de
seg000:0028
seg000:0028 loc_28:                                 ; CODE XREF: seg000:0135↓p
seg000:0028                 inc     e
seg000:0029                 dec     e
seg000:002A                 ld      e, 88h ; 'ˆ'
seg000:002C                 rra
seg000:002D                 jp      nz, loc_88
seg000:0030
seg000:0030 loc_30:                                 ; CODE XREF: seg000:0142↓p
seg000:0030                 ld      hl, 9876h

Z380 COFF File Format

Assembler code

seg000:001E                 inc     d
seg000:001F                 dec     d
seg000:0020
seg000:0020 loc_20:                                 ; CODE XREF: seg000:062A↓p
seg000:0020                 ld      d, 12h
seg000:0022
seg000:0022 loc_22:                                 ; CODE XREF: sub_0+23↓j
seg000:0022                 rla
seg000:0023                 jr      loc_22
seg000:0023 ; End of function sub_0
seg000:0023
seg000:0025 ; ---------------------------------------------------------------------------
seg000:0025                 add     hl, de
seg000:0026                 ld      a, (de)
seg000:0027                 dec     de
seg000:0028
seg000:0028 ; =============== S U B R O U T I N E =======================================
seg000:0028
seg000:0028
seg000:0028 sub_28:                                 ; CODE XREF: seg000:096A↓p
seg000:0028                 dec     de
seg000:0029                 inc     e
seg000:002A                 dec     e
seg000:002B                 ld      e, 12h
seg000:002D
seg000:002D loc_2D:                                 ; CODE XREF: sub_28+6↓j
seg000:002D                 rra
seg000:002E                 jr      nz, loc_2D
seg000:002E ; End of function sub_28
seg000:002E
seg000:0030
seg000:0030 ; =============== S U B R O U T I N E =======================================
seg000:0030
seg000:0030
seg000:0030 sub_30:                                 ; CODE XREF: seg000:097D↓p
seg000:0030                 ld      hl, 1234h

Z8

Assembler code

code:0000000C
code:0000000C ; =============== S U B R O U T I N E =======================================
code:0000000C
code:0000000C
code:0000000C                 ; public start
code:0000000C start:
code:0000000C
code:0000000C ; FUNCTION CHUNK AT code:00000139 SIZE 00000016 BYTES
code:0000000C
code:0000000C                 ld      p2m, #0         ; Port 2 mode register
code:0000000F                 ld      p3m, #1         ; Port 3 mode register
code:00000012                 ld      p01m, #4        ; Ports 0-1 mode register
code:00000015                 ld      ipr, #1Ch       ; Interrupt priority register
code:00000018                 ld      imr, #21h ; '!' ; Interrupt mask register
code:0000001B                 ld      R4, #0Fh
code:0000001E                 ld      R5, #0Fh
code:00000021                 ld      R6, #0Fh
code:00000024                 srp     #10h
code:00000026                 .rp 10h
code:00000026
code:00000026                 ; public Start
code:00000026 Start:                                  ; Program control flags
code:00000026                 clr     flags
code:00000028                 ld      spl, #40h ; '@' ; Stack pointer low byte
code:0000002B                 clr     irq             ; Interrupt request register
code:0000002D                 ei
code:0000002E                 ld      R32, #10h
code:00000031                 ld      R31, #0Fh
code:00000033
code:00000033                 ; public zero
code:00000033 zero:                                   ; CODE XREF: start+2B↓j
code:00000033                 clr     @R32
code:00000035                 inc     R32
code:00000037                 djnz    R31, zero
code:00000039                 ld      p2, #0FFh       ; Port 2

Z80

Assembler code

ROM:02A0
ROM:02A0 ; =============== S U B R O U T I N E =======================================
ROM:02A0
ROM:02A0
ROM:02A0 sub_2A0:
ROM:02A0                 ld      a, 7Fh
ROM:02A2                 in      a, (0FEh)
ROM:02A4                 rra
ROM:02A5                 jr      c, loc_2B2
ROM:02A7                 ld      a, 7Fh
ROM:02A9                 in      a, (0FEh)
ROM:02AB                 rra
ROM:02AC                 jr      c, loc_2B2
ROM:02AE                 ld      a, 14h
ROM:02B0                 scf
ROM:02B1                 ret
ROM:02B2 ; ---------------------------------------------------------------------------
ROM:02B2
ROM:02B2 loc_2B2:                                ; CODE XREF: sub_2A0+5↑j
ROM:02B2                                         ; sub_2A0+C↑j
ROM:02B2                 or      a
ROM:02B3                 ret
ROM:02B3 ; End of function sub_2A0
ROM:02B3
ROM:02B3 ; ---------------------------------------------------------------------------
ROM:02B4                 db    0
ROM:02B5                 db    0
ROM:02B6                 db    0
ROM:02B7                 db    0
ROM:02B8                 db    0
ROM:02B9                 db    0
ROM:02BA                 db    0
ROM:02BB                 db    0
ROM:02BC                 db    0
ROM:02BD                 db    0

IDA supported processors

The list of supported processor/OS/file format combinations is so large that it is not easy to enumerate it. Please look at our gallery which contains disassembly samples across a wide number of processors.

IDA Pro supported processors

IIDA Pro supports the processors listed below. The source code of some processor modules is available in our free SDK.

IDA Pro supported processors
  • web assembly (WASM)
  • AMD K6-2 3D-Now! extensions
  • 32-bit ARM Architecture versions from v3 to v8 including Thumb, Thumb-2, DSP instructions and NEON Advanced SIMD instructions.
    • ARMv4 / ARMv4T: ARM7 cores (ARM7TDMI / ARM710T / ARM720T / ARM740T), ARM9 cores (ARM9TDMI / ARM920T / ARM922T / ARM940T)
    • ARMv5 / ARMv5TE / ARMv5TEJ: ARM9 cores (ARM946E-S/ ARM966E-S/ ARM968E-S/ ARM926EJ-S/ ARM996HS), ARM10E (ARM1020E / ARM1022E / ARM1026EJ-S)
    • ARMv6 / ARMv6T2 / ARMv6Z / ARMv6K: ARM11 cores (ARM1136J(F)-S / ARM1156T2(F)-S / ARM1176JZ(F)-S / ARM11 MPCore)
    • ARMv6-M: Cortex-M0 / Cortex-M0+ / Cortex-M1 (e.g. NXP LPC800/LPC1xxx, Freescale Kinetis L and M series, STM32 F0 series etc.)
    • ARMv7-M: Cortex-M3 (e.g. NXP LPC17xx/18xx/13xx, STM32 F1/F2/L1 series, TI Stellaris, Toshiba TX03 / TMPM3xx etc.)
    • ARMv7E-M: Cortex-M4 (e.g. NXP LPC43xx, STM32 F3/F4 series, TI Stellaris LM4F, Freescale Kinetis K series and W series, Atmel AT91SAM4 etc.)
    • ARMv7-R: Cortex-R4(F)/Cortex-R5/Cortex-R7 (e.g. TI TMS570LS etc.)
    • ARMv7-A: Cortex-A5 / Cortex-A7 / Cortex-A8 / Cortex-A9 / Cortex-A12 / Cortex-A15 (e.g. TI Sitara, TI OMAP series, Samsung S5PC100 and Exynos, Nvidia Tegra, Freescale i.MX, Allwinner A-Series and many others)
    • ARMv7 (custom): Apple A4/A5/A5X/A6/A6X (Swift microarchitecture, used in Apple’s iPhone/iPod/iPad/AppleTV), Qualcomm Snapdragon [Note: this list is incomplete; code for any ARM-compliant core can be disassembled]
  • ARM64 Architecture (aka AArch64): *
    • ARMv8-A: Cortex-A50/Cortex-A53/Cortex-A57 etc.
    • ARMv8 (custom): Apple A7,A8 etc. (iPhone 5s and newer devices)
  • ARC (Argonaut RISC Core), including ARCompact and ARCv2 (comes with source code)
  • ATMEL AVR (comes with source code)
  • DEC PDP-11(comes with source code)
  • Fujitsu FR (comes with source code)
  • Nintendo Entertainment System (NES) (6502)
  • Nintendo Super Entertainment System (SNES) (65816, 65C816)
  • Nintendo GameBoy (Z80, ARM7)
  • Nintendo DS (ARM9, ARM11)
  • Hitachi/Renesas H8/300, H8/300L, H8/300H, H8S/2000, H8S/2600, H8SX (comes with source code)H8/330, H8/322, H8/323, H8/325, H8/326-329, H8/336-338, H8/350, H8/3048F, H8/3202, H8/3212, H8/3214, H8/3216, H8/3217, H8/3256, H8/3257, H8/3292, H8/3294, H8/3296, H8/3297, H8/3315, H8/3318, H8/3334Y, H8/3336Y, H8/3337Y, H8/3337YF, H8/3394, H8/3396, H8/3397, H8/3534, H8/3434, H8/3434F, H8/3436, H8/3437, H8/3437F, H8/3522H8/3612, H8/3613, H8/3614, H8/3712, H8/3713, H8/3714, H8/3723, H8/3724, H8/3725, H8/3726, H8/3812, H8/3813, H8/3814, H8/3833-37, H8/3875, H8/3876, H8/3877, H8/3924, H8/3925, H8/3926, H8/3927, H8/3945-47H8/3002, H8/3040-3042, H8/3003, H8/3030-32, H8/3048, H8/3070, H8/3071, H8/3072H8S/2246, H8S/2245, H8S/2244, H8S/2243, H8S/2242, H8S/2241, H8S/2133, H8S/2144F, H8S/2357F, H8S/2143, H8S/2142F, H8S/2345F, H8S/2343, H8S/2341, H8S/2237, H8S/2235, H8S/2233, H8S/2227, H8S/2225, H8S/2223, H8S/2240, H8S/2242, H8S/2350, H8S/2352, H8S/2340, H8S/2355, H8S/2353, H8S/2351, H8S/2134F, H8S/2132FH8S/2655R, H8S/2653R, H8S/2655
  • Hitachi H8/500 (comes with source code)
  • Hitachi HD 6301, HD 6303, Hitachi HD 64180
  • INTEL 8080
  • INTEL 8085 (comes with source code)
  • INTEL 80196 (comes with source code)
  • INTEL 8051 (comes with source code)
  • INTEL 860XR (comes with source code)
  • INTEL 960 (comes with source code)
  • INTEL 80×86 and 80×87 (Intel 8086/8088, 80186, 80286, 80386, 80486 and compatibles)
  • INTEL Pentium/Celeron/Xeon, including SSE, SSE2, SSE3, SSE4, AVX, AVX2, AVX-512 and other extensions
  • Java Virtual Machine (comes with source code)
  • KR1878 (comes with source code)
  • Microsoft .NET (Common Language Infrastructure bytecode)
  • Mitsubishi MELPS740 or Renesas 740 (comes with source code)
  • Hitachi/Renesas M16C family M16C/60, M16C/20, M16C/Tiny, R8C/Tiny, M16C/80, M32C/80, R32C/100
  • MN102 (comes only with source code)
  • MOS Technologies 6502, 65C02 (comes with source code)
  • W65C816S aka 65C816 or 65816 (comes with source code)
  • Motorola/Freescale 68K family: MC680xx, CPU32 (68330), MC6301
    MC680xx
  • Motorola 68xx series: MC6301, MC6303, MC6800, MC6801, MC6803, MC6805, MC6808, HCS08, MC6809, MC6811, \
  • Motorola MC6812/MC68HC12/CPU12
  • Freescale HCS12, HCS12X (including XGATE coprocessor)
  • Motorola MC68HC16
  • NSC CR16 (comes only with source code)
  • NEC V850 series (including V850E1, V850E1F, V850ES, V850E2, V850E2M) (comes with source code)
  • Renesas RH850 series (RH850G3K, RH850G3M, RH850G3KH, RH850G3MH) (comes with source code)
  • EFI Byte Code (EBC) (comes with source code)
  • SPU (Synergistic Processing Unit of the Cell BE) (comes with source code)
  • MSP430, MSP430X (comes with source code)
  • Microchip PIC 12XX, PIC 14XX, PIC 18XX, PIC 16XXX (comes with source code)
  • Microchip 16-bit PIC series (PIC24, dsPIC: PIC24XX, PIC30XX, PIC33XX)
  • Rockwell C39 (comes only with source code)
  • Samsung SAM8 (comes with source code)
  • SGS Thomson ST-7, and ST-20 (comes with source code)
  • TLCS900 (comes only with source code)
  • unSP from SunPlus
  • Sony SPC700
  • Philips XA series (51XA G3)(comes with source code)
  • RISC-V
  • Renesas RL78 series
  • Intel xScale
  • Z80, Zilog Z8, Zilog Z180, Zilog Z380 (comes with source code)
  • IBM z/Architecture (S390, S390x)
  • x64 architecture (aka Intel 64/IA-32e/EM64T/x86-64/AMD64)
  • Analog Devices AD218x series (ADSP-2181, ADSP-2183, ADSP-2184(L/N), ADSP-2185(L/M/N), ADSP-2186(L/M/N), ADSP-2187(L/N), ADSP-2188M/N, ADSP-2189M/N)
  • Dalvik (Android bytecode, DEX)
  • DEC Alpha
  • Motorola DSP563xx, DSP566xx, DSP561XX (comes with source code)
  • TI TMS320C2X, TMS320C5X, TMS320C6X, TMS320C64X, TMS 320C54xx, TMS320C55xx, TMS320C3 (comes with source code)
  • TI TMS320C27x/TMS320C28x
  • Hewlett-Packard HP-PA aka PA-RISC (comes with source code)
  • Hitachi/Renesas SuperH series. Unexhaustive list:
    • SH-1 core, for example SH7020,SH7021, SH7032,SH7034;
    • SH-2 core: SH7047, SH7049, SH7105, SH7107, SH7109 etc.;
    • SH-2E core: SH7055, SH7058 etc.;
    • SH-2A core: SH7201, SH7206, SH7211, SH7214
    • SH2A-FPU core: SH7450, SH7263 etc.;
    • SH3 core: SH7706, SH7709S;
    • SH4 core: SH7091(Sega Dreamcast), SH7750;
    • SH-4A core: SH7450, SH7451,SH7734, SH7785.
  • Renesas RXv1, RXv2, RXv3 cores (RX100/RX200/RX600/RX700)
  • IBM/Motorola PowerPC/POWER architecture, including Power ISA extensions:
    • Book E (Embedded Controller Instructions)
    • Freescale ISA extensions (isel etc.)
    • SPE (Signal Processing Engine) instructions
    • AltiVec (SIMD) instructions
    • Hypervisor and virtualization instructions
    • All instructions from the Power ISA 2.06 specification (Vector, Decimal Floating Point, Integer Multiply-Accumulate, VSX etc.)
    • Cell BE (Broadband Engine) instructions (used in PlayStation 3)
    • VLE (Variable Length Encoding) compressed instruction set
    • Xenon (Xbox 360) instructions, including VMX128 extension
    • Paired Single SIMD instructions (PowerPC 750CL/Gekko/Broadway/Espresso, used in Nintendo Wii and WiiU)
  • Motorola/Freescale PowerPC-based cores and processors, including (but not limited to):
    • MPC5xx series: MPC533 / MPC535 / MPC555 / MPC556 / MPC561 / MPC562 / MPC563 / MPC564 / MPC566 Note: code compression features of MPC534/MPC564/MPC556/MPC566 (Burst Buffer Controller) are currently not supported
    • MPC8xx series (PowerQUICC): MPC821/MPC850/MPC860
    • MPC8xxx series (PowerQUICC II, PowerQUICC II Pro, PowerQUICC III): MPC82xx / MPC83xx / MPC85xx / MPC87xx
    • MPC5xxx series (Qorivva): MPC55xx, MPC56xx, MPC57xx
    • Power PC 4xx, 6xx, 74xx, e200 (including e200z0 with VLE), e500 (including e500v1, e500v2 and e500mc), e600, e700, e5500, e6500 cores
    • QorIQ series: P1, P2, P3, P4, P5 and T1, T2, T4 families
  • Infineon Tricore: TC1xxx (AUDO, AUDO MAX), TC2xx, TC3xx, TC4x (AURIX, supported TriCore architecture up to v1.8)
  • Intel IA-64 Architecture – Itanium.
  • Motorola DSP 56K
  • MIPS
    • MIPS Mark I (R2000)
    • MIPS Mark II (R3000)
    • MIPS Mark III: (R4000, R4200, R4300, R4400, and R4600)
    • MIPS Mark IV: R8000, R10000, R5900 (Playstation 2)
    • MIPS32, MIPS32r2, MIPS32r3 and MIPS64, MIPS64r2, MIPS64r3
    • Allegrex CPU (Playstation Portable – PSP), including VFPU instructions
    • Cavium Octeon and Octeon2 (cnMIPS) ISA extensions
    • MIPS16 (MIPS16e, MIPS16e2) Application Specific Extension
    • microMIPS Application Specific Extension
    • MIPS-MT, MIPS-3D, smartMIPS Application Specific Extensions
    • Toshiba TX19/TX19A Family Application Specific Extension (MIPS16e+ aka MIPS16e-TX)
  • Mitsubishi M32R (comes with source code)
  • Mitsubishi M7700 (comes with source code)
  • Mitsubishi M7900 (comes with source code)
  • Nec 78K0 and Nec 78K0S (comes with source code)
  • STMicroelectronics ST9+, ST-10 (comes with source code)
  • SPARCII, ULTRASPARC
  • Siemens C166 (flow)
    C166
  • Tensilica Xtensa
  • Fujitsu F2MC-16L, Fujitsu F2MC-LC (comes with source code)

IDA Home supported processors

IDA Home supported processors

IDA Home is available in 5 versions, each supporting one of the common processor families:

  • x86/x64
  • ARM/ARM64
  • MIPS/MIPS64
  • PowerPC/PPC64
  • RISC-V/RV64

Debugger Modules

In IDA Pro all debugger modules are available.

Unsupported Processors

If your target processor is not included in the list above, you have two options:

  1. Ask us to add support for the processor sometime in the future: we welcome your feedback about which processors should be added to IDA Pro.
  2. Use our SDK and develop your own (free to all, but unsupported).

Supported file formats

IDA Pro can disassemble all popular file formats. The list contains some, but not all, of the file types handled by IDA Pro.

  • MS DOS
  • EXE File
  • MS DOS COM File
  • MS DOS Driver
  • New Executable (NE)
  • Linear Executable (LX)
  • Linear Executable (LE)
  • Portable Executable (PE) (x86, x64, ARM, etc)
  • Windows CE PE (ARM, SH-3, SH-4, MIPS)
  • Mach-O for OS X and iOS (x86, x64, ARM and PPC)
  • Dalvik Executable (DEX)
  • EPOC (Symbian OS executable)
  • Windows Crash Dump (DMP)
  • XBOX Executable (XBE)
  • Intel Hex Object File
  • MOS Technology Hex Object File
  • Netware Loadable Module (NLM)
  • Common Object File Format (COFF)
  • Binary File
  • Object Module Format (OMF)
  • OMF library
  • S-record format
  • ZIP archive
  • JAR archive
  • Executable and Linkable Format (ELF)
  • Watcom DOS32 Extender (W32RUN)
  • Linux a.out (AOUT)
  • PalmPilot program file
  • AIX ar library (AIAFF)
  • PEF (Mac OS or Be OS executable)
  • QNX 16 and 32-bits
  • Nintendo (N64)
  • SNES ROM file (SMC)
  • Motorola DSP56000 .LOD
  • Sony Playstation PSX executable files,
  • object (psyq) files
  • library (psyq) files

Check out the list of supported processors and screenshots of many processor disassemblies in the gallery.

Windmp file loader

Windmp file loader

The Windmp loader module can load *.dmp files into IDA for static analysis.

For the Windmp loader to function properly, one needs to specify the path to MS Debugger Engine Library (dbgeng.dll). This option can be set in CFG\IDA.CFG under the DBGTOOLS key. If this value is not set then Windmp will try to detect the path.

Windmp can be used to load big dump files, however that will result in a huge database, therefore it is possible to manually load a given input file:

  • Load modules segments only: If used, Windmp will only load segments related to the loaded modules and skips all other memory segments.

  • Do not load symbol names: If the symbol path is configured properly, then Windmp will fetch and rename all known addresses; you can skip this step by not loading symbol names.

  • Skip segments greater than: It skips segments with a given size, resulting in faster loading speed. If this value is zero then this option will not be used.

In addition to static analysis it is possible to run the dump file under the WinDbg debugger module.

Bitfields

There is a special kind of enums: bitfields. A bitfield is an enum divided into bit groups. When you define a new symbolic constant in a bitfield, you need to specify the group to which the constant will belong to. By default, IDA proposes groups containing one bit each. If a group is not defined yet, it is automatically created when the first constant in the group is defined. For example:

        name    CONST1
        value   0x1
        mask    0x1

will define a constant named CONST1 with value 1 and will create a group containing only one bit. Another example. Let’s consider the following definitions:

 #define OOF_SIGNMASK    0x0003
 #define   OOFS_IFSIGN   0x0000
 #define   OOFS_NOSIGN   0x0001
 #define   OOFS_NEEDSIGN 0x0002
 #define OOF_SIGNED      0x0004
 #define OOF_NUMBER      0x0008
 #define OOF_WIDTHMASK   0x0030
 #define   OOFW_IMM      0x0000
 #define   OOFW_16       0x0010
 #define   OOFW_32       0x0020
 #define   OOFW_8        0x0030
 #define OOF_ADDR        0x0040
 #define OOF_OUTER       0x0080
 #define OOF_ZSTROFF     0x0100

How do we describe this?

   name           value    mask   maskname

   OOFS_IFSIGN   0x0000   0x0003 OOF_SIGNMASK
   OOFS_NOSIGN   0x0001   0x0003 OOF_SIGNMASK
   OOFS_NEEDSIGN 0x0002   0x0003 OOF_SIGNMASK
 OOF_SIGNED      0x0004   0x0004
 OOF_NUMBER      0x0008   0x0008
   OOFW_IMM      0x0000   0x0030 OOF_WIDTHMASK
   OOFW_16       0x0010   0x0030 OOF_WIDTHMASK
   OOFW_32       0x0020   0x0030 OOF_WIDTHMASK
   OOFW_8        0x0030   0x0030 OOF_WIDTHMASK
 OOF_ADDR        0x0040   0x0040
 OOF_OUTER       0x0080   0x0080
 OOF_ZSTROFF     0x0100   0x0100

If a mask consists of more than one bit, it can have a name and a comment. A mask name can be set when a constant with the mask is being defined. IDA will display the mask names in a different color.

In order to use a bitfield in the program, just convert an instruction operand to enum. IDA will display the operand like this:

        mov     ax, 70h

will be replaced by

        mov     ax, OOFS_IFSIGN or OOFW_8 or OOF_ADDR

Bitfields Tutorial

In this tutorial, you will learn how to enhance disassembly output by using bitfields.

Suppose the source code looked like this:


// 'flags' parameter is combination of the following bits:
// (don't use OOF_SIGNMASK and OOF_WIDTHMASK, they are for the kernel)

#define OOF_SIGNMASK    0x0003      // sign output:
#define   OOFS_IFSIGN   0x0000      //   output sign if needed
#define   OOFS_NOSIGN   0x0001      //   should not out sign     ()
#define   OOFS_NEEDSIGN 0x0002      //   always out sign         (+-)
#define OOF_SIGNED      0x0004      // output as signed if 


int m65_opflags(const op_t &x)
{
  switch ( x.type )
  {
    case o_displ:
      return OOF_ADDR|OOFS_NOSIGN|OOFW_16;
    case o_near:
    case o_mem:
      return OOF_ADDR|OOF_NUMBER|OOFS_NOSIGN|OOFW_16|OOF_ZSTROFF;
    default:
      return 0;
  }
}

We have a disassembly that looks like this:

Let’s improve it by using bitfields.

  1. We first define a bitfield type by going to the Local types window (menu Open subviews -> Local types). We press Ins to add a new enum and make it a bitfield. The name given to the bitfield does not matter much.

Note that Bitmask has been checked. Click OK.

  1. Then we edit the enum and update it using the C syntax tab as shown in the screenshot below.

Click OK.

The first bitfield mask is 3 (or 2 bits). The name of the mask is not used by IDA, it is intended as a memory helper. The enum definition becomes:

  1. We finally switch to the disassembly window. Through the Edit -> Operand types -> Enum member menu (or by pressing M on the second operand at addresses 0x130003E39 and 0x130003E40) we select the enum type we just defined and get this result…

That’s all folks!

Structures Tutorial

You can use IDA to interactively define and manipulate structures in the disassembly.

Sample program

Consider this simple sample C program:

#include <stdio.h>

struct client {
  char code;
  long id;
  char name[32];
  client *next;
};

void print_clients(client *ptr) {
  while ( ptr != NULL ) {
    printf("ID: %4ld Name: %-32s\n",ptr->id,ptr->name);
    ptr = ptr->next;
  }
}
          

Standard disassembly

Here is the disassembly with no structures defined, as IDA automatically generates it:

.text:0000000180011690 ; void __fastcall print_clients(client *ptr)
.text:0000000180011690 ?print_clients@@YAXPEAUclient@@@Z proc near
.text:0000000180011690                                         ; CODE XREF: print_clients(client *)↑j
.text:0000000180011690                                         ; DATA XREF: .pdata:000000018001E800↓o
.text:0000000180011690
.text:0000000180011690 ptr             = qword ptr  10h
.text:0000000180011690
.text:0000000180011690                 mov     [rsp-8+ptr], rcx
.text:0000000180011695                 push    rbp
.text:0000000180011696                 push    rdi
.text:0000000180011697                 sub     rsp, 0E8h
.text:000000018001169E                 lea     rbp, [rsp+20h]
.text:00000001800116A3                 lea     rcx, __57CB66E6_entry@cpp ; JMC_flag
.text:00000001800116AA                 call    j___CheckForDebuggerJustMyCode
.text:00000001800116AA
.text:00000001800116AF
.text:00000001800116AF loc_1800116AF:                          ; CODE XREF: print_clients(client *)+5F↓j
.text:00000001800116AF                 cmp     [rbp+0D0h+ptr], 0
.text:00000001800116B7                 jz      short loc_1800116F1
.text:00000001800116B7
.text:00000001800116B9                 mov     rax, [rbp+0D0h+ptr]
.text:00000001800116C0                 add     rax, 8
.text:00000001800116C4                 mov     r8, rax
.text:00000001800116C7                 mov     rax, [rbp+0D0h+ptr]
.text:00000001800116CE                 mov     edx, [rax+4]
.text:00000001800116D1                 lea     rcx, _Format    ; "ID: %4ld Name: %-32s\n"
.text:00000001800116D8                 call    j_printf
.text:00000001800116D8
.text:00000001800116DD                 mov     rax, [rbp+0D0h+ptr]
.text:00000001800116E4                 mov     rax, [rax+28h]
.text:00000001800116E8                 mov     [rbp+0D0h+ptr], rax
.text:00000001800116EF                 jmp     short loc_1800116AF
.text:00000001800116EF
.text:00000001800116F1 ; ---------------------------------------------------------------------------
.text:00000001800116F1
.text:00000001800116F1 loc_1800116F1:                          ; CODE XREF: print_clients(client *)+27↑j
.text:00000001800116F1                 lea     rsp, [rbp+0C8h]
.text:00000001800116F8                 pop     rdi
.text:00000001800116F9                 pop     rbp
.text:00000001800116FA                 retn
.text:00000001800116FA
.text:00000001800116FA ?print_clients@@YAXPEAUclient@@@Z endp
        

Defining structures

In order to use meaningful names instead of numbers, we open the local types window and press insert to define a new structure type. Structure members can be added with the D key for data and the A key for ASCII strings or by editing the structure (Alt-E) and adding members using the “C syntax” of the “Edit type” dialog box. When the first method is used, when we add new structure members, IDA automatically names them. You can change any member’s name by pressing N.

struct client
{
  char code;
  int id;
  char name[32];
  client *next;
};
        

Improved disassembly

Finally, the defined structure type can be used to specify the type of an instruction operand. (menu Edit|Operand types|Struct offset).

.text:0000000180011690 ; void __fastcall print_clients(client *ptr)
.text:0000000180011690 ?print_clients@@YAXPEAUclient@@@Z proc near
.text:0000000180011690                                         ; CODE XREF: print_clients(client *)↑j
.text:0000000180011690                                         ; DATA XREF: .pdata:000000018001E800↓o
.text:0000000180011690
.text:0000000180011690 ptr             = qword ptr  10h
.text:0000000180011690
.text:0000000180011690                 mov     [rsp-8+ptr], rcx
.text:0000000180011695                 push    rbp
.text:0000000180011696                 push    rdi
.text:0000000180011697                 sub     rsp, 0E8h
.text:000000018001169E                 lea     rbp, [rsp+20h]
.text:00000001800116A3                 lea     rcx, __57CB66E6_entry@cpp ; JMC_flag
.text:00000001800116AA                 call    j___CheckForDebuggerJustMyCode
.text:00000001800116AA
.text:00000001800116AF
.text:00000001800116AF loc_1800116AF:                          ; CODE XREF: print_clients(client *)+5F↓j
.text:00000001800116AF                 cmp     [rbp+0D0h+ptr], 0
.text:00000001800116B7                 jz      short loc_1800116F1
.text:00000001800116B7
.text:00000001800116B9                 mov     rax, [rbp+0D0h+ptr]
.text:00000001800116C0                 add     rax, 8
.text:00000001800116C4                 mov     r8, rax
.text:00000001800116C7                 mov     rax, [rbp+0D0h+ptr]
.text:00000001800116CE                 mov     edx, [rax+client.id]
.text:00000001800116D1                 lea     rcx, _Format    ; "ID: %4ld Name: %-32s\n"
.text:00000001800116D8                 call    j_printf
.text:00000001800116D8
.text:00000001800116DD                 mov     rax, [rbp+0D0h+ptr]
.text:00000001800116E4                 mov     rax, [rax+client.next]
.text:00000001800116E8                 mov     [rbp+0D0h+ptr], rax
.text:00000001800116EF                 jmp     short loc_1800116AF
.text:00000001800116EF
.text:00000001800116F1 ; ---------------------------------------------------------------------------
.text:00000001800116F1
.text:00000001800116F1 loc_1800116F1:                          ; CODE XREF: print_clients(client *)+27↑j
.text:00000001800116F1                 lea     rsp, [rbp+0C8h]
.text:00000001800116F8                 pop     rdi
.text:00000001800116F9                 pop     rbp
.text:00000001800116FA                 retn
.text:00000001800116FA
.text:00000001800116FA ?print_clients@@YAXPEAUclient@@@Z endp

Union Tutorial

Suppose the source text looked like this:

#include <stdlib.h>

union urecord_t
{
  char c;
  short s;
  long l;
};

struct record_t
{
  int type;
#define RTYPE_CHAR      0
#define RTYPE_SHORT     1
#define RTYPE_LONG      2
  urecord_t u;
};

bool is_negative(record_t *r)
{
  switch ( r->type )
  {
    case RTYPE_CHAR:  return r->u.c < 0;
    case RTYPE_SHORT: return r->u.s < 0;
    case RTYPE_LONG:  return r->u.l < 0;
  }
  abort();
}

We have a disassembly like this:

Let’s improve it with unions. First, let’s define an union type. For this we open the Local types view (menu View|Local types), press Ins to create an union.

We create the union using the “C syntax” tab of the “Add type” dialog:

Switching to the disassembly window, we apply the defined structure through the Edit|Operand types|Struct offset menu item and select the proper representation for the operand. In the union type case, it may be necessary to select the desired union member with the Edit|Structs|Select union member command. The final disassembly looks like this:

That’s all folks !

Variable Length Structures Tutorial

Suppose the source text looked like this:

struct node_t
{
  long id;
  char *name;
  long nchild;                  // number of children
  long child[];                 // children
};

node_t n0 = { 0, "first",  2, { 1, 2 } };
node_t n1 = { 1, "second", 1, { 3 }    };
node_t n2 = { 2, "third",  1, { 4 }    };
node_t n3 = { 3, "fourth", 0,          };
node_t n4 = { 4, "fifth",  0,          };
      

Note that the length of the last field of the structure is not specified. In order to be able to create structures like this in a disassembly we must create a special kind of structure – a variable sized structure. A variable sized structure is created just as a normal structure is. The only difference is that the last member of the structure should be declared as an array with zero elements. (Just a reminder: arrays are declared with an * hotkey). Here is a sample variable sized structure definition:

Now we may switch to the disassembly window. In order to apply the defined structure we use Edit -> Structs -> Struct var … or Alt+Q. But since the structure size cannot be calculated by IDA we need to specify the desired structure size by selecting an area to convert to a structure. Another way to specify the size of a structure would be to use * hotkey. In all cases, you need to tell IDA the exact size of a variable sized structure. The initial disassembly will evolve from this to this:

to this:

That’s all folks !

Data types, operands and constructs

Data and operands available in the disassembly aren’t always interpreted in the most suitable way: IDA’s interactivity allows you to change their type and representation. It even makes high level languages like constructs possible.

Have a look at our data structure tutorial.

{% file src=“datastruct-tutorial/datastruct.pdf” %} Download Data Structure tutorial {% endfile %}

Using IDA to deal with packed executables

Many malware authors attempt to obfuscate or protect their program by packing them. In these tutorials, we show how IDA can be made to handle such program.

  • Learn how to tackle a difficult executable from the normal user interface.
  • Learn how to use the “universal” PE unpacker plug-in (PDF) included in IDA 4.9

{% file src=“packed-executables/unpacking.pdf” %} Download a tutorial about PE unpacker plugin {% endfile %}

Using IDA debugger to unpack an “hostile” PE executable

Several days ago we received, from an IDA user, a small harmless executable (test00.zip; unpack twice with the password 123) that could not be debugged in IDA.

{% file src=“packed-executables/assets/test00.zip” %}

Breakpoints would not break and, the program would run out of control, as if the debugger was too slow to catch it. When we first loaded the program in IDA, it complained that it could not find the imports section. That type of situation is frequent with protected executables, packed worms etc….

The second remarkable thing is that the entry point jumping… nowhere. Addresses marked in red usually reflect a location that IDA can’t resolve.

This code employs attempts to prevent the disassembly and, as a result, the default load parameters are not appropriate. This type of obfuscated code demonstrates the problems inherent to the a one-click approach.

But what if we investigate a bit further, for example by loading the file in the manual mode? In this mode the user can specify which sections of the file should be loaded. To be on the safe side, let’s load all sections. Let’s uncheck the ‘make imports section’ checkbox to avoid the “missing imports” message. We have this:

Once we have answered the questions about each section of the file we will get this listing: much better!

Now that we got rid of the unresolved address, we can analyze the program. The first instruction of our executable is a jump, and it jumps to the program header: loc_400158. Hmmmm, the program header is not supposed to contain any code but this program abuses the conventions and jumps to it. An interesting side effect results of the fact that the program header is read only. That could explain why breakpoints can’t be put there.

Anyway, let’s see how the program works. We see that the program loads a pointer into ESI which gets immediately copied to EBX:

HEADER:00400158                 mov     esi, offset off_40601C
HEADER:0040015D                 mov     ebx, esi

(Ctrl-O converted the hexadecimal number in the first instruction to a label expression)

Later the value of EBX is used to call a subroutine:

HEADER:00400169                 call    dword ptr [ebx]

Calls like this are frequent in the listing, so let’s find out the function and what it does. Apparently a pointer to the function is located here:

__u_____:0040601C off_40601C      dd offset __ImageBase+130h

If we click on __ImageBase, what we’ll see is an array of dwords. IDA represented the program header as an array which is incorrect in our case. We undefine the array (hotkey U), go back to the pointer (hotkey Esc) and follow the pointer again. This time we will end up at the address 0x400130 which should contain a function. We are sure of that because the instruction at 0x400169 calls 0x400130 indirectly. We press P (create procedure or function) to tell IDA that there should be a function at the current address.While the function is now on screen, we only have half of it! It seems that the person who wrote that program wanted it to obfuscate it and separated the function into several pieces. IDA now knows how to deal with those fragmented functions and displays information about the other function parts on the screen:

But it has only references to other parts. It would be nice to have the whole function on one page. There is a special command to help us: the command to generate flow charts of functions in IDA, it’s hotkey is F12. This command is especially interesting for fragmented functions like ours because all pieces of the function will be on the screen:

It might be interesting to display the flow chart of the main function (very long function, keep scrolling!):

A quick glance at the flow chart reveals that there is only one exit from the function at its “ret” instruction (0x4001FA). We could put a breakpoint there and let the program run. Now, before we do that, let’s repeat that it is not a good idea to run untrusted code on your computer. It is much better to have a separate “sandbox” machine for such tests, for example using the remote debugging facilities IDA offers. Therefore, IDA displays a warning when a new file is going to be started under debugger: ignore at your own risk.

Since the breakpoint is located in the program header, and the program header is write protected by the system, we cannot use a plain software breakpoint. We have to use a hardware breakpoint: first press F2 to create a breakpoint, then right click and select “edit breakpoint” to change it to a hardware breakpoint on the “execution” event:

After having set the breakpoint, we start the debugger by pressing F9. When we reach the breakpoint, the program will be unpacked into the ‘MEW’ segment. We jump there and convert everything to code (the fastest way to do this is to press F7 at the breakpoint).

Now we have a very nice listing but with one major problem: it is ephemeral – as soon as we’ll stop the debugging session, the listing will disappear.

The reason is of course that the listing displays the memory content and that the memory will cease to exist when the process will die. It would be nice to be able to save the memory into the database and continue the analysis without the debugger. We will think about adding that feature into future versions of IDA, but meanwhile we’ll have to do it manually. By “manually” we do not mean to copy byte one by one on a paper, of course. We can use the built-in IDC language to achieve this.

There are two things to be saved because they will disappear when the debugger stops: the memory contents and the imported function names. The memory contents can be saved by using the following 4-line script:

auto fp, ea;
fp = fopen("bin", "wb");
for ( ea=0x401000; ea < 0x406000; ea++ )
  fputc(Byte(ea), fp);

When the script has run, we will have a file named “bin” on the disk. It will contain the bytes from the “MEW” segment. As you can see, I hardcoded the hexadecimal addresses: after all, it is a disposable script intended to be run once.

We have to save the imported function names too. Look at the call at 0x401002, for example:

MEW:00401002 call    sub_4012DC

If we want to know the name of the called function, we press Enter several times to follow the links and finally get the name:

kernel32.dll:77E7AD86
kernel32.dll:77E7AD86 kernel32_GetModuleHandleA:              ; CODE XREF: sub_4012DCj
kernel32.dll:77E7AD86                                         ; DATA XREF: MEW:off_402000o
kernel32.dll:77E7AD86 cmp     dword ptr [esp+4], 0

When we quit the debugger, the kernel32.dll segment will disappear from the listing along with all its names, instructions, functions, everything. We have to copy the function names before that:

auto ea, name;
for (ea = 0x401270; ea<0x4012e2; ea =ea+6 )
{
  name = Name(Dword(Dfirst(ea)));               /* get name */
  name = substr(name, strstr(name, "_")+1, -1); /* drop the prefix */
  MakeName(ea, name);
}

Now that we have run those scripts, we may stop the debugger (press Ctrl-F2) and copy back the memory contents. The “Load additional binary file” command in the File, Load menu is the way to go:

Please note that it is not necessary to create a segment, it already exists (clear the “create segments” flag). Also, the address is specified in paragraphs, i.e. it is shifted to the right by 4.

Load the file, press P at 0x401000 and voila, you have a nice listing:

The rest of the analysis is a pleasant and agreeable task left to the reader as…. you guessed it.

Decompiler

Prerequisites
Quick primer
Exception handler
Interactive operation
Introduction to Decompilation vs. Disassembly
Batch operation
Configuration
Third party plugins
Floating point support
Support for intrinsic functions
Overlapped variables
gooMBA
Failures and troubleshooting
FAQ
Limitations
Tips and tricks

Prerequisites

The decompiler requires the latest version of IDA. While it may work with older versions (we try to ensure compatibility with a couple of previous versions), the best results are obtained with the latest version: first, IDA analyses files better; second, the decompiler can use additional available functionality.

The decompiler runs on MS Windows, Linux, and Mac OS X. It can decompile programs for other operating systems, provided they have been built using GCC/Clang/Visual Studio/Borland compilers.

IDA loads appropriate decompilers depending on the input file. If it cannot find any decompiler for the current input file, no decompilers will be loaded at all.

The GUI version of IDA is required for the interactive operation. For the text mode version, only the batch operation is supported.

Quick primer

Let’s start with a very short and simple function:

We decompile it with View, Open subviews, Pseudocode (hotkey F5):

While the generated C code makes sense, it is not pretty. There are many cast operations cluttering the text. The reason is that the decompiler does not perform the type recovery yet. Apparently, the a1 argument points to a structure but the decompiler missed it. Let us add some type information to the database and see what happens. For that we will open the Local Types window (Shift-F1) and add a new structure type:

After that, we switch back to the pseudocode window and specify the type of a1. We can do it by positioning the cursor on any occurrence of a1 and pressing Y:

When we press Enter, the decompilation output becomes much better:

But there is some room for improvement. We could rename the structure fields and specify their types. For example, field_6B1 seems to be used as a counter and field_6B5 is obviously a function pointer. We can do all this without switching windows now. Only the initial structure definition required the Local Types window. Here is how we specify the type of the function pointer field:

The final result looks like this:

Please note that there are no cast operations in the text and overall it looks much better than the initial version.


    Exception handler

    x64 MSVC C++ Exception Handler for the Decompiler

    Hex-Rays’ support for exceptions in Microsoft Visual C++/x64 incorporates the C++ exception metadata for functions into their decompilation, and presents the results to the user via built-in constructs in the decompilation (try, catch, __wind, __unwind). When the results cannot be presented entirely with these constructs, they will be presented via helper calls in the decompilation.

    The documentation describes:

    • Background behind C++ exception metadata. It is recommended that users read this first.
    • Interactive operation via the GUI, configuration file, and keyboard shortcuts.
    • A list of helper calls that may appear in the output.
    • A note about the boundaries of try and __unwind regions.
    • Miscellaneous notes about the plugin.

    BACKGROUND ON C++ EXCEPTIONS

    TRY, CATCH, AND THROW

    The C++ language provides the try scoped construct in which the developer expects that an exception might occur. try blocks must be followed by one or more scoped catch constructs for catching exceptions that may occur within. catch blocks may use ... to catch any exception. Alternatively, catch blocks may name the type of an exception, such as std::bad_alloc. catch blocks with named types may or may not also catch the exception object itself. For example, catch(std::bad_alloc *v10) and catch(std::bad_alloc *) are both valid. The former can access the exception object through variable v10, whereas the latter cannot access the exception object.

    C++ provides the throw keyword for throwing an exception, as in std::bad_alloc ba; throw ba;. This is represented in the output as (for example) throw v10;. C++ also allows code to rethrow the current exception via throw;. This is represented in the output as throw;.

    WIND AND UNWIND

    Exception metadata in C++ binaries is split into two categories: try and catch blocks, as discussed above, and so-called wind and unwind blocks. C++ does not have wind and unwind keywords, but the compiler creates these blocks implicitly. In most binaries, they outnumber try and catch blocks by about 20 to 1.

    Consider the following code, which may or may not throw an int as an exception at three places:

    void may_throw() 
    {
      // Point -1
      if ( rand() % 2 )
        throw -1;
    
      string s0 = "0";
    
      // Point 0
      if ( rand() % 2 )
        throw 0;
    
      string s1 = "1";
    
      // Point 1
      if ( rand() % 2 )
        throw 1;
    
      // Point 2
      printf("%s %sn",
        s0.c_str(),
        s1.c_str());
    
      // Implicit
      // destruction
      s1.~string();
      s0.~string();
    }
    

    If an exception is thrown at point -1, the function exits early without executing any of its remaining code. As no objects have been created on the stack, nothing needs to be cleaned up before the function returns.

    If an exception is thrown at point 0, the function exits early as before. However, since string s0 has been created on the stack, it needs to be destroyed before exiting the function. Similarly, if an exception is thrown at point 1, both string s1 and string s0 must be destroyed.

    These destructor calls would normally happen at the end of their enclosing scope, i.e. the bottom of the function, where the compiler inserts implicitly-generated destructor calls. However, since the function does not have any try blocks, none of the function’s remaining code will execute after the exception is thrown. Therefore, the destructor calls at the bottom will not execute. If there were no other mechanism for destructing s0 and/or s1, the result would be memory leaks or other state management issues involving those objects. Therefore, the C++ exception management runtime provides another mechanism to invoke their destructors: wind blocks and their corresponding unwind handlers.

    wind blocks are effectively try blocks that are inserted invisibly by the compiler. They begin immediately after constructing some object, and end immediately before destructing that object. Their unwind blocks play the role of catch handlers, calling the destructor upon the object when exceptional control flow would otherwise cause the destructor call to be skipped.

    Microsoft Visual C++ effectively transforms the previous example as follows:

    void may_throw_transformed() 
    {
      if ( rand() % 2 )
        throw -1;
    
      string s0 = "0";
    
      // Implicit try
      __wind
      {
        if ( rand() % 2 )
          throw 0;
    
        string s1 = "1";
    
        // Implicit try
        __wind 
        {
          if ( rand() % 2 )
            throw 1;
    
          printf("%s %sn",
            s0.c_str(),
            s1.c_str());
        }
    
        // Implicit catch
        __unwind
        {
          s1.~string();
        }
        s1.~string();
      }
    
      // Implicit catch
      __unwind 
      {
        s0.~string();
      }
      s0.~string();
    }
    

    unwind blocks always re-throw the current exception, unlike catch handlers, which may or may not re-throw it. Re-throwing the exception ensures that prior wind blocks will have a chance to execute. So, for example, if an exception is thrown at point 1, after the unwind handler destroys string s1, re-throwing the exception causes the unwind handler for point 0 to execute, thereby allowing it to destroy string s0 before re-throwing the exception out of the function.

    STATE NUMBERS AND INSTRUCTION STATES

    As we have discussed, the primary components of Microsoft Visual C++ x64 exception metadata are try blocks, catch handlers, wind blocks, and unwind handlers. Generally speaking, these elements can be nested within one another. For example, in C++ code, it is legal for one try block to contain another, and a catch handler may contain try blocks of its own. The same is true for wind and unwind constructs: wind blocks may contain other wind blocks (as in the previous example) or try blocks, and try and catch blocks may contain wind blocks.

    Exceptions must be processed in a particular sequence: namely, the most nested handlers must be consulted first. For example, if a try block contains another try block, any exceptions occurring within the latter region must be processed by the innermost catch handlers first. Only if none of the inner catch handlers can handle the exception should the outer try block’s catch handlers be consulted. Similarly, as in the previous example, unwind handlers must destruct their corresponding objects before passing control to any previous exception handlers (such as string s1’s unwind handler passing control to string s0’s unwind handler).

    Microsoft’s solution to ensure that exceptions are processed in the proper sequence is simple. It assigns a “state number” to each exception-handling construct. Each exception state has a “parent” state number whose handler will be consulted if the current state’s handler is unable to handle the exception. In the previous example, what we called “point 0” is assigned the state number 0, while “point 1” is assigned the state number 1. State 1 has a parent of 0. (State 0’s parent is a dummy value, -1, that signifies that it has no parent.) Since unwind handlers always re-throw exceptions, if state 1’s unwind handler is ever invoked, the exception handling machinery will always invoke state 0’s unwind handler afterwards. Because state 0 has no parent, the exception machinery will re-throw the exception out of the current function. This same machinery ensures that the catch handlers for inner try blocks are consulted before outer try blocks.

    There is only one more piece to the puzzle: given that an exception could occur anywhere, how does the exception machinery know which exception handler should be consulted first? I.e., for every address within a function with C++ exception metadata, what is the current exception state? Microsoft C++/x64 binaries provide this information in the IPtoStateMap metadata tables, which is an array of address ranges and their corresponding state numbers.

    GUI OPERATION

    This support is fully automated and requires no user interaction. However, the user can customize the display of C++ exception metadata elements for the global database, as well as for individual functions.

    GLOBAL SETTINGS

    Under the Edit -> Other-> C++ exception display settings menu item, the user can edit the default settings to control which exception constructs are shown in the listing. These are saved persistently in the database (i.e., the user’s choices are remembered after saving, closing, and re-opening), and can also be adjusted on a per-function basis (described later).

    The settings on the dialog are as follows:

    • Default output mode:

    When the plugin is able to represent C++ exception constructs via nice constructs like try, catch, __wind, and __unwind in the listings, these are called “structured” exception states. The plugin is not always able to represent exception metadata nicely, and may instead be forced to represent the metadata via helper calls in the listing (which are called “unstructured” states). As these can be messy and distracting, users may prefer not to see them by default. Alternatively, the user may prefer to see no exception metadata whatsoever, not even the structured ones. This setting allows the user to specify which types of metadata will be shown in the listing.

    • Show wind states:

    We discussed wind states and unwind handlers in the background material. Although these states can be very useful when reverse engineering C++ binaries (particularly when analyzing constructors), displaying them increases the amount of code in the listing, and sometimes the information they provide is more redundant than useful. Therefore, this checkbox allows the user to control whether they are shown by default.

    • Inform user of hidden states:

    The two settings just discussed can cause unstructured and/or wind states to be omitted from the default output. If this checkbox is enabled, then the plugin will inform the user of these omissions via messages at the top of the listing, such as this message indicating that one unstructured wind state was omitted: // Hidden C++ exception states: #wind_helpers=1

    The contents of these messages depend upon the settings from above, and the facts about which states were hidden from display. If output of exception blocks is entirely disabled, the messages will not appear, even if this setting is enabled.

    The following notes all assume that output is enabled.

    • If the settings indicated that unstructured states should be hidden, and there were hidden (unstructured) try states, the message will say something like #try_helpers=2.

    • If the settings indicated that all wind states should be hidden, then the message might say something like #wind=3 to indicate the total number of hidden wind states.

    • If the settings indicated that wind states should be shown, but that unstructured states should be hidden, then the message might show something like #wind_helpers=1 to indicate that one unstructured wind state was hidden.

    There are three more elements on the settings dialog; most users should never have to use them. However, for completeness, we will describe them now.

    • Warning behavior:

    When internal warnings occur, they will either be printed to the output window at the bottom, or shown as a pop-up warning message box depending on this setting.

    • Reset per-function settings:

    The next section will discuss how the display settings described above can be customized on a per-function basis. This button allows the user to erase all such saved settings, such that all functions will use the global display settings the next time they are decompiled.

    • Rebuild C++ metadata caches:

    Before the plugin can show C++ exception metadata in the output, it must pre-process the metadata across the whole binary. Doing so crucially relies upon the ability to recognize the __CxxFrameHandler3 and/or __CxxFrameHandler4 unwind handler functions when they are referenced by the binary’s unwind metadata. If the plugin fails to recognize one of these functions, then it will be unable to display C++ exception metadata for any function that uses the unrecognized unwind handler(s).

    If the user suspects that a failure like this has taken place – say, because they expect to see a try/catch in the output and it is missing, and they have confirmed that the output was not simply hidden due to the display settings above – then this button may help them to diagnose and repair the issue. Pressing this button flushes the existing caches from the database and rebuilds them. It also prints output to tell the user which unwind handlers were recognized and which ones were not. The user can use these messages to confirm whether the function’s corresponding unwind handler was unrecognized. If it was not, the user can rename the unwind handler function to something that contains one of the two aforementioned names, and then rebuild the caches again.

    Note that users should generally not need to use this button, as the plugin tries several methods to recognize the unwind handlers (such as FLIRT signatures, recognizing import names, and looking at the destination of “thunk” functions with a single jmp to a destination function). If the user sees any C++ exception metadata in the output, this almost always means that the recognition worked correctly. This button should only be used by experienced users as a last resort. Users are advised to save their database before pressing this button, and only proceed with the changes if renaming unwind handlers and rebuilding the cache addresses missing metadata in the output.

    CONFIGURATION

    The default options for the settings just described are controlled via the %IDADIR%/cfg/eh34.cfg configuration file. Editing this file will change the defaults for newly-created databases (but not affect existing databases).

    PER-FUNCTION SETTINGS

    As just discussed, the user can control which C++ exception metadata is displayed in the output via the global menu item. Users can also customize these settings on a per-function basis (say, by enabling display of wind states for selected functions only), and they will be saved persistently in the database.

    When a function has C++ exception metadata, one or more items will appear on Hex-Rays’ right click menu. The most general one is “C++ exception settings…”. Selecting this menu item will bring up a dialog that is similar to the global settings menu item with the following settings:

    • Use global settings.

    If the user previously changed the settings for the function, but wishes that the function be shown via the global settings in the future, they can select this item and press “OK”. This will delete the saved settings for the function, causing future decompilations to use the global settings.

    • This function’s output mode:

    This functions identically to “Default output mode” from the global settings dialog, but only affects the current function.

    • Show wind states:

    Again, identical to the global settings dialog item.

    There is a button at the bottom, “Edit global settings”, which is simply a shortcut to the same global settings dialog from the Edit -> Other -> C++ exception display settings menu item.

    The listing will automatically refresh if the user changes any settings.

    Additionally, there are four other menu items that may or may not appear, depending upon the metadata present and whether the settings caused any metadata to be hidden. These menu items are shortcuts to editing the corresponding fields in the per-function settings dialog just discussed. They are:

    • Show unstructured C++ states:

    If the global or per-function default output setting was set to “Structured only”, and the function had unstructured states, this menu item will appear. Clicking it will enable display of unstructured states for the function and refresh the decompilation.

    • Hide unstructured C++ states:

    Similar to the above.

    • Show wind states:

    If the global or per-function “Show wind states” setting was disabled, and the function had wind states, this menu item will appear. Clicking it will enable display of wind states for the function and refresh the decompilation.

    • Hide wind states:

    Similar to the above.

    KEYBOARD SHORTCUTS

    The user can change (add, remove, or edit) the keyboard shortcuts for the per-function settings right-click menu items from the Edit -> Options -> Shortcuts dialog. The names of the corresponding actions are:

    TitleName
    “Show unstructured C++ states”eh34:enable_unstructured
    “Hide unstructured C++ states”eh34:disable_unstructured
    “Show wind states”eh34:enable_wind
    “Hide wind states”eh34:disable_wind
    The global settings dialogeh34:config_menu

    HELPER CALLS

    Hex-Rays’ Microsoft C++ x64 exception support tries to hide low-level details about exception state numbers as much as possible. However, compiler optimizations can cause binaries to diverge from the original source code. For example, inlined functions can produce goto statements in the decompilation despite there being none in the source. Optimizations can also cause C++ exception metadata to differ from the original code. As a result, it is not always possible to represent try, catch, wind, and unwind constructs as scoped regions that hide the low-level details.

    In these cases, Hex-Rays’ Microsoft C++ x64 exception support will produce helper calls with informative names to indicate when exception states are entered and exited, and to ensure that the user can see the bodies of catch and unwind handlers in the output. The user can hover their mouse over those calls to see their descriptions. They are also catalogued below.

    The following helper calls are used when exception states have multiple entrypoints, or multiple exits:

    Function nameDescription
    __eh34_enter_wind_state(s1, s2)switch state from parent state s1 to child wind state s2
    __eh34_enter_try_state(s1, s2)switch state from parent state s1 to child try state s2
    __eh34_exit_wind_state(s1, s2)switch state from child wind state s1 to parent state s2
    __eh34_exit_try_state(s1, s2)switch state from child try state s1 to parent state s2

    The following helper calls are used when exception states had single entry and exit points, but could not be represented via try or __wind keywords:

    Function nameDescription
    __eh34_wind(s1, s2)switch state from parent state s1 to child state s2; a new c++ object that requires a dtr has been created
    __eh34_try(s1, s2)switch state from parent state s1 to child state s2; mark beginning of a try block

    The following helper calls are used to display catch handlers for exception states that could not be represented via the catch keyword:

    Function nameDescription
    __eh34_catch(s)beginning of catch blocks at state s; s corresponds to the second argument of the matching try call (if present)
    __eh34_catch_type(s, "handler_address")a catch statement for the type described at "handler_address"
    __eh34_catch_ellipsis(s)catch all“ statement

    The following helper calls should be removed, but if you see them, they signify the boundary of a catch handler:

    Function nameDescription
    __eh34_try_continuation(s, i, ea)end of catch handler i for state s, returning to address ea
    __eh34_caught_type(s, "handler_address")a pairing call for __eh34_catch_type when catch handler has no continuation
    __eh34_caught_ellipsis(s)“caught all”, paired with __eh34_catch_ellipsis when catch handler has no continuation

    The following helper calls are used to display unwind handlers for exception states that could not be represented via the __unwind keyword:

    Function nameDescription
    __eh34_unwind(s)destruct the c++ object created immediately before entering state s; s corresponds to the second argument of the matching wind call (if present)

    The following helper calls are used to signify that an unwind handler has finished executing, and will transfer control to a parent exception state (or outside of the function):

    Function nameDescription
    __eh34_continue_unwinding(s1, s2)after unwinding at child state s1, switch to parent state s2 and perform its unwind or catch action
    __eh34_propagate_exception_into_caller(s1, s2)after unwinding at child state s1, switch to root state s2; this corresponds to the exception being propagated into the calling function

    The following helper call is used when the exception metadata did not specify a function pointer for an unwind handler, which causes program termination:

    Function nameDescription
    __eh34_no_unwind_handler(s)the state s did not have an unwind handler, which causes program termination in the event that an exception reaches it

    The following helper calls are used to signify that Hex-Rays was unable to display an exception handler in the decompilation:

    Function nameDescription
    __eh34_unwind_handler_absent(s, ea)could not inline unwind handler at ea for wind state s
    __eh34_catch_handler_absent(s, i, ea)could not inline i’th catch handler at ea for try state s

    BOUNDARIES OF EXCEPTION REGIONS

    From Microsoft Visual Studio versions 2005 (toolchain version 8.0) to 2017 Service Pack 2 (version 14.12), the compiler emitted detailed metadata that precisely defined the boundaries of all exception regions within C++ functions. This made binary files large, and not all of the metadata was strictly necessary for the runtime library to handle C++ exceptions correctly.

    Starting from MSVC 2017 Service Pack 3 (version 14.13), the compiler began applying optimizations to reduce the size of the C++ exception metadata. An official Microsoft blog entry entitled: “Making C++ Exception Handling Smaller on x64” describes the first change as “dropping metadata for regions of code that cannot throw and folding logically identical states”. (Version 14.23 later introduced the __CxxFrameHandler4 metadata format to compress the metadata further.)

    As a result of these changes, the C++ exception metadata in MSVC 14.13+ binaries is no longer fully precise. Exception states are frequently reported as beginning physically after where the source code would indicate. In order to produce usable output, Hex-Rays employs mathematical optimization algorithms to reconstruct more detailed C++ exception metadata configurations that can be displayed in a nicer format in the decompilation. These algorithms improve the listings by producing more structured regions and fewer helper calls in the output, but they introduce further imprecision as to the true starting and ending locations of exception regions when compared to the source code. They are an integral part of Hex-Rays C++/x64 Windows exception metadata support and cannot be disabled.

    The takeaway is that, when processing MSVC 14.13+ binaries, Hex-Rays C++/x64 Windows exception support frequently produces try and __unwind blocks that begin and/or end earlier and/or later than what the source code would indicate, were it available. This has important consequences for vulnerability analysis.

    For example, given accurate exception boundary information, the destructor for a local object would ordinarily be situated after the end of that object’s __wind and __unwind blocks, as in:

    Object::Constructor(&v14);
    __wind
    {
      // ...
    }
    __unwind
    {
      Object::Destructor(&v14);
    }
    
    // HERE: destructor after __wind region
    Object::Destructor(&v14);
    

    Yet, due to the imprecise boundary information, Hex-Rays might display the destructor as being inside of the __wind block:

    Object::Constructor(&v14);
    __wind
    {
      // ...
      // HERE: destructor inside of __wind region
      Object::Destructor(&v14);
    }
    __unwind
    {
      Object::Destructor(&v14);
    }
    

    The latter output might indicate that v14’s destructor would be called twice if its destructor were to throw an exception. However, this indication is simply the result of imprecise exception region boundary information. In short, users should be wary of diagnosing software bugs or security issues based upon the positioning of statements nearby the boundaries of try and __wind blocks. The example above indicates something that might appear to be a bug in the code – a destructor being called twice – but is in fact not one.

    These considerations primarily apply when analyzing C++ binaries compiled with MSVC 14.13 or greater. They do not apply as much to binaries produced by MSVC 14.12 or earlier, when the compiler emitted fully precise information about exception regions.

    Although Hex-Rays may improve its detection of exception region boundaries in the future, because modern binaries lack the ground truth of older binaries, the results will never be fully accurate. If the imprecision is unacceptable to you, we recommend permanently disabling C++ metadata display via the eh34.cfg file discussed previously.

    MISCELLANEOUS

    Hex-Rays’ support for exceptions in Microsoft Visual C++/x64 only works after auto-analysis has been completed. Users can explore the database and decompile functions as usual, but no C++ exception metadata will be shown. Users are advised to refresh any decompilation windows after auto-analysis has completed.

    If users have enabled display of wind states, they may see empty __wind or __unwind constructs in the output. Usually, this does not indicate an error occurred; this usually means that the region of the code corresponding the wind state was very small or contained dead code, and Hex-Rays normal analysis and transformation made it empty.

    Starting in IDA 9.0, IDA’s auto-analysis preprocesses C++ exception metadata differently than in previous versions. In particular, on MSVC/x64 binaries, __unwind and catch handlers are created as standalone functions, not as chunks of their parent function as in earlier versions. This is required to display the exception metadata correctly in the decompilation. For databases created with older versions, the plugin will still show the outline of the exception metadata, but the bodies of the __unwind and catch handlers will be displayed via the helper calls __eh34_unwind_handler_absent and __eh34_catch_handler_absent, respectively. The plugin will also print a warning at the top of the decompilation such as Absent C++ exception handlers: # catch=1 (pre-9.0 IDB) in these situations. Re-creating the IDB with a newer version will solve those issues, although users might still encounter absent handlers in new databases (rarely, and under different circumstances).

    Introduction to Decompilation vs. Disassembly

    A decompiler represents executable binary files in a readable form. More precisely, it transforms binary code into text that software developers can read and modify. The software security industry relies on this transformation to analyze and validate programs. The analysis is performed on the binary code because the source code (the text form of the software) traditionally is not available, because it is considered a commercial secret.

    Programs to transform binary code into text form have always existed. Simple one-to-one mapping of processor instruction codes into instruction mnemonics is performed by disassemblers. Many disassemblers are available on the market, both free and commercial. The most powerful disassembler is our own IDA Pro. It can handle binary code for a huge number of processors and has open architecture that allows developers to write add-on analytic modules.

    Decompilers are different from disassemblers in one very important aspect. While both generate human readable text, decompilers generate much higher level text which is more concise and much easier to read.

    Compared to low level assembly language, high level language representation has several advantages:

    • It is consise.
    • It is structured.
    • It doesn’t require developers to know the assembly language.
    • It recognizes and converts low level idioms into high level notions.
    • It is less confusing and therefore easier to understand.
    • It is less repetitive and less distracting.
    • It uses data flow analysis.

    Let’s consider these points in detail.

    Usually the decompiler’s output is five to ten times shorter than the disassembler’s output. For example, a typical modern program contains from 400KB to 5MB of binary code. The disassembler’s output for such a program will include around 5-100MB of text, which can take anything from several weeks to several months to analyze completely. Analysts cannot spend this much time on a single program for economic reasons.

    The decompiler’s output for a typical program will be from 400KB to 10MB. Although this is still a big volume to read and understand (about the size of a thick book), the time needed for analysis time is divided by 10 or more.

    The second big difference is that the decompiler output is structured. Instead of a linear flow of instructions where each line is similar to all the others, the text is indented to make the program logic explicit. Control flow constructs such as conditional statements, loops, and switches are marked with the appropriate keywords.

    The decompiler’s output is easier to understand than the disassembler’s output because it is high level. To be able to use a disassembler, an analyst must know the target processor’s assembly language. Mainstream programmers do not use assembly languages for everyday tasks, but virtually everyone uses high level languages today. Decompilers remove the gap between the typical programming languages and the output language. More analysts can use a decompiler than a disassembler.

    Decompilers convert assembly level idioms into high-level abstractions. Some idioms can be quite long and time consuming to analyze. The following one line code

    x = y / 2;

    can be transformed by the compiler into a series of 20-30 processor instructions. It takes at least 15- 30 seconds for an experienced analyst to recognize the pattern and mentally replace it with the original line. If the code includes many such idioms, an analyst is forced to take notes and mark each pattern with its short representation. All this slows down the analysis tremendously. Decompilers remove this burden from the analysts.

    The amount of assembler instructions to analyze is huge. They look very similar to each other and their patterns are very repetitive. Reading disassembler output is nothing like reading a captivating story. In a compiler generated program 95% of the code will be really boring to read and analyze. It is extremely easy for an analyst to confuse two similar looking snippets of code, and simply lose his way in the output. These two factors (the size and the boring nature of the text) lead to the following phenomenon: binary programs are never fully analyzed. Analysts try to locate suspicious parts by using some heuristics and some automation tools. Exceptions happen when the program is extremely small or an analyst devotes a disproportionally huge amount of time to the analysis. Decompilers alleviate both problems: their output is shorter and less repetitive. The output still contains some repetition, but it is manageable by a human being. Besides, this repetition can be addressed by automating the analysis.

    Repetitive patterns in the binary code call for a solution. One obvious solution is to employ the computer to find patterns and somehow reduce them into something shorter and easier for human analysts to grasp. Some disassemblers (including IDA Pro) provide a means to automate analysis. However, the number of available analytical modules stays low, so repetitive code continues to be a problem. The main reason is that recognizing binary patterns is a surprisingly difficult task. Any “simple” action, including basic arithmetic operations such as addition and subtraction, can be represented in an endless number of ways in binary form. The compiler might use the addition operator for subtraction and vice versa. It can store constant numbers somewhere in its memory and load them when needed. It can use the fact that, after some operations, the register value can be proven to be a known constant, and just use the register without reinitializing it. The diversity of methods used explains the small number of available analytical modules.

    The situation is different with a decompiler. Automation becomes much easier because the decompiler provides the analyst with high level notions. Many patterns are automatically recognized and replaced with abstract notions. The remaining patterns can be detected easily because of the formalisms the decompiler introduces. For example, the notions of function parameters and calling conventions are strictly formalized. Decompilers make it extremely easy to find the parameters of any function call, even if those parameters are initialized far away from the call instruction. With a disassembler, this is a daunting task, which requires handling each case individually.

    Decompilers, in contrast with disassemblers, perform extensive data flow analysis on the input. This means that questions such as, “Where is the variable initialized?”“ and, “Is this variable used?” can be answered immediately, without doing any extensive search over the function. Analysts routinely pose and answer these questions, and having the answers immediately increases their productivity.

    Side-by-side comparisons of disassembly and decompilation

    Below you will find side-by-side comparisons of disassembly and decompilation outputs. The following examples are available:

    The following examples are displayed on this page:

    1. Division by two
    2. Simple enough?
    3. Where’s my variable?
    4. Arithmetics is not a rocket science
    5. Sample window procedure
    6. Short-circuit evaluation
    7. Inlined string operations

    Division by two

    Just note the difference in size! While the disassemble output requires you not only to know that the compilers generate such convoluted code for signed divisions and modulo operations, but you will also have to spend your time recognizing the patterns. Needless to say, the decompiler makes things really simple.

    {% tabs %} {% tab title=“Assembler code” %}

    ; =============== S U B R O U T I N E =======================================
    ; int __cdecl sub_4061C0(char *Str, char *Dest)
    sub_4061C0      proc near               ; CODE XREF: sub_4062F0+15p
                                            ; sub_4063D4+21p ...
    Str             = dword ptr  4
    Dest            = dword ptr  8
                    push    esi
                    push    offset aSmtp_   ; "smtp."
                    push    [esp+8+Dest]    ; Dest
                    call    _strcpy
                    mov     esi, [esp+0Ch+Str]
                    push    esi             ; Str
                    call    _strlen
                    add     esp, 0Ch
                    xor     ecx, ecx
                    test    eax, eax
                    jle     short loc_4061ED
    loc_4061E2:                             ; CODE XREF: sub_4061C0+2Bj
                    cmp     byte ptr [ecx+esi], 40h
                    jz      short loc_4061ED
                    inc     ecx
                    cmp     ecx, eax
                    jl      short loc_4061E2
    loc_4061ED:                             ; CODE XREF: sub_4061C0+20j
                                            ; sub_4061C0+26j
                    dec     eax
                    cmp     ecx, eax
                    jl      short loc_4061F6
                    xor     eax, eax
                    pop     esi
                    retn
    ; ---------------------------------------------------------------------------
    loc_4061F6:                             ; CODE XREF: sub_4061C0+30j
                    lea     eax, [ecx+esi+1]
                    push    eax             ; Source
                    push    [esp+8+Dest]    ; Dest
                    call    _strcat
                    pop     ecx
                    pop     ecx
                    push    1
                    pop     eax
                    pop     esi
                    retn
    sub_4061C0      endp
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    signed int __cdecl sub_4061C0(char *Str, char *Dest)
    {
      int len; // eax@1
      int i; // ecx@1
      char *str2; // esi@1
      signed int result; // eax@5
      strcpy(Dest, "smtp.");
      str2 = Str;
      len = strlen(Str);
      for ( i = 0; i < len; ++i )
      {
        if ( str2[i] == 64 )
          break;
      }
      if ( i < len - 1 )
      {
        strcat(Dest, &str2[i + 1]);
        result = 1;
      }
      else
      {
        result = 0;
      }
      return result;
    }
    
    

    {% endtab %} {% endtabs %}

    Simple enough?

    Questions like

    • What are the possible return values of the function?
    • Does the function use any strings?
    • What does the function do?

    can be answered almost instantaneously looking at the decompiler output. Needless to say that it looks better because I renamed the local variables. In the disassembler, registers are renamed very rarely because it hides the register use and can lead to confusion.

    {% tabs %} {% tab title=“Assembler code” %}

    ; =============== S U B R O U T I N E =======================================
    ; int __cdecl sub_4061C0(char *Str, char *Dest)
    sub_4061C0      proc near               ; CODE XREF: sub_4062F0+15p
                                            ; sub_4063D4+21p ...
    Str             = dword ptr  4
    Dest            = dword ptr  8
                    push    esi
                    push    offset aSmtp_   ; "smtp."
                    push    [esp+8+Dest]    ; Dest
                    call    _strcpy
                    mov     esi, [esp+0Ch+Str]
                    push    esi             ; Str
                    call    _strlen
                    add     esp, 0Ch
                    xor     ecx, ecx
                    test    eax, eax
                    jle     short loc_4061ED
    loc_4061E2:                             ; CODE XREF: sub_4061C0+2Bj
                    cmp     byte ptr [ecx+esi], 40h
                    jz      short loc_4061ED
                    inc     ecx
                    cmp     ecx, eax
                    jl      short loc_4061E2
    loc_4061ED:                             ; CODE XREF: sub_4061C0+20j
                                            ; sub_4061C0+26j
                    dec     eax
                    cmp     ecx, eax
                    jl      short loc_4061F6
                    xor     eax, eax
                    pop     esi
                    retn
    ; ---------------------------------------------------------------------------
    loc_4061F6:                             ; CODE XREF: sub_4061C0+30j
                    lea     eax, [ecx+esi+1]
                    push    eax             ; Source
                    push    [esp+8+Dest]    ; Dest
                    call    _strcat
                    pop     ecx
                    pop     ecx
                    push    1
                    pop     eax
                    pop     esi
                    retn
    sub_4061C0      endp
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    signed int __cdecl sub_4061C0(char *Str, char *Dest)
    {
      int len; // eax@1
      int i; // ecx@1
      char *str2; // esi@1
      signed int result; // eax@5
      strcpy(Dest, "smtp.");
      str2 = Str;
      len = strlen(Str);
      for ( i = 0; i < len; ++i )
      {
        if ( str2[i] == 64 )
          break;
      }
      if ( i < len - 1 )
      {
        strcat(Dest, &str2[i + 1]);
        result = 1;
      }
      else
      {
        result = 0;
      }
      return result;
    }
    

    {% endtab %} {% endtabs %}

    Where’s my variable?

    IDA highlights the current identifier. This feature turns out to be much more useful with high level output. In this sample, I tried to trace how the retrieved function pointer is used by the function. In the disassembly output, many wrong eax occurrences are highlighted while the decompiler did exactly what I wanted.

    {% tabs %} {% tab title=“Assembler code” %} IDA disassembler output {% endtab %}

    {% tab title=“Pseudocode” %} IDA decompiler output {% endtab %} {% endtabs %}

    {% tabs %} {% tab title=“Assembler code” %}

    ; =============== S U B R O U T I N E =======================================
    ; int __cdecl myfunc(wchar_t *Str, int)
    myfunc          proc near               ; CODE XREF: sub_4060+76p
                                            ; .text:42E4p
    Str             = dword ptr  4
    arg_4           = dword ptr  8
                    mov     eax, dword_1001F608
                    cmp     eax, 0FFFFFFFFh
                    jnz     short loc_10003AB6
                    push    offset aGetsystemwindo ; "GetSystemWindowsDirectoryW"
                    push    offset aKernel32_dll ; "KERNEL32.DLL"
                    call    ds:GetModuleHandleW
                    push    eax             ; hModule
                    call    ds:GetProcAddress
                    mov     dword_1001F608, eax
    loc_10003AB6:                           ; CODE XREF: myfunc+8j
                    test    eax, eax
                    push    esi
                    mov     esi, [esp+4+arg_4]
                    push    edi
                    mov     edi, [esp+8+Str]
                    push    esi
                    push    edi
                    jz      short loc_10003ACA
                    call    eax ; dword_1001F608
                    jmp     short loc_10003AD0
    ; ---------------------------------------------------------------------------
    loc_10003ACA:                           ; CODE XREF: myfunc+34j
                    call    ds:GetWindowsDirectoryW
    loc_10003AD0:                           ; CODE XREF: myfunc+38j
                    sub     esi, eax
                    cmp     esi, 5
                    jnb     short loc_10003ADD
                    pop     edi
                    add     eax, 5
                    pop     esi
                    retn
    ; ---------------------------------------------------------------------------
    loc_10003ADD:                           ; CODE XREF: myfunc+45j
                    push    offset aInf_0   ; "\\inf"
                    push    edi             ; Dest
                    call    _wcscat
                    push    edi             ; Str
                    call    _wcslen
                    add     esp, 0Ch
                    pop     edi
                    pop     esi
                    retn
    myfunc          endp
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    size_t __cdecl myfunc(wchar_t *buf, int bufsize)
    {
      int (__stdcall *func)(_DWORD, _DWORD); // eax@1
      wchar_t *buf2; // edi@3
      int bufsize; // esi@3
      UINT dirlen; // eax@4
      size_t outlen; // eax@7
      HMODULE h; // eax@2
      func = g_fptr;
      if ( g_fptr == (int (__stdcall *)(_DWORD, _DWORD))-1 )
      {
        h = GetModuleHandleW(L"KERNEL32.DLL");
        func = (int (__stdcall *)(_DWORD, _DWORD))
                    GetProcAddress(h, "GetSystemWindowsDirectoryW");
        g_fptr = func;
      }
      bufsize = bufsize;
      buf2 = buf;
      if ( func )
        dirlen = func(buf, bufsize);
      else
        dirlen = GetWindowsDirectoryW(buf, bufsize);
      if ( bufsize - dirlen >= 5 )
      {
        wcscat(buf2, L"\\inf");
        outlen = wcslen(buf2);
      }
      else
      {
        outlen = dirlen + 5;
      }
      return outlen;
    }
    
                            
    

    {% endtab %} {% endtabs %}

    Arithmetics is not a rocket science

    Arithmetics is not a rocket science but it is always better if someone handles it for you. You have more important things to focus on.

    {% tabs %} {% tab title=“Assembler code” %}

    ; =============== S U B R O U T I N E =======================================
    ; Attributes: bp-based frame
    ; sgell(__int64, __int64)
                    public @sgell$qjj
    @sgell$qjj      proc near
    arg_0           = dword ptr  8
    arg_4           = dword ptr  0Ch
    arg_8           = dword ptr  10h
    arg_C           = dword ptr  14h
                    push    ebp
                    mov     ebp, esp
                    mov     eax, [ebp+arg_0]
                    mov     edx, [ebp+arg_4]
                    cmp     edx, [ebp+arg_C]
                    jnz     short loc_10226
                    cmp     eax, [ebp+arg_8]
                    setnb   al
                    jmp     short loc_10229
    ; ---------------------------------------------------------------------------
    loc_10226:                          ; CODE XREF: sgell(__int64,__int64)+Cj
                    setnl   al
    loc_10229:                          ; CODE XREF: sgell(__int64,__int64)+14j
                    and     eax, 1
                    pop     ebp
                    retn
    @sgell$qjj      endp
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    bool __cdecl sgell(__int64 a1, __int64 a2)
    {
      return a1 >= a2;
    }
    

    {% endtab %} {% endtabs %}

    Sample window procedure

    The decompiler recognized a switch statement and nicely represented the window procedure. Without this little help the user would have to calculate the message numbers herself. Nothing particularly difficult, just time consuming and boring. What if she makes a mistake?…

    {% tabs %} {% tab title=“Assembler code” %}

    ; =============== S U B R O U T I N E =======================================
    wndproc         proc near               ; DATA XREF: sub_4010E0+21o
    Paint           = tagPAINTSTRUCT ptr -0A4h
    Buffer          = byte ptr -64h
    hWnd            = dword ptr  4
    Msg             = dword ptr  8
    wParam          = dword ptr  0Ch
    lParam          = dword ptr  10h
                    mov     ecx, hInstance
                    sub     esp, 0A4h
                    lea     eax, [esp+0A4h+Buffer]
                    push    64h             ; nBufferMax
                    push    eax             ; lpBuffer
                    push    6Ah             ; uID
                    push    ecx             ; hInstance
                    call    ds:LoadStringA
                    mov     ecx, [esp+0A4h+Msg]
                    mov     eax, ecx
                    sub     eax, 2
                    jz      loc_4013E8
                    sub     eax, 0Dh
                    jz      loc_4013B2
                    sub     eax, 102h
                    jz      short loc_401336
                    mov     edx, [esp+0A4h+lParam]
                    mov     eax, [esp+0A4h+wParam]
                    push    edx             ; lParam
                    push    eax             ; wParam
                    push    ecx             ; Msg
                    mov     ecx, [esp+0B0h+hWnd]
                    push    ecx             ; hWnd
                    call    ds:DefWindowProcA
                    add     esp, 0A4h
                    retn    10h
    ; ---------------------------------------------------------------------------
    loc_401336:                             ; CODE XREF: wndproc+3Cj
                    mov     ecx, [esp+0A4h+wParam]
                    mov     eax, ecx
                    and     eax, 0FFFFh
                    sub     eax, 68h
                    jz      short loc_40138A
                    dec     eax
                    jz      short loc_401371
                    mov     edx, [esp+0A4h+lParam]
                    mov     eax, [esp+0A4h+hWnd]
                    push    edx             ; lParam
                    push    ecx             ; wParam
                    push    111h            ; Msg
                    push    eax             ; hWnd
                    call    ds:DefWindowProcA
                    add     esp, 0A4h
                    retn    10h
    ; ---------------------------------------------------------------------------
    loc_401371:                             ; CODE XREF: wndproc+7Aj
                    mov     ecx, [esp+0A4h+hWnd]
                    push    ecx             ; hWnd
                    call    ds:DestroyWindow
                    xor     eax, eax
                    add     esp, 0A4h
                    retn    10h
    ; ---------------------------------------------------------------------------
    loc_40138A:                             ; CODE XREF: wndproc+77j
                    mov     edx, [esp+0A4h+hWnd]
                    mov     eax, hInstance
                    push    0               ; dwInitParam
                    push    offset DialogFunc ; lpDialogFunc
                    push    edx             ; hWndParent
                    push    67h             ; lpTemplateName
                    push    eax             ; hInstance
                    call    ds:DialogBoxParamA
                    xor     eax, eax
                    add     esp, 0A4h
                    retn    10h
    ; ---------------------------------------------------------------------------
    loc_4013B2:                             ; CODE XREF: wndproc+31j
                    push    esi
                    mov     esi, [esp+0A8h+hWnd]
                    lea     ecx, [esp+0A8h+Paint]
                    push    ecx             ; lpPaint
                    push    esi             ; hWnd
                    call    ds:BeginPaint
                    push    eax             ; HDC
                    push    esi             ; hWnd
                    call    my_paint
                    add     esp, 8
                    lea     edx, [esp+0A8h+Paint]
                    push    edx             ; lpPaint
                    push    esi             ; hWnd
                    call    ds:EndPaint
                    pop     esi
                    xor     eax, eax
                    add     esp, 0A4h
                    retn    10h
    ; ---------------------------------------------------------------------------
    loc_4013E8:                             ; CODE XREF: wndproc+28j
                    push    0               ; nExitCode
                    call    ds:PostQuitMessage
                    xor     eax, eax
                    add     esp, 0A4h
                    retn    10h
    wndproc         endp
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    
    LRESULT __stdcall wndproc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
      LRESULT result; // eax@4
      HWND h; // esi@10
      HDC dc; // eax@10
      CHAR Buffer; // [sp+40h] [bp-64h]@1
      struct tagPAINTSTRUCT Paint; // [sp+0h] [bp-A4h]@10
      LoadStringA(hInstance, 0x6Au, &Buffer, 100);
      switch ( Msg )
      {
        case 2u:
          PostQuitMessage(0);
          result = 0;
          break;
        case 15u:
          h = hWnd;
          dc = BeginPaint(hWnd, &Paint);
          my_paint(h, dc);
          EndPaint(h, &Paint);
          result = 0;
          break;
        case 273u:
          if ( (_WORD)wParam == 104 )
          {
            DialogBoxParamA(hInstance, (LPCSTR)0x67, hWnd, DialogFunc, 0);
            result = 0;
          }
          else
          {
            if ( (_WORD)wParam == 105 )
            {
              DestroyWindow(hWnd);
              result = 0;
            }
            else
            {
              result = DefWindowProcA(hWnd, 0x111u, wParam, lParam);
            }
          }
          break;
        default:
          result = DefWindowProcA(hWnd, Msg, wParam, lParam);
          break;
      }
      return result;
    }
    

    {% endtab %} {% endtabs %}

    Short-circuit evaluation

    This is an excerpt from a big function to illustrate short-circuit evaluation. Complex things happen in long functions and it is very handy to have the decompiler to represent things in a human way. Please note how the code that was scattered over the address space is concisely displayed in two if statements.

    {% tabs %} {% tab title=“Assembler code” %}

    loc_804BCC7:                            ; CODE XREF: sub_804BB10+A42j
                    mov     [esp+28h+var_24], offset aUnzip ; "unzip"
                    xor     eax, eax
                    test    esi, esi
                    setnz   al
                    mov     edx, 1
                    mov     ds:dword_804FBAC, edx
                    lea     eax, [eax+eax+1]
                    mov     ds:dword_804F780, eax
                    mov     eax, ds:dword_804FFD4
                    mov     [esp+28h+var_28], eax
                    call    _strstr
                    test    eax, eax
                    jz      loc_804C4F1
    loc_804BCFF:                            ; CODE XREF: sub_804BB10+9F8j
                    mov     eax, 2
                    mov     ds:dword_804FBAC, eax
    loc_804BD09:                            ; CODE XREF: sub_804BB10+9FEj
                    mov     [esp+28h+var_24], offset aZ2cat ; "z2cat"
                    mov     eax, ds:dword_804FFD4
                    mov     [esp+28h+var_28], eax
                    call    _strstr
                    test    eax, eax
                    jz      loc_804C495
    loc_804BD26:                            ; CODE XREF: sub_804BB10+99Cj
                                            ; sub_804BB10+9B9j ...
                    mov     eax, 2
                    mov     ds:dword_804FBAC, eax
                    xor     eax, eax
                    test    esi, esi
                    setnz   al
                    inc     eax
                    mov     ds:dword_804F780, eax
      .............................. SKIP ............................
    loc_804C495:                            ; CODE XREF: sub_804BB10+210j
                    mov     [esp+28h+var_24], offset aZ2cat_0 ; "Z2CAT"
                    mov     eax, ds:dword_804FFD4
                    mov     [esp+28h+var_28], eax
                    call    _strstr
                    test    eax, eax
                    jnz     loc_804BD26
                    mov     [esp+28h+var_24], offset aZcat ; "zcat"
                    mov     eax, ds:dword_804FFD4
                    mov     [esp+28h+var_28], eax
                    call    _strstr
                    test    eax, eax
                    jnz     loc_804BD26
                    mov     [esp+28h+var_24], offset aZcat_0 ; "ZCAT"
                    mov     eax, ds:dword_804FFD4
                    mov     [esp+28h+var_28], eax
                    call    _strstr
                    test    eax, eax
                    jnz     loc_804BD26
                    jmp     loc_804BD3D
    ; ---------------------------------------------------------------------------
    loc_804C4F1:                            ; CODE XREF: sub_804BB10+1E9j
                    mov     [esp+28h+var_24], offset aUnzip_0 ; "UNZIP"
                    mov     eax, ds:dword_804FFD4
                    mov     [esp+28h+var_28], eax
                    call    _strstr
                    test    eax, eax
                    jnz     loc_804BCFF
                    jmp     loc_804BD09
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    dword_804F780 = 2 * (v9 != 0) + 1;
      if ( strstr(dword_804FFD4, "unzip") || strstr(dword_804FFD4, "UNZIP") )
        dword_804FBAC = 2;
      if ( strstr(dword_804FFD4, "z2cat")
        || strstr(dword_804FFD4, "Z2CAT")
        || strstr(dword_804FFD4, "zcat")
        || strstr(dword_804FFD4, "ZCAT") )
      {
        dword_804FBAC = 2;
        dword_804F780 = (v9 != 0) + 1;
      }
    

    {% endtab %} {% endtabs %}

    Inlined string operations

    The decompiler tries to recognize frequently inlined string functions such as strcmp, strchr, strlen, etc. In this code snippet, calls to the strlen function has been recognized.

    {% tabs %} {% tab title=“Assembler code” %}

     mov     eax, [esp+argc]
                    sub     esp, 8
                    push    ebx
                    push    ebp
                    push    esi
                    lea     ecx, ds:0Ch[eax*4]
                    push    edi
                    push    ecx             ; unsigned int
                    call    ??2@YAPAXI@Z    ; operator new(uint)
                    mov     edx, [esp+1Ch+argv]
                    mov     ebp, eax
                    or      ecx, 0FFFFFFFFh
                    xor     eax, eax
                    mov     esi, [edx]
                    add     esp, 4
                    mov     edi, esi
                    repne scasb
                    not     ecx
                    dec     ecx
                    cmp     ecx, 4
                    jl      short loc_401064
                    cmp     byte ptr [ecx+esi-4], '.'
                    jnz     short loc_401064
                    mov     al, [ecx+esi-3]
                    cmp     al, 'e'
                    jz      short loc_401047
                    cmp     al, 'E'
                    jnz     short loc_401064
    loc_401047:                             ; CODE XREF: _main+41j
                    mov     al, [ecx+esi-2]
                    cmp     al, 'x'
                    jz      short loc_401053
                    cmp     al, 'X'
                    jnz     short loc_401064
    loc_401053:                             ; CODE XREF: _main+4Dj
                    mov     al, [ecx+esi-1]
                    cmp     al, 'e'
                    jz      short loc_40105F
                    cmp     al, 'E'
                    jnz     short loc_401064
    loc_40105F:                             ; CODE XREF: _main+59j
                    mov     byte ptr [ecx+esi-4], 0
    loc_401064:                             ; CODE XREF: _main+32j _main+39j ... 
                    mov     edi, esi
                    or      ecx, 0FFFFFFFFh
                    xor     eax, eax
                    repne scasb
                    not     ecx
                    add     ecx, 3
                    push    ecx             ; unsigned int
                    call    ??2@YAPAXI@Z    ; operator new(uint)
                    mov     edx, eax
    

    {% endtab %} {% endtabs %}

    Comparisons of ARM disassembly and decompilation

    Here are some side-by-side comparisons of disassembly and decompiler for ARM. Please maximize the window too see both columns simultaneously.

    The following examples are displayed on this page:

    1. Simple case
    2. 64-bit arithmetics
    3. Conditional instructions
    4. Conditional instructions - 2
    5. Complex instructions
    6. Compiler helper functions
    7. Immediate constants
    8. Position independent code

    Simple case

    Let’s start with a very simple function. It accepts a pointer to a structure and zeroes out its first three fields. While the function logic is obvious by just looking at the decompiler output, the assembly listing has too much noise and requires studying it.

    The decompiler saves your time and allows you to concentrate on more exciting aspects of reverse engineering.

    {% tabs %} {% tab title=“Assembler code” %}

    ; struct_result *__fastcall sub_210DC(struct_result *result)                 
                                             
     var_10          = -0x10                                                      
     var_4           = -4                                                         
                                                                                  
                     MOV     R12, SP                                              
                     STMFD   SP!, {R0}                                            
                     STMFD   SP!, {R12,LR}                                        
                     SUB     SP, SP, #4                                           
                     LDR     R2, [SP,#0x10+var_4]
                     MOV     R3, #0
                     STR     R3, [R2]
                     LDR     R3, [SP,#0x10+var_4]
                     ADD     R2, R3, #4
                     MOV     R3, #0
                     STR     R3, [R2]
                     LDR     R3, [SP,#0x10+var_4]
                     ADD     R2, R3, #8
                     MOV     R3, #0
                     STR     R3, [R2]
                     LDR     R3, [SP,#0x10+var_4]
                     STR     R3, [SP,#0x10+var_10]
                     LDR     R0, [SP,#0x10+var_10]
                     ADD     SP, SP, #4
                     LDMFD   SP, {SP,LR}
                     BX      LR
     ; End of function sub_210DC
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    struct_result *__fastcall sub_210DC(struct_result *result)
    {
      result->dword0 = 0;
      result->dword4 = 0;
      result->dword8 = 0;
      return result;
    }
    

    {% endtab %} {% endtabs %}

    64-bit arithmetics

    Sorry for a long code snippet, ARM code tends to be longer compared to x86 code. This makes our comparison even more impressive: look at how concise is the decompiler output!

    {% tabs %} {% tab title=“Assembler code” %}

     ; bool __cdecl uh_gt_uc()                                                    
                     EXPORT _uh_gt_uc__YA_NXZ                                     
     _uh_gt_uc__YA_NXZ                       ; DATA XREF: .pdata:$T7452o          
                                                                                  
     var_2C          = -0x2C                                                      
     var_28          = -0x28                                                      
     var_24          = -0x24                                                      
     var_20          = -0x20                                                      
     var_1C          = -0x1C                                                      
     var_18          = -0x18                                                      
     var_14          = -0x14                                                      
     var_10          = -0x10                                                      
     var_C           = -0xC                                                       
     var_8           = -8                                                         
     var_4           = -4                                                         
                                                                                  
                     STR     LR, [SP,#var_4]! ; $M7441                            
                                             ; $LN8@uh_gt_uc                      
                     SUB     SP, SP, #0x28                                        
    
     $M7449
                     BL      uh
                     STR     R1, [SP,#0x2C+var_24]
                     STR     R0, [SP,#0x2C+var_28]
                     BL      uc
                     STRB    R0, [SP,#0x2C+var_20]
                     LDRB    R3, [SP,#0x2C+var_20]
                     STR     R3, [SP,#0x2C+var_1C]
                     LDR     R1, [SP,#0x2C+var_1C]
                     LDR     R3, [SP,#0x2C+var_1C]
                     MOV     R2, R3,ASR#31
                     LDR     R3, [SP,#0x2C+var_28]
                     STR     R3, [SP,#0x2C+var_18]
                     LDR     R3, [SP,#0x2C+var_24]
                     STR     R3, [SP,#0x2C+var_14]
                     LDR     R3, [SP,#0x2C+var_18]
                     STR     R3, [SP,#0x2C+var_10]
                     STR     R1, [SP,#0x2C+var_C]
                     LDR     R3, [SP,#0x2C+var_14]
                     CMP     R3, R2
                     BCC     $LN3_8
    
     loc_6AC
                     BHI     $LN5_0
    
     loc_6B0
                     LDR     R2, [SP,#0x2C+var_10]
                     LDR     R3, [SP,#0x2C+var_C]
                     CMP     R2, R3
                     BLS     $LN3_8
    
     $LN5_0
                     MOV     R3, #1
                     STR     R3, [SP,#0x2C+var_8]
                     B       $LN4_8
     ; ---------------------------------------------------------------------------
    
     $LN3_8
                                             ; uh_gt_uc(void)+68j
                     MOV     R3, #0
                     STR     R3, [SP,#0x2C+var_8]
    
     $LN4_8
                     LDR     R3, [SP,#0x2C+var_8]
                     AND     R3, R3, #0xFF
                     STRB    R3, [SP,#0x2C+var_2C]
                     LDRB    R0, [SP,#0x2C+var_2C]
                     ADD     SP, SP, #0x28
                     LDR     PC, [SP+4+var_4],#4
     ; End of function uh_gt_uc(void)
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    bool __fastcall uh_gt_uc()
    {
      unsigned __int64 v0; // ST04_8@1
    
      v0 = uh();
      return v0 > uc();
    }
    

    {% endtab %} {% endtabs %}

    Conditional instructions

    The ARM processor has conditional instructions that can shorten the code but require high attention from the reader. The case above is very simple, just note that there is a pair of instructions: MOVNE and LDREQSH. Only one of them will be executed at once. This is how simple if-then-else looks in ARM.

    The pseudocode shows it much better and does not require any explanations.

    A quiz question: did you notice that MOVNE loads zero to R0? (because I didn’t:)

    Also note that in the disassembly listing we see var_8 but the location really used is var_A, which corresponds to v4.

    {% tabs %} {% tab title=“Assembler code” %}

    ; int __cdecl ReadShort(void *, unsigned __int32 offset, int whence)         
     ReadShort                                                                    
                                                                                  
     whence          = -0x18                                                      
     var_A           = -0xA                                                       
     var_8           = -8                                                         
                                                                                  
                     STMFD   SP!, {R4,LR}                                         
                     SUB     SP, SP, #0x10   ; whence                             
                     MOV     R4, #0
                     ADD     R3, SP, #0x18+var_8
                     STRH    R4, [R3,#-2]!
                     STR     R2, [SP,#0x18+whence] ; whence
                     MOV     R2, R3          ; buffer
                     MOV     R3, #2          ; len
                     BL      ReadData
                     CMP     R0, R4
                     MOVNE   R0, R4
                     LDREQSH R0, [SP,#0x18+var_A]
                     ADD     SP, SP, #0x10
                     LDMFD   SP!, {R4,PC}
     ; End of function ReadShort
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __cdecl ReadShort(void *a1, unsigned __int32 offset, int whence)
    {
      int result; // r0@2
      __int16 v4; // [sp+Eh] [bp-Ah]@1
    
      v4 = 0;
      if ( ReadData(a1, offset, &v4, 2u, whence) )
        result = 0;
      else
        result = v4;
      return result;
    }
    
    

    {% endtab %} {% endtabs %}

    Conditional instructions - 2

    Look, the decompiler output is longer! This is a rare case when the pseudocode is longer than the disassembly listing, but it is a for a good cause: to keep it readable. There are so many conditional instructions here, it is very easy to misunderstand the dependencies. For example, did you notice that the first MOVEQ may use the condition codes set by CMP? The subtle detail is that CMPNE may be skipped and the condition codes set by CMP may reach MOVEQs.

    The decompiler represented it perfectly well. I renamed some variables and set their types, but this was an easy task.

    {% tabs %} {% tab title=“Assembler code” %}

    ; signed int __fastcall get_next_byte(entry_t *entry)
     get_next_byte                           ; DATA XREF: sub_3BC+30o
                                             ;
                     LDR     R2, [R0,#4]
                     CMP     R2, #0
                     LDRNE   R3, [R0]
                     LDRNEB  R1, [R3],#1
                     CMPNE   R1, #0
                     MOVEQ   R1, #1
                     STREQ   R1, [R0,#0xC]
                     MOVEQ   R0, 0xFFFFFFFF
                     MOVEQ   PC, LR
                     SUB     R2, R2, #1
                     STR     R2, [R0,#4]
                     STR     R3, [R0]
                     MOV     R0, R1
                     RET
     ; End of function get_next_byte
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    signed int __fastcall get_next_byte(entry_t *entry)
    {
      signed int chr; // r1@0
      unsigned __int8 *ptr; // r3@0
      int count; // r2@1
      char done; // zf@1
      signed int result; // r0@4
    
      count = entry->count;
      done = count == 0;
      if ( count )
      {
        ptr = entry->ptr + 1;
        chr = *entry->ptr;
        done = chr == 0;
      }
      if ( done )
      {
        entry->done = 1;
        result = -1;
      }
      else
      {
        entry->count = count - 1;
        entry->ptr = ptr;
        result = chr;
      }
      return result;
    }
    

    {% endtab %} {% endtabs %}

    Complex instructions

    Conditional instructions are just part of the story. ARM is also famous for having a plethora of data movement instructions. They come with a set of possible suffixes that subtly change the meaning of the instruction. Take STMCSIA, for example. It is a STM instruction, but then you have to remember that CS means “carry set” and IA means “increment after”.

    In short, the disassembly listing is like Chinese. The pseudocode is longer but requires much less time to understand.

    {% tabs %} {% tab title=“Assembler code” %}

    ; void __fastcall sub_2A38(list_t *ptr, unsigned int a2)
     sub_2A38                                ; CODE XREF: sub_5C8+48p
                                             ; sub_648+5Cp ...
                     MOV     R2, #0
                     STMFD   SP!, {LR}                                            
                     MOV     R3, R2
                     MOV     R12, R2
                     MOV     LR, R2
                     SUBS    R1, R1, #0x20
    
     loc_2A50                                ; CODE XREF: sub_2A38+24j
                     STMCSIA R0!, {R2,R3,R12,LR}
                     STMCSIA R0!, {R2,R3,R12,LR}
                     SUBCSS  R1, R1, #0x20
                     BCS     loc_2A50
                     MOVS    R1, R1,LSL#28
                     STMCSIA R0!, {R2,R3,R12,LR}
                     STMMIIA R0!, {R2,R3}
                     LDMFD   SP!, {LR}
                     MOVS    R1, R1,LSL#2
                     STRCS   R2, [R0],#4
                     MOVEQ   PC, LR
                     STRMIH  R2, [R0],#2
                     TST     R1, #0x40000000
                     STRNEB  R2, [R0],#1
                     RET
     ; End of function sub_2A38
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    void __fastcall sub_2A38(list_t *ptr, unsigned int a2)
    {
      char copybig; // cf@1
      unsigned int size; // r1@1
      list_t *v4; // r0@3
      int remains; // r1@4
      int final; // r1@8
    
      copybig = a2 >= 0x20;
      size = a2 - 32;
      do
      {
        if ( !copybig )
          break;
        ptr->dword0 = 0;
        ptr->dword4 = 0;
        ptr->dword8 = 0;
        ptr->dwordC = 0;
        v4 = ptr + 1;
        v4->dword0 = 0;
        v4->dword4 = 0;
        v4->dword8 = 0;
        v4->dwordC = 0;
        ptr = v4 + 1;
        copybig = size >= 0x20;
        size -= 32;
      }
      while ( copybig );
      remains = size << 28;
      if ( copybig )
      {
        ptr->dword0 = 0;
        ptr->dword4 = 0;
        ptr->dword8 = 0;
        ptr->dwordC = 0;
        ++ptr;
      }
      if ( remains < 0 )
      {
        ptr->dword0 = 0;
        ptr->dword4 = 0;
        ptr = (list_t *)((char *)ptr + 8);
      }
      final = 4 * remains;
      if ( copybig )
      {
        ptr->dword0 = 0;
        ptr = (list_t *)((char *)ptr + 4);
      }
      if ( final )
      {
        if ( final < 0 )
        {
          LOWORD(ptr->dword0) = 0;
          ptr = (list_t *)((char *)ptr + 2);
        }
        if ( final & 0x40000000 )
          LOBYTE(ptr->dword0) = 0;
      }
    }
    
    

    {% endtab %} {% endtabs %}

    Compiler helper functions

    Sorry for another long code snippet. Just wanted to show you that the decompiler can handle compiler helper functions (like __divdi3) and handles 64-bit arithmetic quite well.

    {% tabs %} {% tab title=“Assembler code” %}

    EXPORT op_two64                                              
         op_two64                                ; CODE XREF: refer_all+31Cp          
                                                 ; main+78p                           
                                                                                      
         anonymous_1     = -0x28                                                      
         var_20          = -0x20                                                      
         anonymous_0     = -0x18                                                      
         var_10          = -0x10                                                      
         arg_0           =  4                                                         
                                                                                      
     000                 MOV     R12, SP                                              
     000                 STMFD   SP!, {R4,R11,R12,LR,PC}                              
     014                 SUB     R11, R12, #4                                         
     014                 SUB     SP, SP, #0x18                                        
     02C                 SUB     R4, R11, #-var_10
     02C                 STMDB   R4, {R0,R1}
     02C                 MOV     R1, 0xFFFFFFF0
     02C                 SUB     R12, R11, #-var_10
     02C                 ADD     R1, R12, R1
     02C                 STMIA   R1, {R2,R3}
     02C                 LDR     R3, [R11,#arg_0]
     02C                 CMP     R3, #1
     02C                 BNE     loc_9C44
     02C                 MOV     R3, 0xFFFFFFF0
     02C                 SUB     R0, R11, #-var_10
     02C                 ADD     R3, R0, R3
     02C                 SUB     R4, R11, #-var_10
     02C                 LDMDB   R4, {R1,R2}
     02C                 LDMIA   R3, {R3,R4}
     02C                 ADDS    R3, R3, R1
     02C                 ADC     R4, R4, R2
     02C                 SUB     R12, R11, #-var_20
     02C                 STMDB   R12, {R3,R4}
     02C                 B       loc_9D04
         ; ---------------------------------------------------------------------------
    
         loc_9C44                                ; CODE XREF: op_two64+30j
     02C                 LDR     R3, [R11,#arg_0]
     02C                 CMP     R3, #2
     02C                 BNE     loc_9C7C
     02C                 MOV     R3, 0xFFFFFFF0
     02C                 SUB     R0, R11, #-var_10
     02C                 ADD     R3, R0, R3
     02C                 SUB     R4, R11, #-var_10
     02C                 LDMDB   R4, {R1,R2}
     02C                 LDMIA   R3, {R3,R4}
     02C                 SUBS    R3, R1, R3
     02C                 SBC     R4, R2, R4
     02C                 SUB     R12, R11, #-var_20
     02C                 STMDB   R12, {R3,R4}
     02C                 B       loc_9D04
         ; ---------------------------------------------------------------------------
    
         loc_9C7C                                ; CODE XREF: op_two64+68j
     02C                 LDR     R3, [R11,#arg_0]
     02C                 CMP     R3, #3
     02C                 BNE     loc_9CB8
     02C                 MOV     R3, 0xFFFFFFF0
     02C                 SUB     R0, R11, #-var_10
     02C                 ADD     R3, R0, R3
     02C                 SUB     R2, R11, #-var_10
     02C                 LDMDB   R2, {R0,R1}
     02C                 LDMIA   R3, {R2,R3}
     02C                 BL      __muldi3
     02C                 MOV     R4, R1
     02C                 MOV     R3, R0
     02C                 SUB     R12, R11, #-var_20
     02C                 STMDB   R12, {R3,R4}
     02C                 B       loc_9D04
         ; ---------------------------------------------------------------------------
    
         loc_9CB8                                ; CODE XREF: op_two64+A0j
     02C                 LDR     R3, [R11,#arg_0]
     02C                 CMP     R3, #4
     02C                 BNE     loc_9CF4
     02C                 MOV     R3, 0xFFFFFFF0
     02C                 SUB     R0, R11, #-var_10
     02C                 ADD     R3, R0, R3
     02C                 SUB     R2, R11, #-var_10
     02C                 LDMDB   R2, {R0,R1}
     02C                 LDMIA   R3, {R2,R3}
     02C                 BL      __divdi3
     02C                 MOV     R4, R1
     02C                 MOV     R3, R0
     02C                 SUB     R12, R11, #-var_20
     02C                 STMDB   R12, {R3,R4}
     02C                 B       loc_9D04
         ; ---------------------------------------------------------------------------
    
         loc_9CF4                                ; CODE XREF: op_two64+DCj
     02C                 MOV     R3, 0xFFFFFFFF
     02C                 MOV     R2, 0xFFFFFFFF
     02C                 SUB     R4, R11, #-var_20
     02C                 STMDB   R4, {R2,R3}
    
         loc_9D04                                ; CODE XREF: op_two64+5Cj
                                                 ; op_two64+94j ...
     02C                 SUB     R12, R11, #-var_20
     02C                 LDMDB   R12, {R0,R1}
     02C                 SUB     SP, R11, #0x10
     014                 LDMFD   SP, {R4,R11,SP,PC}
         ; End of function op_two64
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    signed __int64 __fastcall op_two64(signed __int64 a1, signed __int64 a2, int a3)
    {
      signed __int64 v4; // [sp+0h] [bp-28h]@2
    
      switch ( a3 )
      {
        case 1:
          v4 = a2 + a1;
          break;
        case 2:
          v4 = a1 - a2;
          break;
        case 3:
          v4 = a1 * a2;
          break;
        case 4:
          v4 = a1 / a2;
          break;
        default:
          v4 = -1LL;
          break;
      }
      return v4;
    }
    

    {% endtab %} {% endtabs %}

    Immediate constants

    Since ARM instructions cannot have big immediate constants, sometimes they are loaded with two instructions. There are many 0xFA (250 decimal) constants in the disassembly listing, but all of them are shifted to the left by 2 before use. The decompiler saves you from these petty details.

    Also a side: the decompiler can handle ARM mode as well as Thumb mode instructions. It just does not care about the instruction encoding because it is already handled by IDA.

    {% tabs %} {% tab title=“Assembly code” %}

    loc_110D6                               ; CODE XREF: sub_10E38+43Cj
                                             ; sub_10E38+442j ...
                     LDR     R1, =(tmin_ptr - 0x1CDB8)
                     LDR     R2, =(tmax_ptr - 0x1CDB8)
                     LDR     R0, =(aRttMinAvgMaxMd - 0x1CDB8)
                     LDR     R6, [R7,R1]
                     LDR     R5, [R7,R2]
                     MOVS    R3, #0xFA
                     LDR     R4, [R6]
                     LSLS    R1, R3, #2
                     LDR     R6, [R5]
                     ADDS    R5, R7, R0      ; "rtt min/avg/max/mdev = %ld.%03ld/%lu.%0"...
                     MOVS    R0, R4
                     BLX     __aeabi_idiv
                     MOV     R8, R0
                     MOVS    R0, R4
                     MOVS    R4, #0xFA
                     LSLS    R1, R4, #2
                     BLX     __aeabi_idivmod
                     LDR     R3, =0
                     LDR     R2, =0x3E8
                     MOVS    R4, R1
                     LDR     R0, [SP,#0x78+var_40]
                     LDR     R1, [SP,#0x78+var_40+4]
                     BLX     __aeabi_ldivmod
                     LDR     R3, =0
                     LDR     R2, =0x3E8
                     STR     R0, [SP,#0x78+var_50]
                     STR     R1, [SP,#0x78+var_4C]
                     LDR     R0, [SP,#0x78+var_40]
                     LDR     R1, [SP,#0x78+var_40+4]
                     BLX     __aeabi_ldivmod
                     MOVS    R1, #0xFA
                     MOVS    R0, R6
                     LSLS    R1, R1, #2
                     STR     R2, [SP,#0x78+var_78]
                     BLX     __aeabi_idiv
                     STR     R0, [SP,#0x78+var_74]
                     MOVS    R0, R6
                     MOVS    R6, #0xFA
                     LSLS    R1, R6, #2
                     BLX     __aeabi_idivmod
                     MOVS    R2, #0xFA
                     STR     R1, [SP,#0x78+var_70]
                     LDR     R0, [SP,#0x78+var_38]
                     LSLS    R1, R2, #2
                     BLX     __aeabi_idiv
                     MOVS    R3, #0xFA
                     STR     R0, [SP,#0x78+var_6C]
                     LSLS    R1, R3, #2
                     LDR     R0, [SP,#0x78+var_38]
                     BLX     __aeabi_idivmod
                     MOVS    R0, R5          ; format
                     STR     R1, [SP,#0x78+var_68]
                     MOVS    R2, R4
                     MOV     R1, R8
                     LDR     R3, [SP,#0x78+var_50]
                     BLX     printf
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

     printf(
          "rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
          tmin / 1000,
          tmin % 1000,
          v27 / 1000,
          v27 % 1000,
          tmax / 1000,
          tmax % 1000,
          v28 / 1000,
          v28 % 1000);
    
    

    {% endtab %} {% endtabs %}

    Position independent code

    In some case the disassembly listing can be misleading, especially with PIC (position independent code). While the address of a constant string is loaded into R12, the code does not care about it. It is just how variable addresses are calculated in PIC-code (it is .got-someoffset). Such calculations are very frequent in shared objects and unfortunately IDA cannot handle all of them. But the decompiler did a great job of tracing R12.

    {% tabs %} {% tab title=“Assembly code” %}

    sub_65768                               ; DATA XREF: .data:007E37A4o         
                                                                                  
     var_18          = -0x18                                                      
     var_14          = -0x14                                                      
     var_10          = -0x10                                                      
     arg_0           =  0                                                         
                                                                                  
                     PUSH    {LR}                                                 
                     LDR.W   R12, =aResponsetype ; "responseType"
                     SUB     SP, SP, #0x14                                        
                     ADR.W   LR, loc_65774
    
     loc_65774                               ; DATA XREF: sub_65768+8o
                     ADD     R12, LR
                     LDR.W   LR, [SP,#0x18+arg_0]
                     STR.W   LR, [SP,#0x18+var_18]
                     MOV.W   LR, #0x10
                     STR.W   LR, [SP,#0x18+var_14]
                     LDR.W   LR, =0xFFF0883C
                     ADD     R12, LR
                     STR.W   R12, [SP,#0x18+var_10]
                     BL      sub_65378
                     ADD     SP, SP, #0x14
                     POP     {PC}
     ; End of function sub_65768
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall sub_65768(int a1, int a2, int a3, int a4, int a5)
    {
      return sub_65378(a1, a2, a3, a4, a5, 16, (int)myarray);
    }
    

    {% endtab %} {% endtabs %}

    Comparisons of PowerPC disassembly and decompilation

    Here are some side-by-side comparisons of disassembly and decompiler for PowerPC. Please maximize the window too see both columns simultaneously.

    The following examples are displayed on this page:

    1. Simple code
    2. Linear execution
    3. 64-bit comparison
    4. System calls
    5. Compiler helpers
    6. Floating point arithmetic
    7. Magic multiplication/division operations
    8. VLE code
    9. Interactive decompiler

    Simple code

    This simple function calculates the sum of the squares of the first N natural numbers. While the function logic is obvious by just looking at the decompiler output, the assembly listing has too much noise and requires studying it. The decompiler saves your time and allows you to concentrate on more exciting aspects of reverse engineering.

    {% tabs %} {% tab title=“Assembler code” %}

    f:
     .set back_chain, -0x20
     .set var_4, -4
                    stw       r31, var_4(r1)
                    stwu      r1, back_chain(r1)
                    mr        r31, r1
                    stw       r3, 0x14(r31)
                    mr        r4, r3
                    cmpwi     r3, 0
                    stw       r4, 8(r31)
                    bgt       loc_30
                    b         loc_24
     loc_24:
                    li        r3, 0
                    stw       r3, 0x18(r31)
                    b         loc_88
     loc_30:
                    li        r3, 0
                    stw       r3, 0x10(r31)
                    stw       r3, 0xC(r31)
                    b         loc_40
     loc_40:
                    lwz       r3, 0x14(r31)
                    lwz       r4, 0xC(r31)
                    cmpw      r4, r3
                    bge       loc_7C
                    b         loc_54
     loc_54:
                    lwz       r3, 0xC(r31)
                    mullw     r3, r3, r3
                    lwz       r4, 0x10(r31)
                    add       r3, r4, r3
                    stw       r3, 0x10(r31)
                    b         loc_6C
     loc_6C:
                    lwz       r3, 0xC(r31)
                    addi      r3, r3, 1
                    stw       r3, 0xC(r31)
                    b         loc_40
     loc_7C:
                    lwz       r3, 0x10(r31)
                    stw       r3, 0x18(r31)
                    b         loc_88
     loc_88:
                    lwz       r3, 0x18(r31)
                    addi      r1, r1, 0x20
                    lwz       r31, var_4(r1)
                    blr
     # End of       function f
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall f(int a1)
    {
      int i; // [sp+Ch] [-14h]@3
      int v3; // [sp+10h] [-10h]@3
    
      if ( a1 )
          return 0;
      v3 = 0;
      for ( i = 0; i < a1; ++i )
        v3 += i * i;
      return v3;
    }
    

    {% endtab %} {% endtabs %}

    Linear execution

    The PowerPC processor has a number of instructions which can be used to avoid branches (for example cntlzw). The decompiler restores the conditional logic and makes code easier to understand.

    {% tabs %} {% tab title=“Assembler code” %}

    # _DWORD c_eq_s(void)
    .globl _Z6c_eq_sv
    _Z6c_eq_sv:
    
    .set back_chain, -0x10
    .set var_8, -8
    .set var_4, -4
    .set sender_lr, 4
    
                    stwu      r1, back_chain(r1)
                    mflr      r0
                    stw       r0, 0x10+sender_lr(r1)
                    stw       r30, 0x10+var_8(r1)
                    stw       r31, 0x10+var_4(r1)
                    mr        r31, r1
                    bl        c
                    mr        r9, r3
                    extsh     r30, r9
                    bl        s
                    mr        r9, r3
                    xor       r9, r30, r9
                    cntlzw    r9, r9
                    srwi      r9, r9, 5
                    clrlwi    r9, r9, 24
                    mr        r3, r9
                    addi      r11, r31, 0x10
                    lwz       r0, 4(r11)
                    mtlr      r0
                    lwz       r30, -8(r11)
                    lwz       r31, -4(r11)
                    mr        r1, r11
                    blr
    # End of        function c_eq_s(void)
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    bool c_eq_s(void)
    {
      int v0; // r30@1
    
      v0 = c();
      return v0 == s();
    }
    

    {% endtab %} {% endtabs %}

    64-bit comparison

    64-bit comparison usually involves several compare and branch instructions which do not improve the code readability.

    {% tabs %} {% tab title=“Assembler code” %}

    .globl i_ge_uh
    i_ge_uh:
    
    .set back_chain, -0x10
    .set var_4, -4
    
                    stwu      r1, back_chain(r1)
                    stw       r31, 0x10+var_4(r1)
                    mr        r31, r1
                    lis       r9, i@ha
                    lwz       r9, i@l(r9)
                    mr        r8, r9
                    srawi     r9, r9, 0x1F
                    mr        r7, r9
                    lis       r9, uh@ha
                    addi      r9, r9, uh@l
                    lwz       r10, (uh+4 - uh)(r9)
                    lwz       r9, 0(r9)
                    cmplw     cr7, r9, r7
                    bgt       cr7, loc_7028
                    cmplw     cr7, r9, r7
                    bne       cr7, loc_7020
                    cmplw     cr7, r10, r8
                    bgt       cr7, loc_7028
    loc_7020:
                    li        r9, 1
                    b         loc_702C
    loc_7028:
                    li        r9, 2
    loc_702C:
                    mr        r3, r9
                    addi      r11, r31, 0x10
                    lwz       r31, -4(r11)
                    mr        r1, r11
                    blr
    # End of      function i_ge_uh
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    signed int i_ge_uh()
    {
      signed int v0; // r9@2 7029 TYPED
    
      if ( uh unsigned __int64)i )
          v0 = 1;
      else
          v0 = 2;
      return v0;
    }
      
    

    {% endtab %} {% endtabs %}

    System calls

    System call is always mysterious, but decompiler helps you with its name and arguments.

    {% tabs %} {% tab title=“Assembler code” %}

     mr        r3, r26 # set
                    bl .sigfillset
                    li        r0, 0xAE
                    li        r3, 2
                    mr        r4, r26
                    mr        r5, r29
                    li        r6, 8
                    sc
                    mfcr      r0
                    lwz       r5, (off_F9A704C - dword_F9A7130)(r30) # sub_F9920A4 # start_routine
                    mr        r4, r31 # attr
                    mr        r6, r28 # arg
                    addi      r3, r1, 0x180+var_54 # newthread
                    bl .pthread_create
                    li        r0, 0xAE
                    mr        r26, r3
                    mr        r4, r29
                    li        r3, 2
                    li        r5, 0
                    li        r6, 8
                    sc
                    mfcr      r0
                    mr        r3, r31 # attr
                    bl .pthread_attr_destroy
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    ...
    sigset_t v36; // [sp+8h] [-178h]@47 F992C04 TYPED
    sigset_t v37; // [sp+88h] [-F8h]@47 F992BEC TYPED
    pthread_attr_t v38; // [sp+108h] [-78h]@47 F992BC4 TYPED
    __int16 v39; // [sp+12Ch] [-54h]@47 F992C1C
    ...
    
    _sigfillset(&v37);
    v29 = linux_syscall(__NR_rt_sigprocmask, 2, &v37, &v36);
    v30 = _pthread_create((pthread_t *)&v39, &v38, (void *(*)(void *))0x93C10018, v11);
    v31 = linux_syscall(__NR_rt_sigprocmask, 2, &v36, 0);
    _pthread_attr_destroy(&v38);
    

    {% endtab %} {% endtabs %}

    Compiler helpers

    Compiler sometime uses helpers and decompiler knows the meaning of the many helpers and uses it to simplify code.

    {% tabs %} {% tab title=“Assembler code” %}

    .globl lldiv # weak
    lldiv:
    
    .set back_chain, -0x30
    .set var_18, -0x18
    .set var_14, -0x14
    .set var_10, -0x10
    .set var_C, -0xC
    .set var_8, -8
    .set var_4, -4
    .set sender_lr, 4
    
                    stwu      r1, back_chain(r1)
                    mflr      r0
                    stw       r28, 0x30+var_10(r1)
                    mr        r28, r5
                    stw       r29, 0x30+var_C(r1)
                    mr        r29, r6
                    stw       r31, 0x30+var_4(r1)
                    mr        r5, r7
                    mr        r31, r3
                    mr        r6, r8
                    mr        r3, r28
                    mr        r4, r29
                    stw       r0, 0x30+sender_lr(r1)
                    stw       r26, 0x30+var_18(r1)
                    mr        r26, r7
                    stw       r27, 0x30+var_14(r1)
                    mr        r27, r8
                    stw       r30, 0x30+var_8(r1)
                    bl        __divdi3
                    stw       r3, 0(r31)
                    mr        r5, r26
                    stw       r4, 4(r31)
                    mr        r6, r27
                    mr        r3, r28
                    mr        r4, r29
                    bl        __moddi3
                    lwz       r0, 0x30+sender_lr(r1)
                    stw       r3, 8(r31)
                    mr        r3, r31
                    stw       r4, 0xC(r31)
                    mtlr      r0
                    lwz       r26, 0x30+var_18(r1)
                    lwz       r27, 0x30+var_14(r1)
                    lwz       r28, 0x30+var_10(r1)
                    lwz       r29, 0x30+var_C(r1)
                    lwz       r30, 0x30+var_8(r1)
                    lwz       r31, 0x30+var_4(r1)
                    addi      r1, r1, 0x30
                    blr
    # End of     function lldiv
    
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    __int64 *__fastcall lldiv(__int64 *result, int a2, __int64 a3, __int64 a4)
    {
        *result = a3 / a4;
        result[1] = a3 % a4;
        return result;
    }
    

    {% endtab %} {% endtabs %}

    Floating point arithmetic

    The PowerPC processor contains a number of complex floating point instructions which perform several operations at once. It is not easy to recover an expression from the assembler code but not for the decompiler.

    {% tabs %} {% tab title=“Assembler code” %}

                    .globl _x2y2m1f
    _x2y2m1f:
                    lis	 r9, unk_20@ha
                    lfs	 f0, unk_20@l(r9)
                    fsub	 f12, f1, f0
                    fadd	 f0, f1, f0
                    fmul	 f0, f12, f0
                    fmadd	 f1, f1, f2, f0
                    blr
    # End of	function _x2y2m1f
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    double __fastcall x2y2m1f(double a1, double a2)
    {
        return a1 * ((a1 - 1.0) * (a1 + 1.0)) + a2;
    }
    

    {% endtab %} {% endtabs %}

    Magic multiplication/division operations

    Compilers can decompose a multiplication/division instruction into a sequence of cheaper instructions (additions, shifts, etc). This example demonstrates how the decompiler recognizes them and coagulates back to the original operation.

    {% tabs %} {% tab title=“Assembler code” %}

    # __int64 __fastcall int_u_mod_10()
                    .globl int_u_mod_10
    int_u_mod_10:
    
    .set back_chain, -0x20
    .set var_C, -0xC
    .set var_8, -8
    .set var_4, -4
    .set sender_lr, 4
    
                    stwu      r1, back_chain(r1)
                    mflr      r0
                    stw       r0, 0x20+sender_lr(r1)
                    stw       r29, 0x20+var_C(r1)
                    stw       r30, 0x20+var_8(r1)
                    stw       r31, 0x20+var_4(r1)
                    mr        r31, r1
                    bl        u
                    mr        r10, r3
                    lis       r9, -0x3334
                    ori       r9, r9, 0xCCCD # 0xCCCCCCCD
                    mulhwu    r9, r10, r9
                    srwi      r9, r9, 3
                    mulli     r9, r9, 0xA
                    subf      r9, r9, r10
                    mr        r30, r9
                    li        r29, 0
                    mr        r9, r29
                    mr        r10, r30
                    mr        r3, r9
                    mr        r4, r10
                    addi      r11, r31, 0x20
                    lwz       r0, 4(r11)
                    mtlr      r0
                    lwz       r29, -0xC(r11)
                    lwz       r30, -8(r11)
                    lwz       r31, -4(r11)
                    mr        r1, r11
                    blr
    # End of      function int_u_mod_10
    
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    __int64 __fastcall int_u_mod_10()
    {
        return u() % 0xAu;
    }
    

    {% endtab %} {% endtabs %}

    VLE code

    This example demonstrates that the decompiler can handle VLE code without problems.

    {% tabs %} {% tab title=“Assembler code” %}

    sub_498E:
                    se_mr     r6, r3
                    se_mr     r7, r4
                    se_add    r7, r6
                    se_subi   r7, 1
                    se_li     r5, 0
                    se_b      loc_49A2
    # ---------------------------------------------------------------------------
    loc_499A:
                    se_lbz    r4, 0(r6)
                    se_add    r5, r4
                    se_extzh  r5
                    se_addi   r6, 1
    loc_49A2:
                    se_cmpl   r6, r7
                    se_ble    loc_499A
                    se_mr     r7, r5
                    se_mr     r3, r7
                    se_blr
    # End of function sub_498E
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall sub_498E(unsigned __int8 *a1, int a2)
    {
      unsigned __int8 *v2; // r6@1 498F TYPED
      int v3; // r5@1 4997
    
      v2 = a1;
      v3 = 0;
      while ( v2 a1[a2 - 1] )
        v3 = (unsigned __int16)(v3 + *v2++);
      return v3;
    }
      
    

    {% endtab %} {% endtabs %}

    Interactive decompiler

    The pseudocode is not something static because the decompiler is interactive the same way as IDA. You can change variable types and names, change function prototypes, add comments and more. The example above presents the result after these modifications.

    Surely the result is not ideal, and there is a lot of room for improvement, but we hope that you got the idea.

    And you can compare the result with the original: http://lxr.free-electrons.com/source/fs/fat/namei_msdos.c#L224

    {% tabs %} {% tab title=“Assembler code” %}

    # int __fastcall msdos_add_entry(struct inode *_dir, const unsigned __int8 *name, int is_dir, int is_hid,
    int cluster, struct timespec *_ts, struct fat_slot_info *_sinfo)
    msdos_add_entry:
    
    .set back_chain, -0x50
    .set de, -0x48
    .set date, -0x28
    .set time, -0x26
    .set var_14, -0x14
    .set sender_lr, 4
    
                    mflr      r0
                    stw       r0, sender_lr(r1)
                    bl        _mcount
                    stwu      r1, back_chain(r1)
                    mflr      r0
                    stmw      r27, 0x50+var_14(r1)
                    stw       r0, 0x50+sender_lr(r1)
                    subfic    r5, r5, 0
                    mr.       r30, r6
                    lwz       r0, 0(r4)
                    subfe     r10, r10, r10
                    mr        r31, r3
                    lwz       r11, 4(r4)
                    lwz       r3, 0x1C(r3)
                    clrrwi    r10, r10, 4
                    mr        r29, r7
                    lhz       r5, 8(r4)
                    addi      r10, r10, 0x20
                    mr        r28, r8
                    lbz       r6, 0xA(r4)
                    mr        r27, r9
                    lwz       r3, 0x2B8(r3)
                    stw       r0, 0x50+de(r1)
                    stw       r11, 0x50+de.name+4(r1)
                    sth       r5, 0x50+de.name+8(r1)
                    stb       r6, 0x50+de.name+0xA(r1)
                    stb       r10, 0x50+de.attr(r1)
                    beq       loc_728
                    ori       r10, r10, 2
                    li        r9, 0
                    li        r7, 0
                    addi      r6, r1, 0x50+date
                    stb       r10, 0x50+de.attr(r1)
                    addi      r5, r1, 0x50+time
                    mr        r4, r8
                    stb       r9, 0x50+de.lcase(r1)
                    bl        fat_time_unix2fat
                    lhz       r9, 0x50+time(r1)
                    li        r10, 0
                    sth       r10, 0x50+de.adate(r1)
                    sth       r9, 0x50+de.time(r1)
                    lhz       r9, 0x50+date(r1)
                    sth       r10, 0x50+de.cdate(r1)
                    sth       r10, 0x50+de.ctime(r1)
                    stb       r10, 0x50+de.ctime_cs(r1)
                    sth       r9, 0x50+de.date(r1)
    loc_698:
                    addi      r10, r1, 0x50+de.start
                    srawi     r9, r29, 0x10
                    sthbrx    r29, r0, r10
                    addi      r10, r1, 0x50+de.starthi
                    mr        r6, r27
                    sthbrx    r9, r0, r10
                    li        r5, 1
                    li        r9, 0
                    addi      r4, r1, 0x50+de
                    mr        r3, r31
                    stw       r9, 0x50+de.size(r1)
                    bl        fat_add_entries
                    mr.       r30, r3
                    bne       loc_710
                    lwz       r10, 0(r28)
                    lwz       r11, 4(r28)
                    stw       r10, 0x48(r31)
                    stw       r10, 0x50(r31)
                    stw       r11, 0x4C(r31)
                    stw       r11, 0x54(r31)
                    lwz       r9, 0x1C(r31)
                    lwz       r9, 0x34(r9)
                    andi.     r10, r9, 0x90
                    bne       loc_704
                    lwz       r9, 0xC(r31)
                    andi.     r10, r9, 0x41
                    beq       loc_768
    loc_704:
                    mr        r3, r31       # struct inode *
                    li        r30, 0
                    bl        fat_sync_inode
    loc_710:
                    mr        r3, r30
                    lwz       r0, 0x50+sender_lr(r1)
                    lmw       r27, 0x50+var_14(r1)
                    addi      r1, r1, 0x50
                    mtlr      r0
                    blr
    # ---------------------------------------------------------------------------
    loc_728:
                    li        r7, 0
                    addi      r6, r1, 0x50+date
                    stb       r30, 0x50+de.lcase(r1)
                    addi      r5, r1, 0x50+time
                    mr        r4, r8
                    bl        fat_time_unix2fat
                    li        r9, 0
                    sth       r30, 0x50+de.adate(r1)
                    stb       r9, 0x50+de.ctime_cs(r1)
                    lhz       r9, 0x50+time(r1)
                    sth       r30, 0x50+de.cdate(r1)
                    sth       r9, 0x50+de.time(r1)
                    lhz       r9, 0x50+date(r1)
                    sth       r30, 0x50+de.ctime(r1)
                    sth       r9, 0x50+de.date(r1)
                    b         loc_698
    # ---------------------------------------------------------------------------
    loc_768:
                    mr        r3, r31       # struct inode *
                    li        r4, 7
                    bl        __mark_inode_dirty
                    mr        r3, r3
                    lwz       r0, 0x50+sender_lr(r1)
                    lmw       r27, 0x50+var_14(r1)
                    addi      r1, r1, 0x50
                    mtlr      r0
                    blr
    # End of       function msdos_add_entry
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall msdos_add_entry(struct inode *dir, const unsigned __int8 *name, int is_dir, int is_hid,
                                   int cluster, struct timespec *ts, struct fat_slot_info *sinfo)
    {
      __int16 zero; // r30@1 601
      bool not_hidden; // cr34@1 601 TYPED
      int v10; // r11@1 611
      signed int v11; // r10@1 619 TYPED
      __int16 v13; // r5@1 621
      __u8 node_attrs; // r10@1 625 TYPED
      __u8 v16; // r6@1 62D TYPED
      struct msdos_sb_info *sbi; // r3@1 635 TYPED
      int err; // r30@3 6C9 TYPED
      __time_t sec; // r10@4 6D1 TYPED
      __syscall_slong_t nsec; // r11@4 6D5 TYPED
      struct msdos_dir_entry de; // [sp+8h] [-48h]@1 639 TYPED
      __le16 date; // [sp+28h] [-28h]@2 670 TYPED
      __le16 time; // [sp+2Ah] [-26h]@2 670 TYPED
    
      zero = is_hid;
      not_hidden = is_hid == 0;
      v10 = *((_DWORD *)name + 1);
      v11 = (unsigned int)is_dir <= 0 ? 0 : -16;
      v13 = *((_WORD *)name + 4);
      node_attrs = v11 + ATTR_ARCH;                 // ATTR_ARCH or ATTR_DIR
      v16 = name[10];
      sbi = (struct msdos_sb_info *)dir->i_sb->s_fs_info;
      *(_DWORD *)&de.name[0] = *(_DWORD *)name;     // memcpy(&de.name[0], name, 12);
      *(_DWORD *)&de.name[4] = v10;                 // ...
      *(_WORD *)&de.name[8] = v13;                  // ...
      de.name[10] = v16;
      de.attr = node_attrs;
      if ( not_hidden )
      {
        de.lcase = zero;                            // = 0
        fat_time_unix2fat(sbi, ts, &time, &date, 0);
        de.adate = zero;
        de.ctime_cs = 0;
        de.cdate = zero;
        de.time = time;
        de.ctime = zero;
        de.date = date;
      }
      else
      {
        de.attr = node_attrs | ATTR_HIDDEN;
        de.lcase = 0;
        fat_time_unix2fat(sbi, ts, &time, &date, 0);
        de.adate = 0;
        de.time = time;
        de.cdate = 0;
        de.ctime = 0;
        de.ctime_cs = 0;
        de.date = date;
      }
      de.start = _byteswap_ushort(cluster);
      de.starthi = _byteswap_ushort(HIWORD(cluster));
      de.size = 0;
      err = fat_add_entries(dir, &de, 1, sinfo);
      if ( err )
        return err;
      sec = ts->tv_sec;
      nsec = ts->tv_nsec;
      dir->i_mtime.tv_sec = ts->tv_sec;
      dir->i_ctime.tv_sec = sec;
      dir->i_mtime.tv_nsec = nsec;
      dir->i_ctime.tv_nsec = nsec;
      if ( dir->i_sb->s_flags & (MS_DIRSYNC|MS_SYNCHRONOUS) || dir->i_flags & (S_DIRSYNC|S_SYNC) )
      {
        err = 0;
        fat_sync_inode(dir);
        return err;
      }
      _mark_inode_dirty(dir);
      return 0;
    }
                            
    

    {% endtab %} {% endtabs %}

    Comparisons of MIPS disassembly and decompilation

    Here are some side-by-side comparisons of disassembly and decompiler for MIPS. Please maximize the window too see both columns simultaneously.

    The following examples are displayed on this page:

    1. Simple code
    2. 64-bit comparison
    3. Magic divisions
    4. Hard cases with delay slots
    5. Little-endian MIPS
    6. MicroMIPS
    7. Floating-point operations
    8. Compiler helpers

    Simple code

    This is a very simple code to decompile and the output is perfect. The only minor obstacle are references through the global offset table but both IDA and the Decompiler handle them well. Please note the difference in the number of lines to read on the left and on the right.

    {% tabs %} {% tab title=“Assembler code” %}

    # void __fastcall free_argv(int argc, char **argv)
                    .globl _Z9free_argviPPc  # weak
    _Z9free_argviPPc:                        # CODE XREF: test_expand_argv(void)+264↑p
                                             # test_expand_argv(void)+51C↑p ...
    
    var_10          = -0x10
    var_4           = -4
    var_s0          =  0
    var_s4          =  4
    arg_0           =  8
    arg_4           =  0xC
    
     # __unwind {
                    addiu   $sp, -0x28
                    sw      $ra, 0x20+var_s4($sp)
                    sw      $fp, 0x20+var_s0($sp)
                    move    $fp, $sp
                    la      $gp, _GLOBAL_OFFSET_TABLE_+0x7FF0
                    sw      $gp, 0x20+var_10($sp)
                    sw      $a0, 0x20+arg_0($fp)
                    sw      $a1, 0x20+arg_4($fp)
                    lw      $v0, 0x20+arg_4($fp)
                    beqz    $v0, loc_17778
                    nop
                    sw      $zero, 0x20+var_4($fp)
    
    loc_1770C:                               # CODE XREF: free_argv(int,char **)+80↓j
                    lw      $v1, 0x20+var_4($fp)
                    lw      $v0, 0x20+arg_0($fp)
                    slt     $v0, $v1, $v0
                    beqz    $v0, loc_17760
                    nop
                    lw      $v0, 0x20+var_4($fp)
                    sll     $v0, 2
                    lw      $v1, 0x20+arg_4($fp)
                    addu    $v0, $v1, $v0
                    lw      $v0, 0($v0)
                    move    $a0, $v0
                    lw      $v0, (qfree_ptr-0x7FF0 - _GLOBAL_OFFSET_TABLE_)($gp)
                    move    $t9, $v0
                    jalr    $t9 ; qfree
                    nop
                    lw      $gp, 0x20+var_10($fp)
                    lw      $v0, 0x20+var_4($fp)
                    addiu   $v0, 1
                    sw      $v0, 0x20+var_4($fp)
                    b       loc_1770C
                    nop
     # ---------------------------------------------------------------------------
    
    loc_17760:                               # CODE XREF: free_argv(int,char **)+40↑j
                    lw      $a0, 0x20+arg_4($fp)
                    lw      $v0, (qfree_ptr-0x7FF0 - _GLOBAL_OFFSET_TABLE_)($gp)
                    move    $t9, $v0
                    jalr    $t9 ; qfree
                    nop
                    lw      $gp, 0x20+var_10($fp)
    
    loc_17778:                               # CODE XREF: free_argv(int,char **)+28↑j
                    nop
                    move    $sp, $fp
                    lw      $ra, 0x20+var_s4($sp)
                    lw      $fp, 0x20+var_s0($sp)
                    addiu   $sp, 0x28
                    jr      $ra
                    nop
     # } // starts at 176D8
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    void __fastcall free_argv(int argc, char **argv)
    {
      int i; // [sp+1Ch] [+1Ch]
    
      if ( argv )
      {
        for ( i = 0; i < argc; ++i )
          qfree(argv[i]);
        qfree(argv);
      }
    }
    

    {% endtab %} {% endtabs %}

    64-bit comparison

    Sorry for another long assembler listing. It shows that for MIPS, as for other platforms, the decompiler can recognize 64-bit operations and collapse them into very readable constructs.

    {% tabs %} {% tab title=“Assembler code” %}

    # =============== S U B R O U T I N E =======================================
    
    # Attributes: bp-based frame fpd=0x18
    
    # _DWORD uh_eq_s(void)
                    .globl _Z7uh_eq_sv
    _Z7uh_eq_sv:                             # DATA XREF: .eh_frame:000478E4↓o
    
    var_s0          =  0
    var_s4          =  4
    var_s8          =  8
    var_sC          =  0xC
    var_s10         =  0x10
    var_s14         =  0x14
    var_s18         =  0x18
    var_s1C         =  0x1C
    
     # __unwind {
                    addiu   $sp, -0x38
                     sw      $ra, 0x18+var_s1C($sp)
                     sw      $fp, 0x18+var_s18($sp)
                     sw      $s5, 0x18+var_s14($sp)
                     sw      $s4, 0x18+var_s10($sp)
                     sw      $s3, 0x18+var_sC($sp)
                     sw      $s2, 0x18+var_s8($sp)
                     sw      $s1, 0x18+var_s4($sp)
                     sw      $s0, 0x18+var_s0($sp)
                     move    $fp, $sp
                     jal     uh
                     nop
                     move    $s5, $v1
                     move    $s4, $v0
                     jal     s
                     nop
                     move    $s3, $v0
                     sra     $v0, 31
                     move    $s2, $v0
                     xor     $s0, $s4, $s2
                     xor     $s1, $s5, $s3
                     or      $v0, $s0, $s1
                     sltiu   $v0, 1
                     andi    $v0, 0xFF
                     move    $sp, $fp
                     lw      $ra, 0x18+var_s1C($sp)
                     lw      $fp, 0x18+var_s18($sp)
                     lw      $s5, 0x18+var_s14($sp)
                     lw      $s4, 0x18+var_s10($sp)
                     lw      $s3, 0x18+var_sC($sp)
                     lw      $s2, 0x18+var_s8($sp)
                     lw      $s1, 0x18+var_s4($sp)
                     lw      $s0, 0x18+var_s0($sp)
                     addiu   $sp, 0x38
                     jr      $ra
                     nop
      # } // starts at 25C
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    bool uh_eq_s(void)
    {
      unsigned __int64 v0; // $v1
    
      v0 = uh();
      return v0 == s();
    }
    

    {% endtab %} {% endtabs %}

    Magic divisions

    We recognize magic divisions for MIPS the same way as for other processors. Note that this listing has a non-trivial delay slot.

    {% tabs %} {% tab title=“Assembler code” %}

    .globl smod199
     smod199:                                 # DATA XREF: .eh_frame:0000875C↓o
     # __unwind {
                     lui     $v1, 0x5254
                     sra     $v0, $a0, 31
                     li      $v1, 0x5254E78F
                     mult    $a0, $v1
                     mfhi    $v1
                     sra     $v1, 6
                     subu    $v1, $v0
                     li      $v0, 0xC7
                     mul     $a1, $v1, $v0
                     jr      $ra
                     subu    $v0, $a0, $a1
      # } // starts at 4F2C
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall smod199(int a1)
    {
      return a1 % 199;
    }
    
    

    {% endtab %} {% endtabs %}

    Hard cases with delay slots

    The previous example was a piece of cake. This one shows a tougher nut to crack: there is a jump to a delay slot. A decent decompiler must handle these cases too and produce a correct output without misleading the user. This is what we do. (We spent quite long time inventing and testing various scenarios with delay slots).

    {% tabs %} {% tab title=“Assembler code” %}

    branch_to_b_dslot:                       # CODE XREF: branch_to_bal_dslot+14↓p
                                             # DATA XREF: branch_likely_cond_move+10↓o
                    move    $t2, $a0
                    addiu   $t3, $t2, -0x18
                    bltz    $t3, l1
                    li      $a0, 1
                    sllv    $a0, $t3
                    b       l2
    
    l1:                                      # CODE XREF: branch_to_b_dslot+8↑j
                    li      $t4, 0xFFFFFFC0
                    li      $t3, 0x18
                    subu    $t3, $t2
                    srav    $a0, $t3
    
    l2:                                      # CODE XREF: branch_to_b_dslot+14↑j
                    jr      $ra
                    addu    $v0, $a0, $t4
     # End of function branch_to_b_dslot
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall branch_to_b_dslot(int a1)
    {
      int v1; // $a0
    
      if ( a1 - 24 < 0 )
        v1 = 1 >> (24 - a1);
      else
        v1 = 1 << (a1 - 24);
      return v1 - 64;
    }
    

    {% endtab %} {% endtabs %}

    Little-endian MIPS

    We support both big-endian and little-endian code. Usually they look the same but there may be subtle differences in the assembler. The decompiler keeps track of the bits involved and produces human-readable code.

    {% tabs %} {% tab title=“Little-endian” %}

    .globl upd_d2
    upd_d2:
                    lwl     $v0, 5($a0)
                    lwr     $v0, 2($a0)
                    addiu   $v0, $v0, 1
                    swl     $v0, 5($a0)
                    swr     $v0, 2($a0)
                    jr      $ra
                    lb      $v0, 0($a0)
     # End of function upd_d2
    

    {% endtab %}

    {% tab title=“Big-endian” %}

     .globl upd_d2
    upd_d2:
                    lwl     $v0, 2($a0)
                    lwr     $v0, 5($a0)
                    addiu   $v0, $v0, 1
                    swl     $v0, 2($a0)
                    swr     $v0, 5($a0)
                    jr      $ra
                    lb      $v0, 0($a0)
     # End of function upd_d2
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    int __fastcall upd_d2(char *a1)
    {
      ++*(_DWORD *)(a1 + 2);
      return *a1;
    }
    
    

    {% endtab %} {% endtabs %}

    MicroMIPS

    MicroMIPS, as you have probably guessed, is supported too, with its special instructions and quirks.

    {% tabs %} {% tab title=“Assembler code” %}

     lwm16_sp:
    
     var_10          = -0x10
    
                     addiu   $sp, -0x10
                     swm     $ra,$s0-$s2, 0x10+var_10($sp)
                     move    $s0, $a0
                     move    $s1, $a1
                     move    $s2, $a2
                     addu    $s0, $s1
                     addu    $v0, $s0, $s2
                     lwm     $ra,$s0-$s2, 0x10+var_10($sp)
                     jraddiusp 0x10
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    __int64 __fastcall lwm16_sp(int a1, int a2, int a3)
    {
      return a1 + a2 + a3;
    }
    

    {% endtab %} {% endtabs %}

    Floating-point operations

    The MIPS processor contains a number of complex floating point instructions, which perform several operations at once. It is not easy to decipher the meaning of the assembler code but the pseudocode is the simplest possible.

    {% tabs %} {% tab title=“Assembler code” %}

    x2y2m1f:
                    lui     $v0, %hi(dbl_50)
                    ldc1    $f1, dbl_50
                    sub.d   $f0, $f12, $f1
                    add.d   $f1, $f12, $f1
                    mul.d   $f0, $f1
                    jr      $ra
                    madd.d  $f0, $f13, $f0, $f12
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    double __fastcall x2y2m1f(double a1, double a2)
    {
      return a2 * ((a1 - 1.0) * (a1 + 1.0)) + a1;
    }
    

    {% endtab %} {% endtabs %}

    Compiler helpers

    A compiler sometime uses helpers; our decompiler knows the meaning of the many helpers and uses it to simplify code.

    {% tabs %} {% tab title=“Assembler code” %}

    mod4:
    
    var_C           = -0xC
    var_s0          =  0
    
                    lui     $gp, %hi(_GLOBAL_OFFSET_TABLE_+0x7FF0)
                    addiu   $sp, -0x20
                    la      $gp, _GLOBAL_OFFSET_TABLE_+0x7FF0
                    li      $a3, 5
                    sw      $ra, 0x1C+var_s0($sp)
                    sw      $gp, 0x1C+var_C($sp)
                    lw      $t9, (__moddi3_ptr-0x7FF0 - _GLOBAL_OFFSET_TABLE_)($gp)
                    jalr    $t9 ; __moddi3
                    move    $a2, $zero
                    lw      $ra, 0x1C+var_s0($sp)
                    jr      $ra
                    addiu   $sp, 0x20
    
    
    

    {% endtab %}

    {% tab title=“Pseudocode” %}

    __int64 __fastcall mod4(__int64 a1)
    {
      return a1 % 5;
    }
    

    {% endtab %} {% endtabs %}

    Hex-Rays v7.4 vs. v7.3 Decompiler Comparison Page

    Here are some side-by-side comparisons of decompilations for v7.3 and v7.4. Please maximize the window too see both columns simultaneously.

    The following examples are displayed on this page:

    1. Better array detection
    2. Support for more floating-point helpers
    3. Automatic variable mapping
    4. Automatic symbolic names
    5. Simplified C++ names
    6. Improved handling of 64-bit arithmetics
    7. Better detection of 64-bit decrements
    8. More meaningful variable names

    Better array detection

    The text produced by v7.3 is not quite correct because the array at [ebp-128] was not recognized. Overall determining the array is a tough task but we can handle simple cases automatically now.

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    _BYTE v7[256]; // [sp+0h] [bp-128h]
      __int64 v8; // [sp+120h] [bp-8h]
    
      v8 = a2;
      v4 = a2;
      memcpy(v7, &v8, sizeof(v7));
      memcpy(a1, v7, 0x100u);
    
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    _QWORD *v5; // r4
    int v7; // [sp+0h] [bp-128h]
    __int64 v8; // [sp+120h] [bp-8h]
    
      v8 = a2;
      v4 = a2;
      v5 = a1;
      memcpy(&v7, &v8, 0x100u);
      memcpy(v5, &v7, 0x100u);
    

    {% endtab %} {% endtabs %}

    Support for more floating-point helpers

    On the left there is a mysterious call to _extendsfdf2. In fact this is a compiler helper function that just converts a single precision floating point value into a double precision value. However, we do not want to see this call as is. It is much better to translate it into the code that looks more like C. Besides, there is a special treatment for printf-like functions.

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    void __cdecl printf_float(float a)
    {
      printf("%f\n", a);
    }
    
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    void __cdecl printf_float(float a)
    {
      double v1; // r0
    
      v1 = COERCE_DOUBLE(_extendsfdf2(LODWORD(a)));
      printf("%f\n", v1);
    }
    

    {% endtab %} {% endtabs %}

    Automatic variable mapping

    In some cases we can easily prove that one variable can be mapped into another. The new version automatically creates a variable mapping in such cases. This makes the output shorter and easier to read. Needless to say that the user can revert the mapping if necessary.

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    __int64 sprintf_s(
            char *__ptr64 const _Buffer,
            const unsigned __int64 _BufferCount,
            const char *__ptr64 const _Format,
            ...)
    {
      unsigned __int64 *v6; // x0
      __int64 result; // x0
      va_list va; // [xsp+38h] [xbp+38h]
    
      va_start(va, _Format);
      v6 = _local_stdio_printf_options();
      return _stdio_common_vsprintf_s(*v6, _Buffer, _BufferCount, _Format, 0i64,
                                      (char *__ptr64)va);
    }
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    __int64 sprintf_s(
            char *__ptr64 const _Buffer,
            const unsigned __int64 _BufferCount,
            const char *__ptr64 const _Format,
            ...)
    {
      char *v3; // x21
      unsigned __int64 v4; // x20
      const char *v5; // x19
      unsigned __int64 *v6; // x0
      __int64 result; // x0
      va_list va; // [xsp+38h] [xbp+38h]
    
      va_start(va, _Format);
      v3 = _Buffer;
      v4 = _BufferCount;
      v5 = _Format;
      v6 = _local_stdio_printf_options();
      return _stdio_common_vsprintf_s(*v6, v3, v4, v5, 0i64, (char *__ptr64)va);
    }
    
    

    {% endtab %} {% endtabs %}

    Automatic symbolic names

    The new version automatically applies symbolic constants when necessary. Less manual work.

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

      if ( operation == ReadKeyNames )
        return BaseDllReadVariableNames(v1, v2);
      if ( operation != ReadSection )
      {
        if ( operation == WriteKeyValue || operation == DeleteKey )
          return BaseDllWriteVariableValue(v1, v2, 0, 0);
        if ( operation == WriteSection || operation == DeleteSection )
          return BaseDllWriteApplicationVariables(v1, v2);
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    if ( operation == 4 )
        return BaseDllReadVariableNames(v1, v2);
      if ( operation != 6 )
      {
        if ( operation == 2 || operation == 3 )
          return BaseDllWriteVariableValue(v1, v2, 0, 0);
        if ( operation == 7 || operation == 8 )
          return BaseDllWriteApplicationVariables(v1, v2);
    

    {% endtab %} {% endtabs %}

    Simplified C++ names

    This is not the longest C++ function name one may encounter but just compare the left and right sides. In fact the right side could even fit into one line easily, we just kept it multiline to be consistent. By the way, all names in IDA benefit from this simplification, not only the ones displayed by the decompiler. And it is configurable!

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    std::string *
    __fastcall
    std::_System_error::_Makestr(
      std::string *result,
      std::error_code _Errcode,
      std::string _Message)
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    std::basic_string<char,std::char_traits<char>,std::allocator<char> > *
    __fastcall
    std::_System_error::_Makestr(
      std::basic_string<char,std::char_traits<char>,std::allocator<char> > *result,
      std::error_code _Errcode,
      std::basic_string<char,std::char_traits<char>,std::allocator<char> > _Message)
    

    {% endtab %} {% endtabs %}

    Improved handling of 64-bit arithmetics

    The battle is long but we do not give up. More 64-bit patterns are recognized now.

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    return h() % 1024;
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    v0 = h();
    return (__int16)((((v0 ^ (SHIDWORD(v0) >> 31)) - (SHIDWORD(v0) >> 31)) & 0x3FF ^ (SHIDWORD(v0) >> 31))
                     - (SHIDWORD(v0) >> 31));
    

    {% endtab %} {% endtabs %}

    Better detection of 64-bit decrements

    Yet another example of 64-bit arithmetics. The code on the left is correct but not useful at all. It can and should be converted into the simple equivalent text on the right.

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    return a1 - 1;
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

    v1 = a1 + 0xFFFFFFFFLL;
      HIDWORD(v1) = ((unsigned __int64)(a1 + 0xFFFFFFFFLL) >> 32) - 1;
    

    {% endtab %} {% endtabs %}

    More meaningful variable names

    Currently we support only GetProcAddress but we are sure that we will expand this feature in the future.\

    {% tabs %} {% tab title=“Pseudocode v7.4” %}

    MessageBoxA_0 = (int (__stdcall *)(HWND, LPCSTR, LPCSTR, UINT))
                        GetProcAddress(v4, "MessageBoxA");
        if ( !MessageBoxA_0 )
          return 0;
        GetActiveWindow = (HWND (__stdcall *)())GetProcAddress(v5, "GetActiveWindow");
        GetLastActivePopup = (HWND (__stdcall *)(HWND))GetProcAddress(v5, "GetLastActivePopup");
      }
      if ( GetActiveWindow )
      {
        v3 = GetActiveWindow();
        if ( v3 )
        {
          if ( GetLastActivePopup )
            v3 = GetLastActivePopup(v3);
        }
      }
      return MessageBoxA_0(v3, a1, a2, a3);
    
    

    {% endtab %}

    {% tab title=“Pseudocode v7.3” %}

        dword_12313BA8 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))
                         GetProcAddress(v4, "MessageBoxA");
        if ( !dword_12313BA8 )
          return 0;
        dword_12313BAC = GetProcAddress(v5, "GetActiveWindow");
        dword_12313BB0 = (int (__stdcall *)(_DWORD))GetProcAddress(v5, "GetLastActivePopup");
      }
      if ( dword_12313BAC )
      {
        v3 = dword_12313BAC();
        if ( v3 )
        {
          if ( dword_12313BB0 )
            v3 = dword_12313BB0(v3);
        }
      }
      return dword_12313BA8(v3, a1, a2, a3);
    

    {% endtab %} {% endtabs %}

    Hex-Rays v7.3 vs. v7.2 Decompiler Comparison Page

    Below you will find side-by-side comparisons of v7.2 and v7.3 decompilations. Please maximize the window too see both columns simultaneously.

    The following examples are displayed on this page:

    1. More hexadecimal numbers in the output
    2. Support for variable size structures
    3. UTF-32 strings are printed inline
    4. Better argument detection for printf
    5. Better argument detection for scanf
    6. Resolved TEB references
    7. Better automatic selection of union fields
    8. Yet one more example of union fields
    9. Improved support for EABI helpers
    10. Improved local variable allocation
    11. Better recognition of string references
    12. Better handling of structures returned by value
    13. More while loops
    14. Shorter code
    15. Improved recognition of magic divisions
    16. Less gotos
    17. Division may generate an exception
    18. Order of variadic arguments
    19. Improved division recognition

    NOTE: these are just some selected examples that can be illustrated as side-by-side differences. There are many other improvements and new features that are not mentioned on this page. We just got tired selecting them. Some of the improvements that did not do to this page:

    • objc-related improvements
    • value range analysis can eliminate more useless code
    • better resolving of got-relative memory references
    • too big shift amounts are converted to lower values (e.g. 33->1)
    • more for-loops
    • better handling of fragemented variables
    • many other things…

    More hexadecimal numbers in the output

    When a constant looks nicer as a hexadecimal number, we print it as a hexadecimal number by default. Naturally, beauty is in the eye of the beholder, but the new beahavior will produce more readable code, and less frequently you will fell compelled to change the number representation. By the way, this tiny change is just one of numerious improvements that we keep adding in each release. Most of them go literally unnoticed. It is just this time we decided to talk about them

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    bool __fastcall ge_100000001(__int64 a1)
    {
      return a1 >= 0x100000001LL;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    bool __fastcall ge_100000001(__int64 a1)
    {
      return a1 >= 4294967297LL;
    }
    
    

    {% endtab %} {% endtabs %}

    Support for variable size structures

    EfiBootRecord points to a structure that has RecordExtents[0] as the last member. Such structures are considered as variable size structures in C/C++. Now we handle them nicely.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    BlockNumber = EfiBootRecord->RecordExtents[ExtentIndex64].BlockNumber;
    BlockCount = EfiBootRecord->RecordExtents[ExtentIndex64].BlockCount;
    
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    BlockNumber = *(UINT64 *)((char *)&EfiBootRecord[1].BlockHeader.Checksum + ExtentIndex64);
    BlockCount = *(UINT64 *)((char *)&EfiBootRecord[1].BlockHeader.ObjectOid + ExtentIndex64);
    
    

    {% endtab %} {% endtabs %}

    UTF-32 strings are printed inline

    We were printing UTF-8 and other string types, UTF-32 was not supported yet. Now we print it with the ‘U’ prefix.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    v3 = std::operator<<<std::char_traits<char>>(&std::cout, U"This is U\"Hello\"
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

        .rodata:0000000000000120  text "UTF-32LE", 'This is U"Hello"',0
        ...
        v10 = std::ostream::operator<<(v9, aThisIsUHello_0);
    
    

    {% endtab %} {% endtabs %}

    Better argument detection for printf

    The difference between these outputs is subtle but pleasant. The new version managed to determine the variable types based on the printf format string. While the old version ended up with int a2, int a3, the new version correctly determined them as one __int64 a2.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    int __fastcall ididi(int a1, __int64 a2, int a3, __int64 a4, int a5)
    {
      int varg_r0; // [sp+28h] [bp-10h]
      __int64 varg_r2; // [sp+30h] [bp-8h]
    
      varg_r0 = a1;
      varg_r2 = a2;
      my_print("d=%I64d\n", a2);
      my_print("d1=%I64d\n", a4);
      my_print("%d-%I64d-%d-%I64d-%d\n", varg_r0, varg_r2, a3, a4, a5);
      return 0;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    int __fastcall ididi(int a1, int a2, __int64 a3, int a4, __int64 a5, int a6)
    {
      int v6; // r1
      char v8; // [sp+4h] [bp-34h]
      int varg_r0; // [sp+28h] [bp-10h]
      __int64 varg_r2; // [sp+30h] [bp-8h]
    
      varg_r0 = a1;
      varg_r2 = a3;
      my_print("d=%I64d\n", a2, a3);
      my_print("d1=%I64d\n", v6, a5);
      my_print("%d-%I64d-%d-%I64d-%d\n", varg_r0, varg_r2, a4, v8, a5, a6);
      return 0;
    }
    

    {% endtab %} {% endtabs %}

    Better argument detection for scanf

    A similar logic works for scanf-like functions. Please note that the old version was misdetecting the number of arguments. It was possible to correct the misdetected arguments using the Numpad-Minus hotkey but it is always better when there is less routine work on your shoulders, right?

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    scanf("8: %d%i %x%o %s%s %C%c", &v12, &v7, &v3, &v4, &v2, &v9, &v8, &v13);
    scanf("8:   %[ a-z]%c %2c%c %2c%2c %[ a-z]%c", &v12, &v7, &v3, &v4, &v2, &v9, &v8, &v13);
    
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

      scanf("8: %d%i %x%o %s%s %C%c", &v12, &v7, &v3, &v4, &v2, &v9, &v8, &v13, &v10, &v0, &v6, &v5, &v1, &v11);
      scanf(
        "8:   %[ a-z]%c %2c%c %2c%2c %[ a-z]%c",
        &v12,
        &v7,
        &v3,
        &v4,
        &v2,
        &v9,
        &v8,
        &v13,
        &v10,
        &v0,
        &v6,
        &v5,
        &v1,
        &v11);
    
    

    {% endtab %} {% endtabs %}

    Resolved TEB references

    While seasoned reversers know what is located at fs:0, it is still better to have it spelled out. Besides, the type of v15 is automatically detected as struct _EXCEPTION_REGISTRATION_RECORD *.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    v15 = NtCurrentTeb()->NtTib.ExceptionList;
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    v15 = __readfsdword(0);
    

    {% endtab %} {% endtabs %}

    Better automatic selection of union fields

    Again, the user can specify the union field that should be used in the output (the hotkey is Alt-Y) but there are situations when it can be automatically determined based on the access type and size. The above example illustrates this point. JFYI, the type of entry is:

    union __XmStringEntryRec
    {
      _XmStringEmptyHeader empty;
      _XmStringOptSegHdrRec single;
      _XmStringUnoptSegHdrRec unopt_single;
      _XmStringArraySegHdrRec multiple;
    };
    struct __XmStringEmptyHeader
    {
      unsigned __int32 type : 2;
    };
    struct __XmStringOptSegHdrRec
    {
      unsigned __int32 type : 2;
      unsigned __int32 text_type : 2;
      unsigned __int32 tag_index : 3;
      unsigned __int32 rend_begin : 1;
      unsigned __int8 byte_count;
      unsigned __int32 rend_end : 1;
      unsigned __int32 rend_index : 4;
      unsigned __int32 str_dir : 2;
      unsigned __int32 flipped : 1;
      unsigned __int32 tabs_before : 3;
      unsigned __int32 permanent : 1;
      unsigned __int32 soft_line_break : 1;
      unsigned __int32 immediate : 1;
      unsigned __int32 pad : 2;
    };
    

    While we can not handle bitfields yet, their presence does not prevent using other, regular fields, of the structure.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    if ( entry->single.byte_count )
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    if ( *((_BYTE *)&entry->empty + 1) )
    

    {% endtab %} {% endtabs %}

    Yet one more example of union fields

    I could not resist the temptation to include one more example of automatic union selection. How beautiful the code on the right is!

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    void __fastcall h_generic_calc_Perm32x8(V256 *res, V256 *argL, V256 *argR)
    {
      res->w32[0] = argL->w32[argR->w32[0] & 7];
      res->w32[1] = argL->w32[argR->w32[1] & 7];
      res->w32[2] = argL->w32[argR->w32[2] & 7];
      res->w32[3] = argL->w32[argR->w32[3] & 7];
      res->w32[4] = argL->w32[argR->w32[4] & 7];
      res->w32[5] = argL->w32[argR->w32[5] & 7];
      res->w32[6] = argL->w32[argR->w32[6] & 7];
      res->w32[7] = argL->w32[argR->w32[7] & 7];
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    void __fastcall h_generic_calc_Perm32x8(V256 *res, V256 *argL, V256 *argR)
    {
      LODWORD(res->w64[0]) = *((_DWORD *)argL->w64 + (argR->w64[0] & 7));
      HIDWORD(res->w64[0]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[0]) & 7));
      LODWORD(res->w64[1]) = *((_DWORD *)argL->w64 + (argR->w64[1] & 7));
      HIDWORD(res->w64[1]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[1]) & 7));
      LODWORD(res->w64[2]) = *((_DWORD *)argL->w64 + (argR->w64[2] & 7));
      HIDWORD(res->w64[2]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[2]) & 7));
      LODWORD(res->w64[3]) = *((_DWORD *)argL->w64 + (argR->w64[3] & 7));
      HIDWORD(res->w64[3]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[3]) & 7));
    }
    
    

    {% endtab %} {% endtabs %}

    Improved support for EABI helpers

    No comments needed, we hope. The new decompiler managed to fold constant expressions after replacing EABI helpers with corresponding operators.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      printf("r = %d == 42\n", 42);
      printf("r = %lld == 42\n", 42LL);
      printf("ABORT %d\n", 0x40000001);
      return 0;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    void __fastcall h_generic_calc_Perm32x8(V256 *res, V256 *argL, V256 *argR)
    {
      LODWORD(res->w64[0]) = *((_DWORD *)argL->w64 + (argR->w64[0] & 7));
      HIDWORD(res->w64[0]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[0]) & 7));
      LODWORD(res->w64[1]) = *((_DWORD *)argL->w64 + (argR->w64[1] & 7));
      HIDWORD(res->w64[1]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[1]) & 7));
      LODWORD(res->w64[2]) = *((_DWORD *)argL->w64 + (argR->w64[2] & 7));
      HIDWORD(res->w64[2]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[2]) & 7));
      LODWORD(res->w64[3]) = *((_DWORD *)argL->w64 + (argR->w64[3] & 7));
      HIDWORD(res->w64[3]) = *((_DWORD *)argL->w64 + (HIDWORD(argR->w64[3]) & 7));
    }
    

    {% endtab %} {% endtabs %}

    Improved local variable allocation

    Now it works better especially in complex cases.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    tbd
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      int v3; // r0
      int v4; // r0
      int v5; // r0
      int v6; // r0
      int v7; // r0
      __int64 v8; // r0
      int v9; // r2
      __int64 v11; // [sp+0h] [bp-14h]
      int v12; // [sp+Ch] [bp-8h]
      int v13; // [sp+Ch] [bp-8h]
    
      v3 = _mulvsi3(7, 6, envp);
      v4 = _negvsi2(v3);
      v5 = _addvsi3(v4, 101);
      v12 = _subvsi3(v5, 17);
      printf("r = %d == 42\n", v12);
      v11 = _mulvdi3(7, 0, 6, 0);
      v6 = _negvdi2(v12, v12 >> 31);
      v7 = _addvdi3(v6, v6 >> 31, 101, 0);
      v8 = _subvdi3(v7, v7 >> 31, 17, 0);
      printf("r = %lld == 42\n", HIDWORD(v8), v11);
      v13 = _mulvsi3(0x7FFFFFFF, 0x3FFFFFFF, v9);
      printf("ABORT %d\n", v13);
      return 0;
    }
    
    

    {% endtab %} {% endtabs %}

    Better recognition of string references

    In this case too, the user could set the prototype of sub_1135FC as accepting a char * and this would be enough to reveal string references in the output, but the new decompiler can do it automatically.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

      sub_1135FC(-266663568, "This is a long long long string");
      if ( v2 > 0x48u )
      {
        sub_108998("Another str");
    
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

      sub_1135FC(-266663568, 89351520);
      if ( v2 > 0x48u )
      {
        sub_108998(89351556);
    

    {% endtab %} {% endtabs %}

    Better handling of structures returned by value

    The code on the left had a very awkward sequence to copy a structure. The code on the right eliminates it as unnecessary and useless.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

      _BYTE v1[12]; // rax
      ...
      return *(mystruct *)v1;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

      _BYTE v1[12]; // ax
      mystruct result; // 0:ax.11
    
      ...
      *(_QWORD *)result.ca1 = *(_QWORD *)v1;
      result.s1 = *(_WORD *)&v1[8];
      result.c1 = v1[10];
      return result;
    }
    

    {% endtab %} {% endtabs %}

    More while loops

    Do you care about this improvement? Probably you do not care because the difference is tiny. However, in additon to be simpler, the code on the right eliminated a temporary variable, v5. A tiny improvement, but an improvement it is.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    while ( *++v4 )
        ;
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    do
        v5 = *++v4;
      while ( v5 );
    

    {% endtab %} {% endtabs %}

    Shorter code

    Another tiny improvement made the output considerably shorter. We like it!

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    unsigned __int8 *__fastcall otp_memset(unsigned __int8 *pDest, unsigned __int8 val, int size)
    {
      unsigned __int8 *i; // r3
    
      for ( i = pDest; (unsigned int)size-- >= 1; ++i )
        *i = val;
      return pDest;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    unsigned __int8 *__fastcall otp_memset(unsigned __int8 *pDest, unsigned __int8 val, int size)
    {
      unsigned __int8 *i; // r3
      _BOOL1 v4; // cf
    
      for ( i = pDest; ; ++i )
      {
        v4 = (unsigned int)size-- >= 1;
        if ( !v4 )
          break;
        *i = val;
      }
      return pDest;
    }
    }
    
    

    {% endtab %} {% endtabs %}

    Improved recognition of magic divisions

    This is a very special case: a division that uses the rcr instruction. Our microcode does not have the opcode for it but we implemented the logic to handle some special cases, just so you do not waste your time trying to decipher the meaning of convoluted code (yes, rcr means code that is difficult to understand).

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    unsigned __int64 __fastcall konst_mod251_shr3(unsigned __int64 a1)
    {
      return (a1 >> 3) % 0xFB;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    __int64 __fastcall konst_mod251_shr3(unsigned __int64 a1)
    {
      unsigned __int64 v1; // rcx
    
      v1 = a1 >> 3;
      _RDX = v1 + ((v1 * (unsigned __int128)0x5197F7D73404147ui64) >> 64);
      __asm { rcr     rdx, 1 }
      return v1 - 251 * (_RDX >> 7);
    }
    
    

    {% endtab %} {% endtabs %}

    Less gotos

    Well, we can not say that we produce less gotos in all cases, but there is some improvement for sure. Second, note that the return type got improved too: now it is immediately visible that the function returns a boolean (0/1) value.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    _BOOL8 __fastcall sub_0(__int64 a1, int *a2)
    {
      int v2; // eax
      int v3; // eax
      int v4; // eax
    
      v2 = *a2;
      if ( *a2 > 522 )
      {
        v4 = v2 - 4143;
        return !v4 || v4 == 40950;
      }
      if ( v2 != 522 )
      {
        v3 = v2 - 71;
        if ( v3 )
        {
          if ( (unsigned int)(v3 - 205) >= 2 )
            return 0;
        }
      }
      return 1;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    __int64 __fastcall sub_0(__int64 a1, int *a2)
    {
      int v2; // eax
      int v3; // eax
      int v4; // eax
    
      v2 = *a2;
      if ( *a2 > 522 )
      {
        v4 = v2 - 4143;
        if ( !v4 || v4 == 40950 )
          goto LABEL_8;
    LABEL_9:
        return 0;
      }
      if ( v2 != 522 )
      {
        v3 = v2 - 71;
        if ( v3 )
        {
          if ( (unsigned int)(v3 - 205) >= 2 )
            goto LABEL_9;
        }
      }
    LABEL_8:
      return 1;
    }
    

    {% endtab %} {% endtabs %}

    Division may generate an exception

    What a surprise, the code on the right is longer and more complex! Indeed, it is so, and it is because now the decompiler is more careful with the division instructions. They potentially may generate the zero division exception and completely hiding them from the output may be misleading. If you prefer the old behaviour, turn off the division preserving in the configuration file.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    __int64 __fastcall sub_4008C0(int a1)
    {
      int v1; // ecx
      int v2; // edx
      int v4; // [rsp+0h] [rbp-4h]
    
      v1 = 2;
      if ( a1 > 2 )
      {
        do
        {
          nanosleep(&rmtp, &rqtp);
          v2 = a1 % v1++;
          v4 = 1 / v2;
        }
        while ( v1 != a1 );
      }
      return 0LL;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    __int64 __fastcall sub_4008C0(int a1)
    {
      int v1; // ecx
    
      v1 = 2;
      if ( a1 > 2 )
      {
        do
        {
          nanosleep(&rmtp, &rqtp);
          ++v1;
        }
        while ( v1 != a1 );
      }
      return 0LL;
    }
    

    {% endtab %} {% endtabs %}

    Order of variadic arguments

    Do you notice the difference? If not, here is a hint: the order of arguments of sub_88 is different. The code on the right is more correct because the the format specifiers match the variable types. For example, %f matches float a. At the first sight the code on the left looks completely wrong but (surprise!) it works correctly on x64 machines. It is so because floating point and integer arguments are passed at different locations, so the relative order of floating/integer arguments in the call does not matter much. Nevertheless, the code on the right causes less confusion.

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    int __cdecl func1(const float a, int b, void *c)
    {
      return sub_88("%f, %d, %p\n", a, (unsigned int)b, c);
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    int __cdecl func1(const float a, int b, void *c)
    {
      return sub_88("%f, %d, %p\n", (unsigned int)b, c, a);
    }
    

    {% endtab %} {% endtabs %}

    Improved division recognition

    This is a never ending battle, but we advance!

    {% tabs %} {% tab title=“PSEUDOCODE V7.3” %}

    int int_h_mod_m32ui64(void)
    {
      return h() % 32;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.2” %}

    int int_h_mod_m32ui64(void)
    {
      __int64 v0; // r10
    
      v0 = h();
      return (abs64(v0) & 0x1F ^ (SHIDWORD(v0) >> 31)) - (SHIDWORD(v0) >> 31);
    }
    

    {% endtab %} {% endtabs %}

    Hex-Rays v7.2 vs. v7.1 Decompiler Comparison Page

    Below you will find side-by-side comparisons of v7.1 and v7.2 decompilations. Please maximize the window too see both columns simultaneously.

    The following examples are displayed on this page:

    1. Magic divisions in 64-bit code
    2. More aggressive ‘if’ to ‘boolean’ folding
    3. Better type of ‘this’ argument
    4. Improved union field selection
    5. Improved recognition of ‘for’ loops
    6. Added support for shifted pointers
    7. Better recognition of inlined standard functions
    8. Improved application of pre-increment and pre-decrement
    9. Added support for RRX addressing mode in ARM
    10. Improved constant propagation in global memory
    11. Added support for Objective C blocks
    12. Improved recognition of 64-bit comparisons
    13. Merged common code in ‘if’ branches
    14. Added forced stack variables
    15. Added support for virtual calls

    NOTE: these are just some selected examples that can be illustrated as side-by-side differences. There are many other improvements and new features that are not mentioned on this page.


    Magic divisions in 64-bit code

    In the past the Decompiler was able to recognize magic divisions in 32-bit code. We now support magic divisions in 64-bit code too.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    return 21600 * (t / 21600);
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

      return 21600
           * (((signed __int64)((unsigned __int128)(1749024623285053783LL
             * (signed __int128)t) >> 64) >> 11) - (t >> 63));
    

    {% endtab %} {% endtabs %}

    More aggressive ‘if’ to ‘boolean’ folding

    More aggressive folding of if_one_else_zero constructs; the output is much shorter and easier to grasp.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    return a1 << 28 != 0 && (a1 & (unsigned __int8)(a1 - 1)) == 0;
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

      v1 = 1;
      v2 = 1;
      if ( !(a1 << 28) )
        v2 = 0;
      if ( !((unsigned __int8)a1 & (unsigned __int8)(a1 - 1)) )
        v1 = 0;
      return v2 && !v1;
    

    {% endtab %} {% endtabs %}

    Better type of ‘this’ argument

    The decompiler tries to guess the type of the first argument of a constructor. This leads to improved listing.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    XImage *__fastcall XImage::setHotSpot(XImage *this, int a2, int a3)
    {
      LOWORD(this->height) = a2;
      HIWORD(this->height) = a3;
      return this;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    int __fastcall XImage::setHotSpot(int this, int a2, int a3)
    {
      *(_WORD *)(this + 4) = a2;
      *(_WORD *)(this + 6) = a3;
      return this;
    }
    

    {% endtab %} {% endtabs %}

    Improved union field selection

    The decompiler has a better algorithm to find the correct union field. This reduces the number of casts in the output.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    float __fastcall ret4f(__n128 a1)
    {
      return a1.n128_f32[2];
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    float __fastcall ret4f(__n128 a1)
    {
      return *(float *)&a1.n128_u32[2];
    }
    

    {% endtab %} {% endtabs %}

    Improved recognition of ‘for’ loops

    We improved recognition of ‘for’ loops, they are shorter and much easier to understand.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

      for ( i = 0; i < 16; ++i )
      {
        printf("%x", *(unsigned __int8 *)(i + v2) >> 4);
        printf("%x", *(_BYTE *)(i + v2) & 0xF);
      }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    v3 = 0;
    do
    {
      printf("%x", (unsigned int)*(unsigned __int8 *)(v3 + v2) >> 4);
      printf("%x", *(_BYTE *)(v3++ + v2) & 0xF);
    }
    while ( v3 < 16 );
    

    {% endtab %} {% endtabs %}

    Added support for shifted pointers

    Please note that the code on the left is completely illegible; the assembler code is probably easier to work with in this case.
    However, the code on the right is very neat.
    JFYI, below is the class hierarchy for this example:

    struct __cppobj B1
    {
      B1_vtbl *__vftable /*VFT*/;
      char d1[4];
    };
    struct __cppobj B2
    {
      B2_vtbl *__vftable /*VFT*/;
      char d2[4];
    };
    struct __cppobj A : B1, B2
    {
      char d3[4];
    };
      
    

    Also please note that the source code had

    A::a2(A *this)
    

    but at the assembler level we have

    A::a2(B2 *this)
    

    Visual Studio plays such tricks.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    int __thiscall A::a2(B2 *__shifted(A,8) this)
    {
      printf("A::a2 %p\n", ADJ(this));
      printf("A::d2 %p\n", ADJ(this)->d2);
      return ADJ(this)->d3[0];
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    int __thiscall A::a2(B2 *this)
    {
      B2 *v1; // ST08_4
    
      v1 = this;
      printf("A::a2 %p\n", this - 1);
      printf("A::d2 %p\n", (char *)v1 + 4);
      return *((char *)v1 + 8);
    }
    

    {% endtab %} {% endtabs %}

    Better recognition of inlined standard functions

    Yes, the code on the left and on the right do the same. We prefer the right side, very much.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    if ( !memcmp(i + 10, "AMIBIOSC", 8u) )
          return i + 10;
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

        v2 = 0;
        v3 = 1;
        v4 = i + 10;
        v5 = "AMIBIOSC";
        v6 = 8;
        do
        {
          if ( !v6 )
            break;
          v2 = *v4 < (const unsigned __int8)*v5;
          v3 = *v4++ == *v5++;
          --v6;
        }
        while ( v3 );
        if ( (!v2 && !v3) == v2 )
          return i + 10;
    
    

    {% endtab %} {% endtabs %}

    Improved application of pre-increment and pre-decrement

    Minor stuff, one would say, and we’d completely agree. However, these minor details make reading the output a pleasure.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

        v5 = *++v4;
        result = --a4;
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

        v5 = (v4++)[1];
        result = a4-- - 1;
    

    {% endtab %} {% endtabs %}

    Added support for RRX addressing mode in ARM

    This is a rare addressing mode that is nevertheless used by compilers. Now we support it nicely.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    __int64 __fastcall sar64(__int64 a1)
    {
      return a1 >> 1;
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    __int64 __fastcall sar64(__int64 a1)
    {
      __int64 result; // r0
    
      SHIDWORD(a1) >>= 1;
      __asm { MOV     R0, R0,RRX }
      return result;
    }
    

    {% endtab %} {% endtabs %}

    Improved constant propagation in global memory

    The new decompiler managed to disentangle the obfuscation code and convert it into a nice strcpy()

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    strcpy((char *)&dword_1005DF9A, "basic_string");
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

      dword_1005DF9A = 0xADB0A3A3;
      dword_1005DF9E = 0xBCB499A6;
      dword_1005DFA2 = 0xABA5A3BB;
      LOBYTE(dword_1005DF9A) = 'b';
      BYTE1(dword_1005DF9A) ^= 0xC2u;
      HIWORD(dword_1005DF9A) = 'is';
      LOBYTE(dword_1005DF9E) = 'c';
      BYTE1(dword_1005DF9E) ^= 0xC6u;
      HIWORD(dword_1005DF9E) = 'ts';
      LOBYTE(dword_1005DFA2) = 'r';
      BYTE1(dword_1005DFA2) ^= 0xCAu;
      HIWORD(dword_1005DFA2) = 'gn';
      byte_1005DFA6 = 0;
    

    {% endtab %} {% endtabs %}

    Added support for Objective C blocks

    The new version knows about ObjC blocks and can represent them correctly in the output. See Edit, Other, Objective-C submenu in IDA, it contains the necessary actions to analyze the blocks.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    __int64 __fastcall sub_181450634(__int64 a1, __int64 a2, __int64 a3)
    {
      Block_layout_18145064C blk; // [xsp+0h] [xbp-30h]
    
      blk.isa = _NSConcreteStackBlock;
      *(_QWORD *)&blk.flags = 0x42000000LL;
      blk.invoke = sub_181450694;
      blk.descriptor = (Block_descriptor_1 *)&unk_1B0668958;
      blk.lvar1 = *(_QWORD *)(a1 + 32);
      blk.lvar2 = a3;
      return sub_18144BD0C(a2, &blk);
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    __int64 __fastcall sub_181450634(__int64 a1, __int64 a2, __int64 a3)
    {
      void *(*v4)[32]; // [xsp+0h] [xbp-30h]
      __int64 v5; // [xsp+8h] [xbp-28h]
      __int64 (__fastcall *v6)(); // [xsp+10h] [xbp-20h]
      void *v7; // [xsp+18h] [xbp-18h]
      __int64 v8; // [xsp+20h] [xbp-10h]
      __int64 v9; // [xsp+28h] [xbp-8h]
    
      v4 = _NSConcreteStackBlock;
      v5 = 1107296256LL;
      v6 = sub_181450694;
      v7 = &unk_1B0668958;
      v8 = *(_QWORD *)(a1 + 32);
      v9 = a3;
      return sub_18144BD0C(a2, &v4);
    }
    

    {% endtab %} {% endtabs %}

    Improved recognition of 64-bit comparisons

    We continue to improve recognition of 64-bit arithmetics. While it is impossible to handle all cases, we do not give up.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

      gettimeofday(&tv, 0);
      v0 = 90 * (v3 / 1000 + 1000LL * *(_QWORD *)&tv);
      if ( v0 < 0xFFFFFFFFFFFFFFFFLL )
        stamp = 90 * (v3 / 1000 + 1000LL * *(_QWORD *)&tv);
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

      gettimeofday(&tv, 0);
      v0 = 1000LL * (unsigned int)tv.tv_usec;
      HIDWORD(v0) = (unsigned __int64)(1000LL * *(_QWORD *)&tv) >> 32;
      v1 = 90LL * (unsigned int)(v4 / 1000 + v0);
      HIDWORD(v1) = (unsigned __int64)(90 * (v4 / 1000 + v0)) >> 32;
      if ( HIDWORD(v1) < 0xFFFFFFFF || -1 == HIDWORD(v1) && (unsigned int)stamp > (unsigned int)v1 )
        stamp = v1;
    

    {% endtab %} {% endtabs %}

    Merged common code in ‘if’ branches

    Yet another optimization rule that lifts common code from ‘if’ branches. We made it even more aggressive.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

        mywcscpy();
        if ( a3 < 0 )
          v4 = -a3;
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

        if ( a3 >= 0 )
        {
          mywcscpy();
        }
        else
        {
          mywcscpy();
          v4 = -a3;
        }
    

    {% endtab %} {% endtabs %}

    Added forced stack variables

    Sometimes compilers reuse the same stack slot for different purposes. Many our users asked us to add a feature to handle this situation. The new decompiler addresses this issue by adding a command to force creation of a new variable at the specified point. Currently we support only aliasable stack variables because this is the most common case.

    In the sample above the slot of the p_data_format variable is reused. Initially it holds a pointer to an integer (data_format) and then it holds a simple integer (errcode). Previous versions of the decompiler could not handle this situation nicely and the output would necessarily have casts and quite difficult to read. The two different uses of the slot would be represented just by one variable. You can see it in the left listing.

    The new version produces clean code and displays two variables. Naturally it happens after applying the force new variable command.

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

        data_format = *p_data_format;
        if ( *p_data_format < 0 || data_format > 13 )
        {
          errcode = 2;
          SetError(&this->status, &errcode, "format not one of accepted types");
        }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

        data_format = *p_data_format;
        if ( *p_data_format < 0 || data_format > 13 )
        {
          p_data_format = (int *)2;
          SetError(&this->status, (errcode_t *)&p_data_format, "format not one of accepted types");
        }
    

    {% endtab %} {% endtabs %}

    Added support for virtual calls

    Well, these listings require no comments, the new version apparently wins!

    {% tabs %} {% tab title=“PSEUDOCODE V7.2” %}

    void __cdecl test3(D7 *a1)
    {
      a1->f1(&a1->A1);
      a1->f2(&a1->D3);
      a1->f3(&a1->D5);
      a1->f4(&a1->A4);
      a1->f5(a1);
      a1->f6(a1);
      a1->g0(&a1->D5);
      a1->g5(&a1->D5);
      a1->g7(a1);
      if ( a1 )
        a1->~D7(a1);
    }
    

    {% endtab %}

    {% tab title=“PSEUDOCODE V7.1” %}

    void __cdecl test3(D7 *a1)
    {
      (**((void (__cdecl ***)(char *))a1 + 12))((char *)a1 + 48);
      (*(void (__cdecl **)(char *))(*((_DWORD *)a1 + 10) + 12))((char *)a1 + 40);
      (**((void (__cdecl ***)(char *))a1 + 6))((char *)a1 + 24);
      (**((void (__cdecl ***)(char *))a1 + 26))((char *)a1 + 104);
      (**(void (__cdecl ***)(D7 *))a1)(a1);
      (*(void (__cdecl **)(D7 *))(*(_DWORD *)a1 + 12))(a1);
      (*(void (__cdecl **)(char *))(*((_DWORD *)a1 + 6) + 4))((char *)a1 + 24);
      (*(void (__cdecl **)(char *))(*((_DWORD *)a1 + 6) + 16))((char *)a1 + 24);
      (*(void (__cdecl **)(D7 *))(*(_DWORD *)a1 + 16))(a1);
      if ( a1 )
        (*(void (__cdecl **)(D7 *))(*(_DWORD *)a1 + 8))(a1);
    }
    
    

    {% endtab %} {% endtabs %}

    Interactive operation

    The decompiler adds the following commands to the menus:

    View, Open subviews, Pseudocode (hotkey F5)

    This command decompiles the current function. If the decompilation is successful, it opens a new window titled “Pseudocode” and places the generated C text in this window.

    The following commands can be used in the pseudocode window:

    If the current item is a local variable, additional items may appear in the context menu:

    If the current item is a union field, an additional item may appear in the context menu:

    If the current item is a parenthesis, bracket, or a curly brace, the following hotkey is available:

    The user can also select text and copy it to the clipboard with the Ctrl-C combination.

    If the current item is C statement keyword, an additional item may appear in the context menu:

    The user can also select text and copy it to the clipboard with the Ctrl-C combination.

    Pressing Enter on a function name will decompile it. Pressing Esc will return to the previously decompiled function. If there is no previously decompiled function, the pseudocode window will be closed.

    Ctrl-Enter or Ctrl-double click on a function name will open a new pseudocode window for it.

    Pressing F5 while staying in a pseudocode window will refresh its contents. Please note that the decompiler never refreshes pseudocode by itself because it can take really long.

    The user can use the mouse right click or keyboard hotkeys to access the commands. Please check the command descriptions for the details.

    Jump, Jump to pseudocode (hotkey Tab)

    This command toggles between the disassembly view and pseudocode view. If there is no pseudocode window, a new window will be created.

    Pressing Tab while staying in the pseudocode window will switch to the disassembly window. The Tab key can be used to toggle pseudocode and disassembly views.

    See above the Open pseudocode command for more details.

    File, Produce file, Create C file (hotkey Ctrl-F5)

    This command decompiles the selected functions or the whole application. It will ask for the name of the output .c file.

    If there is a selected area in the disassembly view, only the selected functions will be decompiled. Otherwise, the whole application will be decompiled.

    When the whole application is decompiled, the following rules apply:

    • the order of decompilation is determined by the decompiler. It will start with the leaf functions and will proceed in the postnumbering order in the call graph. This order makes sure that when we decompile a function, we will have all information about the called functions. Obviously, for recursive functions some information will be still missing.
    • the library (light blue) functions will not be decompiled. By the way, this is a handy feature to exclude functions from the output.
    • A decompilation failure will not stop the analysis but the internal errors will. The decompiler generates #error directives for failed functions.

    Edit, Comments, Add pseudocode comments

    This command decompiles the current function and copies the pseudocode to the disassembly listing in the form of anterior comments. If the current function already has a pseudocode window, its contents are used instead of decompiling the function anew.

    This menu item performs exactly the same actions as the Copy to assembly command.

    Edit, Comments, Delete pseudocode comments

    This command deletes all anterior comments created by the previous command. Its name is a slight misnomer because it does not verify the comment origin. In fact, all anterior comments within the current function are deleted.

    Edit, Other, Toggle skippable instructions

    This command marks/unmarks instructions to be skipped by the decompiler. It is useful if some prolog/epilog instructions were missed by IDA. If such instructions were not detected and marked, the decompilation may fail (most frequently the call analysis will fail).

    The decompiler skips the prolog, epilog, and switch instructions. It relies on IDA to mark these instructions. Sometimes IDA fails to mark them, and this command can be used to correct the situation.

    If the command is applied to marked instructions, it will unmark them.

    By default, the skipped instructions are not visualized. To make them visible, edit the IDA.CFG file and uncomment the following lines:

     PROLOG_COLOR = 0xE0E0E0            // grey
     EPILOG_COLOR = 0xE0FFE0            // light green
     SWITCH_COLOR = 0xE0E0FF            // pink
    

    Edit, Other, Reset decompiler information

    This command deletes decompiler information.

    It can delete information about global objects (functions, static data, structure/enum types) and/or information local to the current function.

    Use this command if you inadvertently made some change that made decompilation impossible.

    It can also be used to reset other information types used by the decompiler. For example, the forced variadic arguments or split expression can be reset.

    Edit, Other, Decompile as call

    This commands configures a function call the current instruction should be replaced by in the pseudocode output.

    Special names can be used to access operands of the current instructions: __OP1, __OP2, … for first, second, etc. operands. Each function argument having a name like that will be replaced in the call by the value of the corresponding operand of the instruction. Also if the function name has this format, a call to the location pointed by the corresponding operand will be generated. Other arguments and the return value will be placed into locations derived from the function prototype according to the current compiler, calling convention, argument and return types. You can use IDA-specific __usercall calling convention to specify arbitrary locations independently of platform and argument/return types (read IDA help pages about the user defined calling conventions for more info).

    Examples

    • We could ask to replace the following instruction:
      out 2b, ax
      by specifying the following prototype:
      void OUT(unsigned int8 __OP1, int16 __OP2)
      which would lead to the following decompiler output:
      OUT(0x2b, v1);
      where v1 is mapped to ax.
    • The following prototype: int __usercall syscall@<R0;>(int code@<R12;>, void *a1@<R0;>, void *a2@<R1;>)
      applied to the second instruction in the following piece of code:
      mov r12, #0x148
      svc 0x801
      will generate the following pseudocode:
      v3 = syscall(328, v1, v2);
      where v1, v2, v3 are mapped to R0, R1, R2 respectively.

    Help, Send database

    This command packs and sends the current database to our server. The user can specify his/her email and add notes about the error. This is the preferred way of filing bugreports because it is virtually impossible to do anything without a database. The database will also contain the internal state of the decompiler, which is necessary to reproduce the bug.

    The database is sent in the compressed form to save the bandwidth. An encrypted connection (SSL) is used for the transfer.

    Help, Extract function

    This command deletes all code and data from the current idb extract the current function. It can be used to reduce the database size before sending a bug report. Please note that deleting information from the database may make the bug irreproducible, so please verify it after applying this command.

    Rename

    Hotkey: N

    The rename command renames the current item. It can be applied to the following things:

    • Function
    • Local variable
    • Global item (function or data)
    • Structure field
    • Statement label

    Normally the item under the cursor will be renamed. If the command is applied to the very first line of the output text and the decompiler cannot determine the item under the cursor, the current function will be renamed.

    See also: interactive operation

    Set type

    Hotkey: Y

    The SetType command sets the type of the current item. It can be applied to the following things:

    • Function
    • Local variable
    • Global item (function or data)

    If the command is applied to the very first line of the output text, the decompiler will try to detect the current function argument. If the cursor is on an argument declaration, then the argument type will be modified. Otherwise, the current function type will be modified.

    In all other cases the item under the cursor will be modified.

    When modifying the prototype of the current function you may add or remove function arguments, change the return type, and change the calling convention. If you see that the decompiler wrongly created too many function arguments, you can remove them.

    The item type must be specified as a C type declaration. All types defined in the loaded type libraries, all structures in the local types window, all enum definitions in the local types window can be used.

    This is a very powerful command. It can change the output dramatically. Use it to remove cast operations from the output and to make it more readable. In some cases, you will need to define structure types in the local types window and only after that use them in the pseudocode window.

    NOTE: since the arguments of indirect calls are collected before defining variables, specifying the type of the function pointer may not be enough. Please read this for more info.

    Since variables and function types are essential, the decompiler uses colors to display them. By default, definite types (set by the user, for example) are displayed in blue while guessed types are displayed in gray. Please note that the guessed types may change if the circumstances change. For example, if the prototype of a called function is changed, the variable that holds its return value may change automatically, unless its type was set by the user.

    This command does not rename the operated item, even if you specify the name in the declaration. Please use the rename command for that.

    See also: interactive operation

    Set number representation

    Hotkeys:

    • H - toggle between hexadecimal and decimal representations
    • R - switch to character constant representation
    • M - switch to enumeration (symbolic constant) representation
    • _ - invert sign
    • T - apply struct offset

    This command allows the user to specify the desired form of a numeric constant. Please note that some constants have a fixed form and cannot be modified. This mainly includes constants generated by the decompiler on the fly.

    The decompiler ties the number format information to the instruction that generated the constant. The instruction address and the operand number are used for that. If a constant, which was generated by a single instruction, is used in many different locations in the pseudocode, all these locations will be modified at once.

    Using the ‘invert sign’ negates the constant and resets the enum/char flag if it was set.

    When this command is applied the first time to a negative constant, the output will seemingly stay the same. However, the list of symbolic constants available to the M hotkey changes. For example, if the constant is ‘-2’, then before inverting the sign the symbolic constants corresponding to ‘-2’ are available. After inverting the sign the symbolic constants corresponding to ‘2’ are available.

    The T hotkey applies the structure offset to the number. For positive numbers, it usually converts the number into offsetof() macro. For negative numbers, it usually converts the whole (var-num) expression into the CONTAINING_RECORD macro. By the way, the decompiler tries to use other hints to detect this macro. It checks if the number corresponds to a structure offset in the disassembly listing. For example, an expression like

            v1 = (structype *)((char *)v2 - num);
    

    can be converted into

            v1 = CONTAINING_RECORD(v2, structype, fieldname);
    

    where structype * is the type of v1 and offsetof(structype, fieldname) == num. Please note that v2 must be declared as a pointer to the corresponding structure field, otherwise the conversion may fail.

    See also:

    Edit indented comment

    Hotkey: /

    This command edits the indented comment for the current line or the current variable. It can be applied to the local variable definition area (at the top of the output) and to the function statement area (at the bottom of the output).

    If applied to the local variable definition area, this command edits the comment for the current local variable. Otherwise the comment for the current line will be edited.

    Please note that due to the highly dynamic nature of the output, the decompiler uses a rather complex coordinate system to attach comments. Some output lines will not have a coordinate in this system. You cannot edit comments for these lines. We will try to overcome this limitation in the future but it might take some time and currently we do not have a clear idea how to improve the existing coordinate system.

    Each time the output text changes the decompiler will rearrange the entered comments so they are displayed close to their original locations. However, if the output changes too much, the decompiler could fail to display some comments. Such comments are called “orphan comments”. All orphan comments are printed at the very end of the output text.

    You can cut and paste them to the correct locations or you can delete them with the “Delete orphan comments” command using the right-click menu.

    The starting line position for indented comments can be configured by the user. Please check the COMMENT_INDENT parameter in the configuration file.

    See also: Edit block comment | Interactive operation

    Edit block comment

    Hotkey: Ins

    This command edits the block comment for the current line. The entered comment will be displayed before the current line.

    Please note that due to the highly dynamic nature of the output, the decompiler uses a rather complex coordinate system to attach comments. Some output lines will not have a coordinate in this system. You cannot edit comments for these lines. Also, some lines have the same coordinate. In this case, the comment will be attached to the first line with the internal coordinate. We will try to overcome this limitation in the future but it might take some time and currently we do not have a clear idea how to improve the existing coordinate system.

    Each time the output text changes the decompiler will rearrange the entered comments so they are displayed close to their original locations. However, if the output changes too much, the decompiler could fail to display some comments. Such comments are called “orphan comments”. All orphan comments are printed at the very end of the output text.

    If applied to the function declaration line, this command edits the function comment. This comment is shared with IDA: it is the same as the function comment in IDA.

    You can cut and paste them to the correct locations or you can delete them with the “Delete orphan comments” command using the right-click menu.

    See also: Edit indented comment | Interactive operation

    Hide/unhide C statements

    Hotkeys

    Keypad -

    Hide current statement

    Keypad +

    Unhide current statement

    This command collapses the current statement into one line. It can be applied to multiline statements (if, while, for, do, switch, blocks).

    The hidden item can be uncollapsed using the unhide command.

    See also: interactive operation

    Split/unsplit expression

    Hotkeys

    None

    Split current expression

    None

    Unsplit current expression

    This command splits the current expression into multiple expressions. It is available only for int16, int32, or int64 assignments or expressions which were combiled by the decompiler (e.g. 64bit comparison on 32bit platform). Splitting an assignment breaks it into two assignments: one for the low part and one for the high part. Other expressions can be splitted into more than two expressions.

    This command is useful if the decompiler erroneously combines multiple unrelated expressions into one. In some cases the types of the new variables should be explicitly specified to get a nice listing. For example:

            __int64 v0;
            v0 = 0ui64;
    

    can be split into two assignments:

            __int32 v0;
            __int32 v1;
            v0 = 0;
            v1 = 0;
    

    by right clicking on the 64-bit assignment operation (the ‘=’ sign) and selecting the ‘Split’ command.

    The split expression can be unsplit using the unsplit command. Unsplitting removes all effects of the previous Split commands.

    See also: interactive operation

    Force call type

    In some cases, especially for indirect calls, the decompiler cannot correctly detect call arguments. For a call like

            push something
            mov  eax, [ecx]
            call [eax+8]
    

    it is very difficult to determine where are the input arguments. For example, it is unclear if ECX is used by the call or not.

    However, the number of arguments and their types can become available at later stages of decompilation. For example, the decompiler may determine that ECX points to a class with a table of virtual functions. If the user specifies the vtable layout, the output may become similar to

            ((int (*__stdcall)(DWORD))ptr-vftable-somefunc)(v1);
    

    If the user declares somefunc as a pointer to a function like this:

            int __thiscall (*somefunc)(myclass *obj, int arg);
    

    then the code is incorrect. The decompiler detected only one argument and missed the one in ECX.

    The ‘force call type’ command instructs the decompiler not to perform the call argument analysis but just use the type of the call object. For the above example, the call will be transformed into something like

            ptr-vftable-somefunc(obj, v1);  // obj is in ECX
    

    In other words, this command copies the call type from the call object to the call instruction. The call object may be any expression, the only requirement is that it must be a pointer to a function.

    There is a more general command Set call type that allows the user to set any type for a call instruction.

    NOTE: Behind the scenes the ‘force call’ command copies the desired type to the operand of the call instruction. To revert the effects of ‘force call’ or to fine tune the forced type please use the Edit, Operand type, Set operand type in the disassembly view while staying on the call instruction.

    See also: interactive operation

    Set call type

    In some cases, especially for indirect calls, the decompiler cannot correctly detect call arguments. The ‘Set call type’ command sets the type of the function call at the current item without changing the prototype of the called function itself. So there is a difference between ‘Set call type’ and Set type commands. Let us assume that there is a call

            v1 = off_5C6E4(a1);
    

    and that the decompiler erroneously detected one argument whereas four arguments actually are present. If the user sets the new call type as

            int (*)(int, int, int, int)
    

    then the call will be transformed into

            v1 = ((int (__cdecl *)(int, int, int, int))off_5C6E4)(a1, a2, a3, a4);
    

    and the type of off_5C6E4 will remain unchanged. Note that in this case the user can revert the call to the previous state using the Force call type command.

    The Set type command will have a different effect:

            v1 = off_5C6E4(a1, a2, a3, a4);
    

    It sets the new type for off_5C6E4 that will cause changes to all places where off_5C6E4 is called, including the current call.

    This command also can be used to specify the __noreturn attribute of a call.

    NOTE: Behind the scenes the ‘Set call type’ command, like Force call type, copies the entered type to the operand of the call instruction. Actually it is a shortcut to Edit, Operand type, Set operand type in the disassembly view while staying on the call instruction.

    See also: interactive operation

    Add/del variadic arguments

    Hotkeys

    Numpad+

    Add variadic argument

    Numpad-

    Delete variadic argument

    This command adds or removes an argument of a variadic call. It is impossible to detect the correct number of variadic arguments in all cases, and this command can be used to fix wrongly detected arguments. It is available only when the cursor is located on a call to a variadic function (like printf). The decompiler automatically detects the argument locations, the user can only increase or decrease their number.

    This command is useful if the decompiler determines the number of arguments incorrectly. For example:

            printf("This is a test call: %d\n");
    

    apparently lacks an argument. Pressing Numpad+ modifies it:

            printf("This is a test call: %d\n", v1);
    

    If too many arguments are added to a variadic call, decompilation may fail. Three methods to correct this situation exist:

    See also: interactive operation

    Del function argument

    Hotkey: Shift-Del

    This command removes an argument or the return type from a function prototype. It can be applied to the prototype of the current function as well as to any called function.

    It is available only when the cursor is on a function argument or on the return type. As a result of this command, the function prototype is modified: the selected argument is removed from the argument list. If necessary, the calling convention is replaced by a new one.

    Please note that other register arguments do not change their locations. This logic ensures that a stray argument in the argument list can be deleted with a keypress.

    When applied to the function return type it will convert it to “void”.

    This command is available starting from v7.5.

    See also: interactive operation, Add/delete function return type.

    Add/delete function return type

    Hotkey: Ctrl-Shift-R

    This command removes the return type from the function prototype. It is applied to the prototype of the current function.

    It is available anywhere in the pseudocode window, regardless where exactly the cursor is positioned. This command is not visible in the context sensitive popup menu.

    If applied to a function without the return type, it will add the previously removed return type to the function prototype.

    This command is available starting from v7.5.

    See also: interactive operation, Del function argument.

    Jump to cross reference

    This command opens the standard dialog box with the cross references to the current item. The user may select a cross reference and jump to it. If the cross-reference address belongs to a function, it will be decompiled. Otherwise, IDA will switch to the disassembly view.

    For local variables, the following cross reference types are defined:

      r  Read
      w  Write
      rw Read/Write
      o  Reference
    

    It is also possible to jump to structure fields. All local references to a field of a structure type will be displayed.

    If the item under the cursor is a label, a list of all references to the label will be displayed.

    Finally, xrefs to statment types are possible too. For example, a list of all return statements of the current function can be obtained by pressing X on a return statment. All statements with keywords are supported.

    See also: interactive operation

    Jump to cross reference globally

    This command decompiles all non-trivial functions in the database and looks for xrefs in them. Library and thunk functions are skipped. The decompilation results are cached in memory, so only the first invocation of this command is slow.

    Cross references to the current item are looked up in the decompilation results. A list of such xrefs is formed and displayed on the screen. Currently the following item types are supported:

    • a structure field
    • a enumeration member (symbolic constant)

    This action is also available (only by hotkey) in the local types view.

    See also: interactive operation

    Generate HTML file

    This command generates an HTML file with the pseudocode of the current function. It is available from the popup menu if the mouse is clicked on the very first line of the pseudocode text.

    This command also works on the selected area. The user can select the area that will be saved into HTML file. This is useful if only a small code snippet is needed to be saved instead of the entire function body.

    See also: interactive operation

    Mark/unmark as decompiled

    This command marks the current function as decompiled. It is a convenient way to track decompiled functions. Feel free to use it any way you want.

    Marking a function as decompiled will change its background color to the value specified by the MARK_BGCOLOR parameter in the configuration file. The background color will be used in the pseudocode window, in the disassembly listing, and in the function list.

    See also: interactive operation

    Copy to assembly

    This command copies the pseudocode text to the disassembly window. It is available from the popup right-click menu.

    Please note that only “meaningful” lines are copied. Lines containing curly braces, else/do keywords will be omitted.

    The copied text is represented as anterior comments in the disassembly. Feel free edit them the way you want. The copied text is static and will not change if the pseudocode text changes.

    See also: interactive operation

    Show/hide casts

    Hotkey: \

    This command hides all cast operators from the output listing. Please note that the output may become more difficult to understand or even lose its meaning without cast operators. However, since in some cases it is desirable to temporarily hide them, we provide the end user with this command.

    The initial display of cast operators can be configured by the user. Please check the HO_DISPLAY_CASTS bit in the HEXOPTIONS parameter in the configuration file.

    See also: interactive operation

    Reset pointer type

    Hotkey: none

    This command resets the type of the current local variable from a pointer type to an integer type. This is just a convenience command. Please use the set type command in order to specify arbitrary variable types.

    See also: interactive operation

    Convert to struct *

    Hotkey: none

    This convenience command allows the user to specify a pointer to structure type in a quick and efficient manner. The list of the local structure types will be displayed. The type of the current variable will be set as a pointer to the selected structure type.

    This is just a convenience command. Please use the set type command in order to specify arbitrary variable types.

    This command is available only when the decompiler is used with recent IDA versions.

    See also: interactive operation

    Create new struct type

    Hotkey: none

    This convenience command allows the user to convert the current local variable from a non-pointer type to a pointer to a newly created structure type. It is available from the context menu if the current variable is used a pointer in the pseudocode.

    The decompiler scans the pseudocode for all references to the variable and tries to deduce the type of the pointed object. Then the deduced type is displayed on the screen and the user may modify it to his taste before accepting it. When the user clicks OK, the new type is created and the type of the variable is set as a pointer to the newly created type.

    In simple cases (for example, when the variable is used as a simple character pointer), the decompiler does not display any dialog box but directly changes the variable type. In such cases, no new type will be created.

    This is just a convenience command. Please use the set type command in order to specify arbitrary variable types.

    This command is available only when the decompiler is used with recent IDA versions.

    See also: interactive operation

    Split variable

    Hotkey: Shift-S

    Sometimes a stack slot is used for two completely different purposes during the lifetime of a function. While for the unaliased part of the stack frame the decompiler can usually sort things out, it cannot do much for the aliased part of the stack frame. For the aliased part, it will create just one variable even if the corresponding stack slot is used for multiple different purposes. It happens so because the decompiler cannot prove that the variable is used for a different purpose, starting from a certain point.

    The split variable command is designed to solve exactly this problem.

    This command allows the user to force the decompiler to allocate a new variable starting from the current point. If the current expression is a local variable, all its subsequent occurrences will be replaced by a new variable up to the end of the function or the next split variable at the same stack slot. If the cursor does not point to a local variable, the decompiler will ask the user about the variable to replace.

    In the current statement, only the write accesses to the variable will be replaced. In the subsequent statements, all occurrences of the variable will be replaced. We need this logic to handle the following situation:

            func(var, &var);
    

    where only the second occurrence of the variable should be replaced. Please note that in some cases it makes sense to click on the beginning of the line with the function call, rather than on the variable itself.

    Please note that in the presence of loops in the control flow graph it is possible that even the occurrences before the current expression will be replaced by the new variable. If this is not desired, the user should split the variable somewhere else.

    The very first and the very last occurrences of a variable cannot be used to split the variable because it is not useful.

    The decompiler does not verify the validity of the new variable. A wrong variable allocation point may render the decompiler output incorrect.

    Currently, only aliasable stack variables can be split.

    A split variable can be deleted by right clicking on it and selecting ‘Unsplit variable’.

    See also: interactive operation

    Select union field

    Hotkey: Alt-Y

    This command allows the user to select the desired union field. In the presence of unions, the decompiler cannot always detect the correct union field.

    The decompiler tries to reuse the union selection information from the disassembly listing. If there is no information in the disassembly listing, the decompiler uses an heuristic rule to choose the most probable union field based on the field types. However, it may easily fail in the presence of multiple union fields with the same type or when there is no information how the union field is used.

    If both the above methods of selecting the union field fail, then this command can be used to specify the desired field. It is especially useful for analyzing device drivers (I/O request packets are represented with a long union), or COM+ code that uses VARIANT data types.

    See also: interactive operation

    Jump to paired paren

    This command jumps to the matching parenthesis. It is available only when the cursor is positioned on a parenthesis, bracket, or curly brace.

    The default hotkey is ‘%’.

    See also: interactive operation

    Collapse/uncollapse item

    This command collapses the selected multiline C statement into one line. It can be applied to if, while, for, switch, do keywords. The collapsed item will be replaced by its keyword and “…”

    It can also be applied to the local variable declarations. This can be useful if there are too many variables and they make the output too long. All variable declarations will be replaced by just one line:

            // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
    

    See also: interactive operation

    Map to another variable

    Hotkey: =

    This command allows the user to replace all occurrences of a variable by another variable. The decompiler will propose a list of variables that may replace the current variable. The list will include all variables that have exactly the same type as the current variable. Variables that are assigned to/from the current variable will be included too.

    Please note that the decompiler does not verify the mapping. A wrong mapping may render the decompiler output incorrect.

    The function arguments and the return value cannot be mapped to other variables. However, other variable can be mapped to them.

    A mapping can be undone by right clicking on the target variable and using the ‘unmap variable’ command.

    See also: interactive operation

    Hex-Rays interactive operation: Show all call decompilations

    Hotkey: none

    This command will appear on the right-click menu when the cursor is over a direct call, or when the cursor is over the function’s prototype. When selected, it will prompt the user whether they would like to decompile all functions that call the highlighted function. If the user selects “Yes”, Hex-Rays will decompile those functions, extract the decompilation for all calls to that location, and show the results in a new window. The user can navigate through this window by double-clicking (or pressing Enter) on any of the lines.

    This command is available starting from v9.2.

    See also: interactive operation, show all xref decompilations.

    Hex-Rays interactive operation: Show all xref decompilations

    Hotkey: none

    This command will appear on the right-click menu when the cursor is over a global data item. (If the cursor is over a direct call, Show all call decompilations will appear instead.)

    When selected, it will prompt the user whether they would like to decompile all functions that reference the highlighted global variable. If the user selects “Yes”, Hex-Rays will decompile those functions, extract the decompilation nearby the reference to that global variable, and show the results in a new window. The user can navigate through this window by double-clicking (or pressing Enter) on any of the lines.

    The following cross reference types are defined:

      r  Read
      w  Write
      rw Read/Write
      o  Reference
    

    This command is available starting from v9.2.

    See also: interactive operation, show all call decompilations.

    Batch operation

    The decompiler supports the batch mode operation with the text and GUI versions of IDA. All you need is to specify the -Ohexrays switch in the command line. The format of this switch is:

    -Ohexrays:-option1:-option2...:outfile:func1:func2\...
    

    The valid options are:

    • -new decompile only if output file does not exist
    • -nosave do not save the database (idb) file after decompilation
    • -errs send problematic databases to hex-rays.com
    • -lumina use Lumina server
    • [email protected] your email (meaningful if -errs option is used)

    The output file name can be prepended with + to append to it. If the specified file extension is invalid, .c will be used.

    The functions to decompile can be specified by their addresses or names. The ALL keyword means all non-library non-trivial functions. For example:

    idat -Ohexrays:-errs:[email protected]:outfile:ALL -A input
    

    will decompile all nonlibrary non-trivial (having more than one instruction) functions to outfile.c. In the case of an error, the .idb file will be sent to hex-rays.com. The -A switch is necessary to avoid the initial dialog boxes.

    Configuration

    The decompiler has a configuration file. It is installed into the ‘cfg’ subdirectory of the IDA installation. The configuration file is named ‘hexrays.cfg’. It is a simple text file, which can be edited to your taste. Currently the following keywords are defined:

    LOCTYPE_BGCOLOR

    Background color of local type declarations. Currently this color is not used.
    Default: default background of the disassembly view

    VARDECL_BGCOLOR

    Background color of local variable declarations. It is specified as a hexadecimal number 0xBBGGRR where BB is the blue component, GG is the green component, and RR is the red component. Color -1 means the default background color (usually white).
    Default: default background of the disassembly view

    FUNCBODY_BGCOLOR

    Background color of the function body. It is specified the same way as VARDECL_BGCOLOR.
    Default: default background of the disassembly view

    MARK_BGCOLOR

    Background color of the function if it is marked as decompiled. It is specified the same way as VARDECL_BGCOLOR.
    Default: very light green

    BLOCK_INDENT

    Number of spaces to use for block indentations.
    Default: 2

    COMMENT_INDENT

    The position to start indented comments.
    Default: 48

    RIGHT_MARGIN

    As soon as the line length approaches this value, the decompiler will try to split it. However, it some cases the line may be longer.
    Default: 120

    MAX_NCOMMAS

    In order to keep the expressions relatively simple, the decompiler limits the number of comma operators in an expression. If there are too many of them, the decompiler will add a goto statement and replace the expression with a block statement. For example, instead of

       if ( cond || (x=*p,y=func(),x+y0) )
         body;
    

    we may end up with:

       if ( cond )
         goto LABEL;
       x = *p;
       y = func();
       if ( x + y  0 )
     LABEL:
         body;
    


    Default: 8

    DEFAULT_RADIX

    Specifies the default radix for numeric constants. Possible values: 0, 10, 16. Zero means “decimal for signed, hex for unsigned”.
    Default: 0

    MAX_FUNCSIZE

    Specifies the maximal decompilable function size, in KBs. Only reachable basic blocks are taken into consideration.
    Default: 64

    OPT_VALRNG_SWITCH_NCASES

    This option controls the ARM decompiler’s switch statement optimization that eliminates unreachable cases from the decompiler output. The value specifies the maximum number of cases a switch statement can have before this optimization is skipped. To disable this optimization entirely, set it to 0.

    Default: 32

    HEXOPTIONS

    Combination of various analysis and display options:

    HO_JUMPOUT_HELPERS

    If enabled, the decompiler will handle out-of-function jumps by generating a call to the JUMPOUT() function. If disables, such functions will not be decompiled.
    Default: enabled

    HO_DISPLAY_CASTS

    If enabled, the decompiler will display cast operators in the output listing.
    Default: enabled

    HO_HIDE_UNORDERED

    If enabled, the decompiler will hide unordered floating point comparisons. If this option is turned off, unordered comparisons will be displayed as calls to a helper function: __UNORDERED__(a, b)
    Default: enabled

    HO_SSE_INTRINSICS

    If enabled, the decompiler will generate intrinsic functions for SSE instructions that use XMM/MMX registers. If this option is turned off, these instructions will be displayed using inline assembly.
    Default: enabled

    HO_IGNORE_OVERLAPS

    If enabled, the decompiler will produce output even if the local variable allocation has failed. In this case the output may be wrong and will contain some overlapped variables.
    Default: enabled

    HO_FAST_STRUCTURAL

    If enabled, fast structural analysis will be used. It generates less number of nested if-statements but may occasionally produce some unnecessary gotos. It is much faster on huge functions.

    HO_CONST_STRINGS

    Only print string literals if they reside in read-only memory (e.g. .rodata segment). When off, all strings are printed as literals. You can override decompiler’s decision by adding ‘const’ or ‘volatile’ to the string variable’s type declaration.

    HO_SIGNBIT_CHECKS

    Convert signed comparisons of unsigned variables with zero into bit checks.
    Before:

       (signed int)x < 0
    

    After:

       (x & 0x80000000) != 0
    

    For signed variables, perform the opposite conversion.

    HO_UNMERGE_TAILS

    Reverse effects of branch tail optimizations: reduce number of gotos by duplicating code

    HO_KEEP_CURLIES

    Keep curly braces for single-statement blocks

    HO_DEL_ADDR_CMPS

    Optimize away address comparisons.
    Example:

       &a < &b
     
    

    will be replaced by 0 or 1.
    This optimization works only for non-relocatable files.

    HO_SHOW_CSTR_CASTS

    Print casts from string literals to pointers to char/uchar. For example:

       (unsigned __int8 *)"Hello"
      
    

    HO_ESC_CLOSES_VIEW

    Pressing Esc closes the pseudocode view

    HO_SPOIL_FLAGREGS

    Assume all functions spoil flag registers ZF,CF,SF,OF,PF (including functions with explicitly specified spoiled lists)

    HO_KEEP_INDIRECT_READS**

    Keep all indirect memory reads (even with unused results) so as not to lose possible invalid address access

    HO_KEEP_EH_CODE

    Keep exception related code (e.g. calls to _Unwind_SjLj_Register)

    HO_SHOW_PAC_INSNS

    Translate ARMv8.3 Pointer Authentication instructions into intrinsic function calls (otherwise ignore all PAC instructions)

    HO_KEEP_POTENTIAL_DIV0

    Preserve potential divisions by zero (if not set, all unused divisions will be deleted)

    HO_MIPS_ADDSUB_TRAP

    Generate the integer overflow trap call for ‘add’, ‘sub’, ‘neg’ insns

    HO_MIPS_IGN_DIV0_TRAP

    Ignore the division by zero trap generated by the compiler (only for MIPS)

    HO_HONEST_READFLAGS

    Consider __readflags as depending on cpu flags default: off, because the result is correct but awfully unreadable

    HO_NON_FATAL_INTERR

    Permit decompilation after an internal error (normally the decompiler does not permit new decompilations after an internal error in the current session)

    HO_SINGLE_LINE_PROTO

    Never use multiline function declarations, even for functions with a long argument list

    HO_DECOMPILE_LIBFUNCS

    Decompile library functions too (in batch mode)

    HO_PROP_VOLATILE_LDX

    Propagate ldx instructions without checking for volatile memory access

    WARNINGS

    Specifies the warning messages that should be displayed after decompilation. Please refer to hexrays.cfg file for the details.
    Default: all warnings are on

    CMPFUNCS

    Specified list of function names that are considered “strcmp-like”. For them the decompiler will prefer to use comparison against zero like

        strcmp(a, b) == 0
                   
    

    as a condition. Underscores, j_ prefixes and _NN suffixes will be ignored when comparing function names

    MSVC Control Flow Guard names

    CFGUARD_CHECK

    Name of Control Flow Guard check function. Calls of this function will not be included into the pseudocode.
    Default: “guard_check_icall_fptr”

    CFGUARD_DISPATCH

    Name of Control Flow Guard dispatch function. Each call of this function will be replaced by ‘call rax’ instruction when generating pseudocode.
    Default: “guard_dispatch_icall_fptr”

    Third party plugins

    Below is the list of noteworthy public third-party plugins for the decompiler.

    • HexRaysCodeXplorer by Aleksandr Matrosov and Eugene Rodionov

      Hex-Rays Decompiler plugin for better code navigation Here is the features list for first release:

      • navigation through virtual function calls in Hex-Rays Decompiler window;
      • automatic type reconstruction for C++ constructor object;
      • useful interface for working with objects & classes;
    • List of IDA plugins

      A simple list of various IDA and Decompiler plugins

    • More to come…

    Happy analysis!

    Floating point support

    The x86 decompiler supports floating point instructions. While everything works automatically, the following points are worth noting:

    • The decompiler knows about all floating point types, including: float, double, long double, and _TBYTE (the extended floating format used by x86 FPU). We introduced _TBYTE because sizeof(long double) is often different from the size of _TBYTE. While sizeof(long double) can be configured in the compiler settings, the size of _TBYTE is always equal to 10 bytes.
    • The decompiler performs FPU stack analysis, which is similar to the simplex method performed by IDA. If it fails, the decompiler represents FPU instructions using inline assembler statements. In this case the decompiler adds one more prefix column to the disassembly listing, next to the stack pointer values. This column shows the calculated state of the FPU stack and may help to determine where exactly the FPU stack tracing went wrong.
    • Wrong prototypes of the called functions returning a value on the FPU stack may lead to a failure of the FPU stack analysis, leading to inline assembly as explain in the previous bullet point.
    • The decompiler ignores all manipulations with the floating point control word. In practice this means that it may miss an unusual rounding mode.
    • SSE floating point instructions are represented by intrinsic functions. Scalar SSE instructions are however directly mapped to floating point operations in pseudocode.
    • Casts from integers types to floating point types and vice versa are always displayed in the listing, even if the output has the same meaning without them.
    • Feel free to report all anomalies and problems with floating point support using the Send database command. This will help us to improve the decompiler and make it more robust. Thank you!

    See also: Failures and troubleshooting

    Support for intrinsic functions

    The current release of the decompiler supports instrinsic functions. The instructions that cannot be directly mapped to high level languages very often can be represented by special intrinsic functions. All Microsoft and Intel simple instrinsic functions up to SSE4a are supported, with some exceptions. While everything works automatically, the following points are worth noting:

    • SSE intrinsic functions require IDA v5.6 or higher. Older versions of IDA do not have the necessary functionality and register definitions.
    • Some intrinsic functions work with XMM constant values (16 bytes long). Modern compiler do not accept 16-byte constants yet but the decompiler may generate them when needed.
    • Sometimes it is better to represent SSE code using inline assembly rather than with intrinsic functions. If the decompiler detects SSE instructions in the current function, it adds a one more item to the popup menu. This item allows the user to enable or disable SSE intrinsic functions for the whole database. This setting is remembered in the database. It can also be modified in the configuration file for new databases.
    • The decompiler knows about all MMX/XMM built-in types. If the current database does not define these types, they are automatically added to the local types as soon as a SSE instruction is decompiled.
    • Scalar SSE instructions are never converted to intrinsic functions. Instead, they are directly mapped to floating point operations. This usually produces much better output, especially for Mac OS X binaries.
    • The scalar SSE instructions that cannot be mapped into simple floating point operations (like sqrtss) are mapped into simple functions from math.h.
    • The decompiler uses intrinsic function names as defined by Microsoft and Intel.
    • The decompiler does not track the state of the x87 and mmx registers. It is assumed that the compiler generated code correctly handles transitions between x87 and mmx registers.
    • Some intrinsic functions are not supported because of their prototype. For example, the __cpuid(int a[4], int b) function is not handled because it requires an array of 4 integers. We assume that most cpuid instructions will be used without any arrays, so adding such an intrinsic function will obscure things rather than to make the code more readable.
    • Feel free to report all anomalies and problems with intrinsic functions using the Send database command. This will help us to improve the decompiler and make it more robust. Thank you!

    See also: Failures and troubleshooting

    Overlapped variables

    In some cases the decompiler cannot produce nice output because the variable allocation fails. It happens because the input contains overlapped variables (or the decompiler mistakenly lumps together memory reads and writes). Overlapped variables are displayed in red so they conspicuously visible. Let us consider some typical situations.

    There are read/write accesses that involve two or more variables

    For example, consider the following output:

      __int64 v1; // qax@2 OVERLAPPED
      int v2; // ecx@2 OVERLAPPED
      __int64 result; // qax@4
    
      if ( *(_BYTE *)(a1 + 5) & 1 )
      {
        HIDWORD(v1) = *(_DWORD *)(a1 + 7);
        v2 = *(_DWORD *)(a1 + 11);
      }
      else
      {
        HIDWORD(v1) = 0;
        v2 = 0;
      }
      v1 = *(__int64 *)((char *)&v1 + 4); // ODD ASSIGNMENT!
    

    The last assignment to v1 reads beyond v1 boundaries. In fact, it also reads v2. See the assembly code:

    test    byte ptr [eax+5], 1
                     jz      short loc_409521
                     mov     edx, [eax+7]
                     mov     ecx, [eax+0Bh]
                     jmp     short loc_409525
    
    loc_409521:
                     xor     edx, edx
                     xor     ecx, ecx
    
    loc_409525:
                     mov     eax, edx
                     mov     edx, ecx
    

    Unfortunately, the decompiler cannot handle this case and reports overlapped variables.

    There is an array function argument

    Arrays cannot be passed to functions by value, so this will lead to a warning. Just get rid of such an array (embed it into a structure type, for example)

    There are too many function arguments

    The decompiler can handle up to 64 function arguments. It is very unlikely to encounter a function with a bigger number of arguments. If so, just embed some of them into a structure passed by value.

    The corrective actions include:

    • Check the stack variables and fix them if necessary. A wrongly variable can easily lead to a lvar allocation failure.
    • Define a big structure that covers the entire stack frame or part of it. Such a big variable will essentially turn off variables lumping (if you are familiar with compiler jargon, the decompiler builds a web of lvars during lvar allocation and some web elements become too big, this is why variable allocation fails). Instead, all references will be done using the structure fields.
    • Check the function argument area of the stack frame and fix any wrong variables. For example, this area should not containt any arrays (arrays cannot be passed by value in C). It is ok to pass structures by value, the decompiler accepts it.

    gooMBA


    description: Hands-Free Binary Deobfuscation with gooMBA

    gooMBA

    At Hex-Rays SA, we are constantly looking for ways to improve the usefulness of our state-of-the-art decompiler solution. We achieve this by monitoring for new trends in anti-reversing technology, keeping up with cutting-edge research, and brainstorming ways to innovate on existing solutions.

    Today we are excited to introduce a new Hex-Rays decompiler feature, gooMBA, which should greatly simplify the workflow of reverse-engineers working with obfuscated binaries, especially those using Mixed Boolean-Arithmetic (MBA) expressions. Our solution combines algebraic and program synthesis techniques with heuristics for best-in-class performance, integrates directly into the Hex-Rays decompiler, and provides a bridge to an SMT-solver to prove the correctness of simplifications.

    MBA Obfuscation Overview

    What Is MBA?

    A Mixed Boolean-Arithmetic (MBA) expression combines arithmetic (e.g. addition and multiplication) and boolean operations (e.g. bitwise OR, AND, XOR) into a single expression. These expressions are often made extremely complex in order to make it difficult for reverse-engineers to determine their true meaning.

    For instance, here is an example of an MBA obfuscation found in a decompilation listing. Note the combination of bitshift, addition, subtraction, multiplication, XOR, OR, and comparison operators within one expression.

    v1 = 715827883LL * (char)((((unsigned __int64)(-424194301LL * (a1 >> 4)) >> 35)+(-424194301LL * (a1 >> 4) < 0)) *  a1);
    v2 = (char)(((((((unsigned  __int64)(-424194301LL * (a1 >> 4)) >> 35) + (-424194301LL * (a1  >> 4) < 0)) * a1 - 48 * ((v1 >> 35) + (v1  < 0))) ^ 0x28) + 111) | 0x33);
    v3 = 818089009LL * (char)(((((((unsigned  __int64)(-424194301LL * (a1 >> 4)) >> 35) + (-424194301LL * (a1  >> 4) < 0)) * a1 - 48 * ((v1 >> 35) + (v1  < 0))) ^ 0x28) + 111) | 0x33);
    v4 = (4 * (v2 - 21 * ((v3 >> 34) + (v3  >> 63)))) & 0xF4 | 8;
    return (v4 - ((v4 / 0x81) & 0x7F | ((v4 /  0x81) << 7))) ^ 0xE;
    

    For reference, the above code always returns 0x89.

    MBA is also used as a name for a semantics-preserving obfuscation technique, which replaces simple expressions found in the source program with much more complicated MBA expressions. MBA obfuscation is called semantics-preserving since it only changes the syntax of the expression, not the underlying semantics — the input/output behavior of the expression should remain the same before and after.

    Why is MBA Reversing Difficult?

    A decompiler can be thought of as a massive simplification engine — it reduces the mental load of the reverse engineer by transforming a complex binary program into a vastly simplified higher-level readable format. It partially achieves this through equivalences, special pattern-matching rules derived from mathematical properties such as the commutativity, distributivity, and identity. For instance, the following simplification can be performed by applying the distributive property and identity property.

     2a + 3(a+0) = 5a
    

    Both boolean functions and arithmetic functions on integers are very well studied, and there is an abundance of simplification techniques and algorithms developed for each. MBA obfuscators exploit the fact that many of these equivalences and techniques break down when the two function types are combined. For instance, we all know that integer multiplication distributes over addition, but note that the same does not hold over the bitwise XOR:

     3·(2 ⊕ 1) = 3·3 = 9
    
     (3 ⊕ 2)·(3⊕1) = 1·2 = 2
    

    Advanced Computer Algebra Systems (CAS) such as Sage and Mathematica allow users to simplify arithmetic expressions, but their algorithms break down when we start introducing bitwise operations into our inputs.

    Furthermore, although Satisfiability Modulo Theories (SMT) solvers such as z3 do often support both arithmetic and boolean operations on computer integers, they do not perform simplification — at least not for any human definition of “simplicity.” Rather, their only goal is to prove or disprove the input formula; as a result, they are useful in proving a simplification correct, but not in deriving the simplification to begin with.

    MBA Obfuscation Techniques

    The core idea behind MBA obfuscation is that a complex, but semantically equivalent, MBA expression can be substituted for simpler expressions in the source program. For instance, one technique that can be used for MBA generation is the repeated application of simple MBA identities, such as:

    
    x+y=(x|y)+(x&y)
    
    x+y=2(x|y)-(x⊕y)
    
    x|y=(¬x|y)-¬x
    
    x-y=x+¬y+1
    

    Many of these identities are available in the classic book Hacker’s Delight, but there are an effectively unbounded number of them. For instance, Reichenwallner et al. easily generated 1,000 distinct MBA substitutions for x+y alone.

    There are also many more sophisticated techniques that can be used for MBA generation, such as applying invertible functions and point functions. The number of invertible functions in computer integers is similarly unbounded. By simply choosing and applying any invertible function followed by its inverse, then applying rewriting rules to mix up the order of operations, an MBA generator can create extremely complex expressions effortlessly.

    Effects of MBA Obfuscation

    Besides the obvious effect of making decompilation listings longer and more complex for humans to understand, there are a few other effects which this form of obfuscation can have on the binary analysis process.

    For instance, dataflow/taint analysis is a static analysis technique that can be used to automatically search for potentially exploitable parts of a program (such as an unsanitized dataflow from untrusted user input into a SQL query). MBA obfuscation can be used to complicate dataflow analysis, by introducing arbitrary unrelated variables into the MBA expression without modifying its semantics. It then becomes extremely difficult to deduce whether or not the newly introduced variable has an effect on the expression’s final value.

    An extreme example of this false dataflow technique is known as opaque predicates, whose original expressions have no semantic data inflows (i.e. they are constant). In other words, they always evaluate to a constant, regardless of their (potentially many) inputs. These opaque predicates can then be used for branching, creating false connections in the control-flow graph in addition to the dataflow graph.

    Prior Work

    Over the years, many algorithms have been developed to simplify MBA expressions. These include pattern matching, algebraic methods, program synthesis, and machine learning methods.

    Pattern Matching

    Since one of the core techniques involved in MBA generation is the application of rewrite rules, it seems natural to simply match and apply the same rewrite rules in the reverse direction. Indeed, this is precisely what earlier tools such as SSPAM did.

    There are several issues with pattern matching methods. Firstly, there are a massive number of possible rewrite rules, and proprietary binary obfuscators are unlikely to reveal what rules they use. In addition, at any given moment an expression might contain multiple subexpressions that each match a pattern, and the order in which we perform these simplifications matters! Performing one simplification might prevent a more optimal simplification from appearing down the line. If we were to attempt every possible ordering of optimizations, our search space quickly becomes exponential. As a result, we considered pure pattern-matching methods to be infeasible for our purposes of simplifying complex MBA expressions.

    Algebraic Methods

    Arybo is an example of an MBA simplifier that relies entirely on algebraic methods. It splits both inputs and outputs into their individual bits and simplifies each bit of the output individually. It’s clear that this method comes with some limitations. For a 64-bit expression, the program outputs 64 individual boolean functions, and it then becomes quite difficult for a human to combine these functions back into a single simplified expression. Notably, the built-in z3 bitvector simplifier also outputs a vector of boolean functions, since this representation is more useful for its main goal of proving whether or not a statement holds.

    Other algebraic algorithms for solving MBA expressions which do not split the expression into individual bits also exist. For instance, MBA-Blast and MBA-Solver use a transformation between n-bit MBA expressions and 1-bit boolean expressions. For linear MBAs (which we will describe in more detail later), this transformation is well-behaved, and a lookup table can trivially be used to simplify the corresponding boolean expression.

    SiMBA, another algorithm published by Denuvo researchers in 2022, uses a similar approach to MBA-Blast and MBA-Solver, but additionally makes the observation that the transformation to 1-bit boolean expressions is not necessary for correctness; rather, the authors prove that it is sufficient to simply limit the domains of all input variables to 0/1. As a result, their algorithm yields much better performance; however, it’s important to note that the algorithm still relies on the algebraic structure of linear MBA expressions, and as a result will not work on all MBA expressions found in the wild.

    Program Synthesis

    Program synthesis is the act of generating programs that provably fulfill some useful criteria. In the case of MBA-deobfuscation, our task is to generate simpler programs that are provably semantically equivalent to the provided obfuscated program. In short, two programs are considered semantically equivalent if they yield identical side effects and identical outputs on every possible set of inputs. For the MBA expressions we consider, the expressions have no side effects or branching, so we are just left with the requirement that the simplified expression must yield the same output for every possible set of inputs.

    One core observation made by synthesis-based tools such as Syntia, QSynthesis, and msynth is that for many real-world programs, the underlying semantics are relatively simple. After all, it is much more common to calculate the sum of two numbers x+y, than the result of say, 4529*(x>>(y^(11-~x))). Thus, for the most part, we only need to consider synthesizing relatively simple programs. To be clear, this is still a massive number of programs, but it at least makes the problem tractable.

    The main technique used by QSynth and msynth is an offline enumerate synthesis primitive guided by top-down breadth-first search. In simpler terms, these tools take advantage of precomputation, generating and storing a massive database of candidate expressions known as an oracle, searchable by their input/output behavior. Then, when asked to simplify a new expression, they analyze its input/output behavior and use it to perform a lookup in the oracle.

    Essentially, the input/output behavior of any expression is summarized by running the candidate expression with various inputs (some random, some specially chosen like 0 or 0xffffffff), collecting the resulting outputs, and hashing them into a single number. We refer to this number as a fingerprint, and the oracle can be thought of as a multimap from fingerprints to expressions. The simplification is then performed by calculating the fingerprint of the expression to be simplified, then looking up the fingerprint in the oracle for simpler equivalent expressions.

    Machine Learning

    Tools such as Syntia and NeuReduce use machine learning and reinforcement learning techniques to search for semantically equivalent expressions on the spot. However, we found that Syntia’s success rate was quite low — only around 15% on linear MBA expressions, and NeuReduce appeared to only have been evaluated on linear MBA expressions (on which it reported a 75% success rate), which are already solvable 100% of the time through algebraic approaches such as MBA-Blast and SiMBA.

    Goals for gooMBA

    When designing gooMBA, we had the following goals in mind:

    • Correctness — Obviously, a tool that outputs nonsense is useless, so we should strive to generate correct simplifications whenever feasible. When a true proof of correctness is infeasible, the tool should try to verify the results to a reasonable degree of certainty.
    • SpeedThe Hex-Rays decompiler is well-known in the industry for its speed. Likewise, the tool should strive for the highest performance possible. However, we are obviously willing to sacrifice a couple of seconds in machine-computation time if it means saving a human analyst hours of work.
    • Integration — The decompiler plugin should be able to optionally disappear into the background. Ideally, the user should be able to forget that they are even analyzing an obfuscated program and focus only on the work at hand.

    Our Approach

    Since there is no single way to generate MBA expressions, we decided to incorporate multiple deobfuscation algorithms into our final design and leave room for more in the future. Our tool, gooMBA, can be split into the following parts: microcode tree walking, simplification engine, SMT proofs of correctness, and heuristics.

    Below is a drawing of our overall approach:

    Since we found the SMT stage to be the most time-consuming, we run several hundred random test cases on candidate simplifications before attempting a proof.

    Microcode Tree Walking

    Before we can attempt simplification, we must first find potential MBA-obfuscated expressions in the binary. The Hex-Rays decompiler converts binaries into an intermediate form known as microcode, and continuously propagates variable values downward until a certain complexity limit is reached. Since MBA-expressions can be extremely complex (but notably, not so complex that they hinder performance), we increase the complexity limit when the MBA deobfuscator is invoked in order to maximize the complexity of expressions we can analyze. We then perform a simple tree-search through all expressions found in the program, starting with the most complex top-level expressions, and falling through to simpler subexpressions if they fail to simplify.

    Simplification Engine

    Our MBA simplification engine is split into three parts, each handling a subset of MBA expressions. We refer to these three parts as the Simple Linear Algorithm, Advanced Linear Algorithm, and the Synthesis Oracle Lookup.

    We can think of each one of these three parts as a self-contained module: the obfuscated expression goes in one end, and a set of candidate expressions (each simpler than the obfuscated expression) comes out of the other end. At this stage, these expressions are simply guesses, and may or may not be correct.

    One important thing to note is that all three of our subengines are considered black-box, i.e. they do not care about the syntactic characteristics of the expression being simplified, only its semantic properties — i.e. how the outputs change depending on the input values.

    Simple Linear Algorithm

    One of the fastest and easiest types of expressions we can simplify are those that reduce to a linear equation, i.e.

    Note that constants fall under this category as well. We can simplify these easily by emulating the expression we are trying to simplify, first using zeroes for every input variable. This would tell us the value of a0. We can then emulate the instruction once again, this time using zeroes for every input variable except x1. Combined with the previously found value, this tells us the value of a1. We can repeat the process until we’ve obtained all the necessary coefficients. Note that the algorithm can also efficiently detect when a variable needs to be zero- or sign- extended; we can simply try the value -1 for each variable and see which of the zero- or sign-extended versions of the linear equation matches the output value. It can be shown in this case that both checks will succeed if and only if both sign- and zero-extension are semantically acceptable.

    Advanced Linear Algorithm

    Reichenwallner et al. showed that there is also a fast algorithm, namely SiMBA, to simplify linear MBA expressions, defined as those which can be written as a linear combination of bitwise expressions, i.e.

    Where each ei(x1,...,xn)is a bitwise expression. For instance, 2*(x&y) is a linear MBA expression, but neither (x & 0x7) nor (x>>3) are linear MBA expressions, since neither (x & 0x7) nor (x >> 3) are bitwise or can be written as the linear combination of bitwise expressions.

    Essentially, the algorithm works by deriving an equivalent representation consisting of linear combinations of only bitwise conjunctions, e.g. 4 + 2*x + 3*x + 5*(x&y). Without going into too much detail, we can recall that every boolean function has a single canonical full DNFform (i.e. it can be written as an OR of ANDs formula), which can then be easily translated into a linear combination of conjunctions. Therefore, every linear MBA expression can be written as a linear combination of conjunctions by simply applying the aforementioned transformation to each individual bitwise function, then combining terms.

    Now, this linear combination of ANDs can be easily solved using a similar technique we described in the previous section, with the difference being that we must evaluate every possible combination of 0/1 value inputs, not just the inputs containing zero or one 1-values. Without going into too much detail, the coefficients can then be solved through a system of 2n linear equations of 2n variables, where each variable in the linear system represents one of the conjunctions of original variables, and each equation represents a possible 0/1 assignment to the original variables. We improve upon the algorithm proposed by Reichenwallner et al. by making further observations on the structure of the coefficients in the system and applying the forward substitution technique, yielding a simpler and faster solver.

    Finally, Reichenwallner et al. apply an 8-step refinement procedure to find simpler representations, involving more bitwise operations than just conjunction. We found this refinement procedure reasonable and only applied a few tweaks in our implementation.

    Synthesis Oracle Lookup

    The algebraic engines are great for deriving constants when the expression’s semantics fulfill a certain structural quality, namely that they are equivalent to a linear combination of bitwise functions. However, we found that non-linear MBAs are also common in real-world binaries. In order to handle these cases, it is necessary to implement a more general algorithm that does not rely on algebraic properties of the input expression.

    QSynth (2020, David, et al.) and later msynth (2021, Blazytko, et al.) both rely on a precomputed oracle which contains an indexed list of expressions generated through an enumerative search procedure. These expressions are searchable by what we refer to as fingerprints, which can intuitively be understood as a numeric representation of a function’s I/O behavior.

    In order to generate a function fingerprint, we begin by generating test cases, which are assignments of possible inputs to the function. For instance, if we had three variables, a possible test case would be (x=100, y=0, z=-1). Then, we feed each one of these test cases into the function being analyzed; for instance, the expression "x - y + z" would yield the output value 99 for the previous test case. Finally, we collect all the outputs and hash them into a single number to get the fingerprint. Now we can look up the fingerprint in the oracle and find a function that is possibly semantically equivalent to the analyzed function.

    Note that two functions that are indeed semantically equivalent will always yield the same fingerprints (since they will give the same outputs on the test cases). Therefore, if our oracle is exhaustive enough, it should be possible to find equivalences for many MBA-obfuscated expressions. A large precomputed oracle which can be used with goomba is available here: https://hex-rays.com/products/ida/support/freefiles/goomba-oracle.7z

    SMT Proofs of Correctness

    In order to have full confidence in the correctness of our simplifications, we feed both the simplified and original expressions into a satisfiability modulo theories (SMT) solver. Without going into too much detail, we translate IDA’s internal intermediate representation into the SMT language, then confirm that there is no value assignment that causes the two expressions to differ. (In other words, a != b is UNSAT.) If the proof succeeds, then we have full faith that the substitution can be performed without changing the semantics of the decompilation. We use the z3 theorem prover provided by Microsoft Research for this purpose.

    Heuristics

    We found that invoking the SMT solver leads to unreliable performance, since the solver often times out or takes an unreasonable amount of time to prove equivalences. In order to avoid invoking the solver too often, we use heuristics at various points in our analysis. For instance, we detect whether an expression appears to be an MBA expression before trying to simplify it. In addition, every time before we invoke the SMT solver, we generate random test cases and emulate both the input and simplified expressions to ensure they return the same values. We found the latter heuristic to improve performance up to 1,000x in many cases.

    Evaluation

    We evaluated gooMBA on the dataset of linear MBA-obfuscated expressions on MBA-Solver’s GitHub repository, an assortment of real-world examples from VirusTotal that appeared to be MBA-obfuscated, and an MBA-obfuscated sample object file from Apple’s FairPlay DRM solution. In terms of correctness, we find what we expect — gooMBA, being a combination of multiple algorithms, is able to cover more cases than each algorithm individually.

    In terms of performance, we find that gooMBA competes very favorably against state-of-the-art linear MBA solvers, and is able to simplify all of the 1,000 or so examples from MBA-Solver much faster than SiMBA. Note that the comparison is not strictly fair, since SiMBA accepts input expressions as a string, and gooMBA accepts them as decompilation IR; regardless, we claim that accepting decompilation IR leads to a superior user experience with less possibility for human error.

    Compared to msynth, the difference is even more dramatic. On the mba_challenge file provided on msynth’s GitHub repo, we measured the runtime to take around 1.87s per expression. In contrast, our equivalent algorithm took just 0.0047s to run, with the z3 proof taking 0.1s.

    Future Work

    We have presented gooMBA, a deobfuscator that integrates directly into the Hex-Rays decompiler in IDA Pro. This is a meaningful usability trait, since competing tools are typically standalone and require inputting the expression manually or interpreting obtuse outputs. However, this feature also presents some difficulties. For instance, we do not yet perform any use-def analysis or variable propagation beyond what’s already performed by the decompiler. The plugin also currently operates in a purely non-interactive manner, and we believe that adding some interactivity (e.g. allowing the user to choose from a list of simplifications, runs proofs in the background, etc.) would greatly benefit usability.

    Some potential areas of improvement for gooMBA are: sign extensions are not handled uniformly across all simplification strategies, point function analysis is limited, the simplification oracle is limited by necessity, and use-def analysis can be strengthened to extract expressions spread across basic blocks.

    Finally, it’s important to note that MBA obfuscation and deobfuscation are constantly evolving. We based our algorithm choices and implementations on the most promising research on the cutting-edge, but acknowledge that more effective solutions may appear in the future. For instance, though we found that machine learning techniques for MBA-solving have historically underperformed competing methods, machine learning seems like a good candidate for NP-hard problems such as MBA simplification, and we are watching this space for new solutions.

    References

    1. Blazytko, Tim, et al. “Syntia: Synthesizing the semantics of obfuscated code.” 26th USENIX Security Symposium (USENIX Security 17). 2017.
    2. Blazytko, Tim, et al. “msynth.” https://github.com/mrphrazer/msynth. 2021.
    3. David, Robin, Luigi Coniglio, and Mariano Ceccato. “Qsynth-a program synthesis based approach for binary code deobfuscation.” BAR 2020 Workshop. 2020.
    4. Feng, Weijie, et al. “Neureduce: Reducing mixed boolean-arithmetic expressions by recurrent neural network.” Findings of the Association for Computational Linguistics: EMNLP 2020. 2020.
    5. Liu, Binbin, et al. “MBA-Blast: Unveiling and Simplifying Mixed Boolean-Arithmetic Obfuscation.” 30th USENIX Security Symposium (USENIX Security 21). 2021.
    6. Quarkslab. “SSPAM: Symbolic Simplification with PAttern Matching.” https://github.com/quarkslab/sspam. 2016.
    7. Quarkslab. “Arybo.” https://github.com/quarkslab/arybo. 2016.
    8. Reichenwallner, Benjamin, and Peter Meerwald-Stadler. “Efficient Deobfuscation of Linear Mixed Boolean-Arithmetic Expressions.” Proceedings of the 2022 ACM Workshop on Research on offensive and defensive techniques in the context of Man At The End (MATE) attacks. 2022.
    9. Xu, Dongpeng, et al. “Boosting SMT solver performance on mixed-bitwise-arithmetic expressions.” Proceedings of the 42nd ACM SIGPLAN International Conference on Programming Language Design and Implementation. 2021.

    Failures and troubleshooting

    The following failure categories exist:

    1. a crash or access violation
    2. internal consistency check failure (interr)
    3. graceful failure to decompile a function
    4. incorrect output text
    5. inefficient/unclear/suboptimal output text

    The current focus is on producing a correct output for any correct function. The decompiler should not crash, fail, or produce incorrect output for a valid input. Please file a bugreport if this happens.

    The decompiler has an extensive set of internal checks and assertions. For example, it does not produce code which dereferences a “void*” pointer. On the other hand, the produced code is not supposed to be compilable and many compilers will complain about it. This is a deliberate choice of not making the output 100% compilable because the goal is not to recompile the code but to let humans analyze it faster.

    The decompiler uses some C++ constructs in the output text. Their use is restricted to constructs which cannot be represented in C (the most notable example is passing structures to functions by value).

    Internal errors

    When the decompiler detects an internal inconsistency, it displays a message box with the error code. It also proposes you to send the database to the hex-rays.com server:

    It is really difficult (almost impossible) to reproduce bugs without a sample database, so please send it to the server. To facilitate things, the decompiler saves its internal state to the database, which is really handy if the error occurs after hours and hours of decompilation.

    It is impossible to decompile anything after an internal error. Please reload the database, or better, restart IDA.

    Graceful failures

    When the decompiler gracefully fails on a function, it will display one of the following messages. In general, there is no need to file a bugreport about a failure except if you see that the error message should not be displayed.

    Please read the Troubleshooting section about the possible actions.

    cannot convert to microcode

    This error means that the decompiler could not translate an instruction at the specified address into microcode. Please check the instruction and its length. If it looks like a regular instruction used in the compiler generated code and its length is correct, file a bugreport.

    not enough memory

    The error message is self-explanatory. While it should not happen very often, it still can be seen on functions with huge stacks. No need to report this bug. Hopefully the next version will handle functions with huge stack more efficiently.

    Please restart IDA after this error message.

    invalid basic block

    This error means that at the specified address there is a basic block, which does not end properly. For example, it jumps out of the function, ends with a non-instruction, or simply contains garbage. If you can, try to correct the situation by modifying the function boundaries, creating instructions, or playing with function tails. Usually this error happens with malformed functions.

    If the error happens because of a call, which does not return, marking the called function as “noret” will help. If the call is indirect, adding a cross reference to a “noret” function will help too.

    If this error occurs on a database created by an old version of IDA, try to reanalyze the program before decompiling it. In general, it is better to use the latest version of IDA to create the databases for decompilation.

    Unrecognized table jumps may lead to this failure too.

    positive sp value has been found

    The stack pointer at the specified address is higher than the initial stack pointer. Functions behaving so strangely cannot be decompiled. If you see that the stack pointer values are incorrect, modify them with the Alt-K (Edit, Functions, Change stack pointer) command in IDA.

    prolog analysis failed

    Analysis of the function prolog has failed. Currently there is not much you can do but you will not see this error very often. The decompiler will try to produce code with prolog instructions rather than stopping because of this failure.

    switch analysis failed

    The switch idiom (an indirect jump) at the specified address could not be analyzed. You may specify the switch idiom manually using Edit, Other, Specify switch idiom.

    If this error occurs on a database created by an old version of IDA, try to delete the offending instruction and recreate it. Doing so will reanalyze it and might fix the error because newer versions of IDA handle switches much better than older versions.

    exception analysis failed

    This error message should not occur because the current version will happily decompile any function and just ignore any exception handlers and related code.

    stack frame is too big

    Since the stack analysis requires lots of memory, the decompiler will refuse to handle any function with the unaliased stack bigger than 1 MB.

    local variable allocation failed

    This error message means that the decompiler could not allocate local variables with the registers and stack locations. You will see this error message only if you have enabled HO_IGNORE_OVERLAPS in the configuration file. If overlapped variables are allowed in the output, they are displayed in red.

    Please check the prototypes of all involved functions, including the current one. Variables types and definitions may cause this error too.

    Updating the function stack frame and creating correct stack variables too may help solve the problem.

    If you got this error after some manipulations with the function type or variable types, you may reset the information about the current function (Edit, Other, Reset decompiler information) and start afresh.

    16-bit functions are not supported

    The message text says it all. While the decompiler itself can be fine tuned to decompile 16-bit code, this is not a priority.

    call analysis failed

    This is the most painful error message but it is also something you can do something about. In short, this message means that the decompiler could not determine the calling convention and the call parameters. If this is a direct non-variadic call, you can fix it by specifying the callee type: just jump to the callee and hit Y to specify the type. For variadic functions too it is a good idea to specify the type, but the call analysis could still fail because the decompiler has to find out the actual number of arguments in the call. We would recommend to start by checking the stack pointer in the whole function. Get rid of any incorrect stack pointer values. Second, check the types of all called functions. If the type of a called function is wrong, it can interfere with other calls and lead to a failure. Here is a small example:

              push eax
              push edx
              push eax
              call  f1
              call  f2
    

    If f1 is defined as a __stdcall function of 3 arguments, and f2 is a function of 1 argument, the call analysis will fail because we need in total 4 arguments and only 3 arguments are pushed onto the stack.

    If the error occurs on an indirect call, please specify the operand type (Set operand type… command; action SetOpType) of the call instruction. Also, adding an xref to a function of the desired type from the call instruction will work. The decompiler will use the type of the referenced function.

    If all input types are correct and the stack pointer values are correct but the decompiler still fails, please file a bugreport.

    function frame is wrong

    This is a rare error message. It means that something is wrong with the function stack frame. The most probable cause is that the return address area is missing in the frame or the function farness (far/near) does not match it.

    undefined or illegal type

    This error can occur if a reference to a named type (a typedef) is made but the type is undefined. The most common case is when a type library (like vc6win.til) is unloaded. This may invalidate all references to all types defined in it.

    This error also occurs when a type definition is illegal or incorrect. To fix an undefined ordinal type, open the local types windows (Shift-F1) and redefine the missing type.

    inconsistent database information

    Currently this error means that the function chunk information is incorrect. Try to redefine (delete and recreate) the function.

    wrong basic type sizes in compiler settings

    Some basic type sizes are incorrect. The decompiler requires that

    • sizeof(int) == 4
    • sizeof(enum) == 4

    Please check the type sizes in the Options, Compiler dialog box and modify them if they are incorrect.

    Also ensure that the correct memory model is selected: “near data, near code”.

    Finally, the pointer size must be:

    for 32-bit applications use “near 32bit, far 48bit”

    for 64-bit applications use “64bit”.

    redecompilation has been required

    This is an internal error code and should not be visible to the end user. If it still gets displayed, please file a bugreport.

    could not compute fpu stack states

    The decompiler failed to trace the FPU stack pointer. Please check the called function types, this is the only thing available for the moment. We will introduce workarounds and corrective commands in the future. For more information about floating point support, please follow this link.

    max recursion depth reached during lvar allocation

    Please file a bugreport, normally this error message should not be displayed.

    variables would overlap

    This is a variant of the variable allocation failure error. You will see this error message only if you have enabled HO_IGNORE_OVERLAPS in the configuration file. If overlapped variables are allowed in the output, they are displayed in red.

    partially initialized variable

    A partially initialized variable has been detected. Wrong stack trace can induce this error, please check the stack pointer.

    too complex function

    The function is too big or too complex. Unfortunately there is nothing the user can do to avoid this error.

    no license available

    IDA could not locate your decompiler license.

    only 32-bit functions can be decompiled for the current database

    This error message will not currently be displayed.

    only 64-bit functions can be decompiled for the current database

    IDA64 can currently decompile only 64-bit functions. To decompile 32-bit functions please use IDA32.

    already decompiling a function

    An attempt to decompile a function while decompiling another function has been detected. Currently only one function can be decompiled at once.

    far memory model is supported only for pc

    Please check the data and code memory models in the Options, Compiler dialog. If necessary, reset them to ‘near’ models.

    special segments cannot be decompiled

    The current function belongs to a special segment (e.g. “extern” segment). Such segments do not contain any real code, they contain just pointers to imported functions. The function body is located in some other dynamic library. Therefore, there is nothing that we could decompile.

    too big function

    The current function is bigger than the maximal permitted size. The maximal permitted size is specified by the MAX_FUNCSIZE configuration parameter.

    bad input ranges

    The specified input ranges are wrong. The range vector cannot be empty. The first entry must point to an instruction. Ranges may not overlap. Ranges may not start or end in the middle of an item.

    current architecture is not supported

    The current processor bitness, endianness, or ABI settings in the compiler options are not acceptable. See the current ABI limitations here.

    bad instruction in the delay slot

    Branches and jumps are not allowed in a delay slot. Such instructions signal an exception and cannot be decompiled.

    Troubleshooting

    When the decompiler fails, please check the following things:

    • the function boundaries. There should not be any wild branches jumping out of function to nowhere. The function should end properly, with a return instruction or a jump to the beginning of another function. If it ends after a call to a non-returning function, the callee must be marked as a non-returning function.
    • the stack pointer values. Use the Options, General, Stack pointer command to display them in a column just after the addresses in the disassembly view. If the stack pointer value is incorrect at any location of the function, the decompilation may fail. To correct the stack pointer values, use the Edit, Functions, Change stack pointer command.
    • the stack variables. Open the stack frame window with the Edit, Functions, Stack variables… command and verify that the definitions make sense. In some cases creating a big array or a structure variable may help.
    • the function type. The calling convention, the numbers and the types of the arguments must be correct. If the function type is not specified, the decompiler will try to deduce it. In some rare cases, it will fail. If the function expects its input in non-standard registers or returns the result in a non-standard register, you will have to inform the decompiler about it. Currently it makes a good guess about the non-standard input locations but cannot handle non-standard return locations.
    • the types of the called functions and referenced data items. A wrong type can wreak havoc very easily. Use the F hotkey to display the type of the current item in the message window. For functions, position the cursor on the beginning and hit F. If the type is incorrect, modify it with Edit, Functions, Set function type (the hotkey is Y). This command works not only for functions but also for data and structure members.
    • If a type refers to an undefined type, the decompilation might fail.
    • use a database created by the latest version of IDA.

    In some cases the output may contain variables in red. It means that local variable allocation has failed. Please read the page about overlapped variables for the possible corrective methods.

    The future versions will have more corrective commands but we have to understand what commands we need.

    Bugreports

    To be useful, the bugreport must contain enough information to reproduce the bug. The send database command is the preferred way of sending bugreports because it saves all relevant information to the database. Some bugs are impossible to reproduce without this command.

    The database is sent in the compressed form to save the bandwidth. An SSL connection is used for the transfer.

    If your database/input file is confidential and you cannot send it, try to find a similar file to illustrate the problem. Thank you.

    We handle your databases confidentially (as always in the past).

    FAQ

    Currently the list is very short but it will grow with time.


    The output is excessively short for the input function…

    The output is excessively short for the input function. Some code which was present in the assembly form is not visible in the output.

    This can happen if the decompiler decided that the result of these computations is not used (so-called dead code). The dead code is not included in the output.

    One very common case of this is a function that returns the result in an unusual register, e.g. ECX. Please explicitly specify the function type and tell IDA the exact location of the return value. For example:

    int __usercall myfunc<ecx>(void);
    

    Read this section about the user defined calling conventions for more info.

    Another quite common case is a function whose type has been guessed incorrectly by IDA or the decompiler. For example, if the guessed type is

    int func(void);
    

    but the correct function type is

    int func(int x, int y, int z);
    

    then all computations of the function arguments will be removed from the output. The remedy is very simple: tell IDA the correct function type and the argument computations will appear in the output.

    In general, if the input information (function types) is incorrect, the output will be incorrect too. So please check them!


    The following code […] does not look correct. Can this be fixed?

    The following code

    DllUnregisterServer proc near
    
       CommandLine     = byte ptr -274h
       hObject         = _PROCESS_INFORMATION ptr -6Ch
    
                       xor     ebx, ebx
                       mov     [ebp+CommandLine], bl
    

    is being translated into:

       char CommandLine; // [sp+0h] [bp-274h]@1
    
       CommandLine = 0;
    

    This does not look correct. Can this be fixed?

    This happens because the decompiler does not perform the type recovery. To correct the output, modify the definition of CommandLine in IDA. For that, open the stack frame (Edit, Functions, Open stack frame), locate CommandLine and set its type to be an array (Edit, Functions, Set function type). The end result will be:

    CommandLine[0] = 0;
    

    I loaded an old database and the decompiler failed on every single function!**

    Old databases do not contain some essential information. If you want to decompile them, first let IDA reanalyze the database (right click on the lower left corner of the main window and select Reanalyze). You will also need to recreate indirect (table) jump instructions, otherwise the switch idioms will not be recognized and decompilation of the functions containing them will fail.


    The decompiler failed on a function. Should I file a bugreport?

    In general, there is no need to file a bugreport if the decompiler gracefully fails. A failure is not necessarily a bug. Please read the graceful failures section to learn how to proceed.


    The decompiler output is not optimal. Can it be improved?

    Sure, it can be improved. However, given that many decompilation subproblems are still open, even simple things can take enormous time. Meanwhile we recommend you to use a text editor to modify the pseudocode.


    Floating point instructions are displayed as assembly statements. Why?

    Please read this page.


    SSE instructions are displayed as assembly statements. Why?

    Please read this page.

    Limitations

    The decompiler comes in 11 different flavors:

    • x86 decompiler (32-bit code)
    • x64 decompiler (64-bit code)
    • ARM decompiler (32-bit code)
    • ARM64 decompiler (64-bit code)
    • PowerPC decompiler (32-bit code)
    • PowerPC64 decompiler (64-bit code)
    • MIPS decompiler (O32 and N32 ABI)
    • MIPS64 decompiler (N64 ABI)
    • RISC-V decompiler (32-bit code)
    • RISC-V 64 decompiler (64-bit code)
    • ARC Decompiler (32-bit code)

    Currently the decompiler can handle compiler generated code. Manually crafted code may be decompiled too but the results are usually worse than for compiler code. Support for other processors will eventually be added (no deadlines are available, sorry).

    Below are the most important limitations of our decompilers (all processors):

    • exception handling is not supported (except msvc x64 c++ exceptions)
    • type recovery is not performed
    • global program analysis is not performed
    • execution timings are not preserved
    • memory access patterns are not preserved

    Limitations specific to PPC:

    • Vector/DFP/VSX/SPE instructions are not supported

    Limitations specific to MIPS:

    • O32, O64, N32, EABI32, P32(nanoMIPS) are supported
    • only 32-bit FPR in O32,EABI32 and 64-bit FPR in N32,O64 are supported

    Limitations specific to MIPS64:

    • only N64 ABI is supported
    • only 64-bit FPR are supported

    Tips and tricks

    First of all, read the troubleshooting page. It explains how to deal with most decompilation problems. Below is a mix of other useful information that did not fit into any other page:

    Volatile memory

    Sometimes the decompiler can be overly aggressive and optimize references to volatile memory completely away. A typical situation like the following:

                     device_ready    DCD ? ; VOLATILE!
    
                                     MOV     R0, =device_ready
                                     LDR     R1, [R0]
                     LOOP:
                                     LDR     R2, [R0]
                                     SUB     R2, R1
                                     BEQ     LOOP
             
    

    can be decompiled into

                     while ( 1 )
                       ;
             
    

    because the decompiler assumes that a variable cannot change its value by itself and it can prove that r0 continues to point to the same location during the loop.

    To prevent such optimization, we need to mark the variable as volatile. Currently the decompiler considers memory to be volatile if it belongs to a segment with one of the following names: IO, IOPORTS, PORTS, VOLATILE. The character case is not important.

    Constant memory

    Sometimes the decompiler does not optimize the code enough because it assumes that variables may change their values. For example, the following code:

                       LDR     R1, =off_45934
                       MOV     R2, #0
                       ADD     R3, SP, #0x14+var_C
                       LDR     R1, [R1]
                       LDR     R1, [R1]        ; int
                       BL      _IOServiceOpen
             
    

    can be decompiled into

                     IOServiceOpen(r0_1, *off_45934, 0)
             
    

    but this code is much better:

                     IOServiceOpen(r0_1, mach_task_self, 0)
             
    

    because

                     off_45934 DCD _mach_task_self
             
    

    is a pointer that resides in constant memory and will never change its value.

    The decompiler considers memory to be constant if one of the following conditions hold:

    1. the segment has access permissions defined but the write permission is not in the list (to change the segment permissions use the “Edit, Segments, Edit Segment” menu item or the set_segm_attr built-in function)

    2. the segment type is CODE

    3. the segment name is one of the following (the list may change in the future): .text, .rdata, .got, .got.plt, .rodata, __text, __const, __const_coal, __cstring, __cfstring, __literal4, __literal8, __pointers, __nl_symbol_ptr, __la_symbol_ptr, __objc_catlist, __objc_classlist, __objc_classname, __objc_classrefs, __objc_const, __objc_data, __objc_imageinfo, __objc_ivar, __objc_methname, __objc_methtype, __objc_protolist, __objc_protorefs, __objc_selrefs, __objc_superrefs, __message_refs, __cls_refs, __inst_meth, __cat_inst_meth, __cat_cls_meth, __OBJC_RO

      The decompiler tries to completely get rid of references to the following segments and replace them by constants: .got, .got.plt, __pointers, __nl_symbol_ptr, __la_symbol_ptr, __objc_ivar, __message_refs, __cls_refs

    It is possible to override the constness of an individual item by specifying its type with the volatile or const modifiers.

    CONTAINING_RECORD macro

    The decompiler knows about the CONTAINING_RECORD macro and tries to use it in the output. However, in most cases it is impossible to create this macro automatically, because the information about the containing record is not available. The decompiler uses three sources of information to determine if CONTAINING_RECORD should be used:

    1. If there is an assignment like this:

                  v1 = (structype *)((char *)v2 - num);
              
      

      it can be converted into

                  v1 = CONTAINING_RECORD(v2, structype, fieldname);
              
      

      by simply confirming the types of v1 and v2.
      NOTE: the variables types must be specified explicitly. Even if the types are displayed as correct, the user should press Y followed by Enter to confirm the variable type.


    2. Struct offsets applied to numbers in the disassembly listing are used as a hint to create CONTAINING_RECORD. For example, applying structure offset to 0x41C in

                  sub     eax, 41Ch
              
      

      will have the same effect as in the previous point. Please note that it makes sense to confirm the variable types as explained earlier.


    3. Struct offsets applied to numbers in the decompiler output. For example, applying _DEVICE_INFO structure offset to -131 in the following code:

                  deviceInfo = (_DEVICE_INFO *)((char *)&thisEntry[-131] - 4);
              
      

      will convert it to:

                  deviceInfo = CONTAINING_RECORD(thisEntry, _DEVICE_INFO, ListEntry);
              
      

      Please note that it makes sense to confirm the variable types as explained earlier.

    In most cases the CONTAING_RECORD macro can be replaced by a shorter and nicer expression if a shifted pointer used. In this case it is enough to declare the pointer as a shifted pointer and the decompiler will transform all expressions where it is used.

    Indirect calls

    Since the arguments of indirect calls are collected before defining variables, specifying the type of the variable that holds the function pointer may not be enough. The user have to specify the function type using other methods in this case. The following methods exist (in the order of preference):

    1. For indirect calls of this form:

                  call ds:funcptr
              
      

      If funcptr is initialized statically and points to a valid function, just ensure a correct function prototype. The decompiler will use it.

    2. For indirect calls of this form:

                  call [reg+offset]
              
      

      If reg points to a structure with a member that is a function pointer, just convert the operand into a structure offset (hotkey T):

                  call [reg+mystruct.funcptr]
              
      

      and ensure that the type of mystruct::funcptr is a pointer to a function of the desired type.

    3. Specify the type of the called function using Edit, Operand type, Set operand type. If the first two methods cannot be applied, this is the recommended method. The operand type has the highest priority, it is always used if present.

    4. If the address of the called function is known, use Edit, Plugins, Change the callee address (hotkey Alt-F11). The decompiler will use the type of the specified callee. This method is available only for x86. For other processors adding a code cross reference from the call instruction to the callee will help.

    Debugger

    Instant debugger
    Remote debugging
    Local debugging
    Debugger tutorials

    Instant debugger

    The -r command line switch is used to run the built-in debugger without creating a database in advance. The format is this switch is:

      -rdebname{params}:pass@hostname:port+pid
    

    The explanation of the fields:

      debname       Debugger name. Should contain the debugger
                    module name. Examples: win32, linux. This prefix
                    can be shortened or even completely
                    omitted if there is no ambiguity
      params        Optional parameter for the debugger module
                    The parameters from the appropriate configuration file
                    can be specified here, separated by semicolons.
      pass          Password for the remote debugger server
      hostname      Host name or address of the remote debugger server.
                    IPv6 addresses need to be enclosed in [].
      port          Port number to use to connect to the debugger server
      pid           PID of the process to attach
    

    All fields except the first one are optional. Also, the pid field can be specified as ‘+’. IDA will display the process list to attach. See examples below for typical command lines:

      ida -rwin32 file args
            Run 'file' with command line 'args' in the local debugger
            We have to specify the debugger name to avoid ambiguities.
      ida -rwindbg+450
            Attach to process 450 on the local machine using the windbg backend
      ida -rl:hippy@mycom:4567+
            Connect to the remote linux computer 'mycom' at port 4567 using the
            password 'hippy' and display the list of processes running on it.
            Allow the user to select a process and attach to it.
      ida -rl@mycom /bin/ls e*
            Run '/bin/ls' command on the 'mycom' computer using the remote
            debugger server on Linux. Use an empty password and the
            default port number. Pass "e*" as the parameter to /bin/ls.
      ida -rl@mycom whobase.idb
            Run '/usr/bin/who' command on the 'mycom' computer using the
            remote linux debugger server. Use an empty password and the
            default port number. IDA will extract the name of the
            executable from the whobase.idb file in the local current
            directory. If the database does not exist, then this command
            will fail.
      ida "-rwindbg{MODE=1}@com:port=\\.\pipe\com_1,baud=115200,pipe,reconnect+"
            Attach using windbg in kernel mode. The connection string is
            "com:port=\\.\pipe\com_1,baud=115200,pipe,reconnect". A mini database
            will be created on the fly.
    

    When the -r switch is used, IDA works with the databases in the following way:

            - if a database corresponding to the input file exists and
            the -c switch has not been specified, then IDA will use the
            database during the debugging session
    
            - otherwise, a temporary database will be created
    

    Temporary databases contain only meta-information about the debugged process and not the memory contents. The user can make a memory snapshot any time before the process stops. If IDA detects that a command will cause the process to exit or detach IDA, it will propose to make a snapshot.

    The rest of the command line is passed to the launched process.

    In the case there is no input file (when attaching to an existing process, for example), then the temporary database is created in the standard temporary directory. For Windows, this directory is usually “Local Setting\Temp” in the user profile directory.

    See also How to launch remote debugging

    Remote debugging

    1. Launch a remote IDA debugger server on the remote host. The remote server is started from the command line and accepts command line parameters. You can specify a password if you want to protect your debugger server from strangers. For example, to launch the server under MS Windows, you could enter:

            win32_remote -Pmy_secret_password
    

    2. Specify the remote debugger parameters in the Debugger, Process options. The file paths must be valid on the remote host. Do not forget to specify the same password as you have specified when launching the server. For example, to debug notepad.exe on the remote computer remote.host.com:

            Application: c:\windows\notepad.exe
            Input file:  c:\windows\notepad.exe
            Directory:   c:\windows
            Hostname:    remote.host.com
            Port:        23946
            Password:    my_secret_password
    

    3. The rest of debugging is the same as with local debugging.

    {% hint style=“info” %} The Linux debugger server can handle one debugger session at once. If you need to debug several applications simultaneously, launch several servers at different network ports. {% endhint %}

    The following debugger servers are shipped with IDA

     File name             Target system         Debugged programs
     ------------------    ------------------    ----------------------------
     android_server32      ARM Android           32-bit ELF files
     android_server        AArch64 Android       64-bit ELF files
     android_x64_server    x86 Android 32-bit    32-bit ELF files
     android_x86_server    x86 Android 64-bit    64-bit ELF files
     armlinux_server32     ARM Linux             32-bit ELF files
     armlinux_server       AArch64 Linux         64-bit ELF files
     linux_server          Linux 64-bit          64-bit ELF files
     mac_server            Mac OS X/macOS 11     64-bit Mach-O files (x64)
     mac_server_arm        ARM macOS 11          64-bit Mach-O files (arm64)
     mac_server_arme       ARM macOS 11          64-bit Mach-O files (arm64e)
     win32_remote32.exe    MS Windows 32-bit     32-bit PE files
     win64_remote.exe      MS Windows 64-bit     64-bit PE files
    

    An appropriate server must be started on the remote computer before starting a debug session.

    See also

    Remote iOS Debugger

    The Remote iOS Debugger allows for debugging iOS applications directly from IDA.

    IDA’s iOS debugger acts as a client to Apple’s debugserver. So, you must ensure that the debugserver is already installed on your device for the debugger to work.

    See:

    See also

    Android debugger

    Android debugger

    The Android debugger has the following particularities and limitations:

    - ARM32, AArch64, x86 and x64 Android native debugging is supported

    - Both ARM and Thumb mode code is supported

    - Multithreaded applications can be debugged. However, since the operating system does not report thread deaths, they are reported only when the debugger notices that the thread is missing (for example, because there is an error when we try to suspend it)

    - Apparently Android reports applications that are currently executing a system call as executing "LDMFD SP!, {R4,R7}" before the syscall. Once the syscall completes, the next instruction is reached.

    - Hardware breakpoints for ARM32 and AArch64 are not supported.

    See also:

    Dalvik debugger

    Dalvik debugger

    The Dalvik debugger is a plugin to debug Android applications written for the Dalvik Virtual Machine. It includes the source level debugging too.

    Dalvik debugger specific options:

        ADB executable
    
            IDA needs to know where the 'adb' utility resides, and tries various
            methods to locate it automatically. Usually IDA finds the path to adb,
            but if it fails then we can define the ANDROID_SDK_HOME or the
            ANDROID_HOME environment variable to point to the directory where the
            Android SDK is installed to. Or set the path to 'adb' here.
    
        Emulator/device serial number
    
            If multiple emulator/device instances are running, you must specify
            the target instance to connect to.
    
        Package name
    
            Set the package name for the application as specified in
            AndroidManifest.xml. It is a mandatory option to start an application.
            If you plan to use "Attach to process" debugger action then you may
            leave this field empty.
    
        Activity
    
            If your want to start an application using the "Start process"
            debugger action then you have to set this option too. Copy it from
            AndroidManifest.xml. If you plan to use the "Attach to process"
            debugger action then you may leave this field empty.
    
        Command line arguments
    
            Every object inside Dalvik VM has an ID. It is the 64-bit number.
            If you want to see it in "Locals"/"Watches" windows then set this
            checkbox.
    

    Source-level debugging

        In order to use source-level debugging you have to set paths to the
        application source code files. Do it using "Options/Sources path"
        menu item.
    
        Our dalvik debugger presumes that the application sources reside
        in the current (".") directory.  If this is not the case, you can
        map current directory (".") to the directory where the source files
        are located.
    

    List of special things about our Dalvik debugger:

      - In Dalvik there is no stack and there is no SP register.
        The only available register is IP.
      - The method frame registers and slots (v0, v1, ...) are represented as
        local variables in IDA.
        We can see them in the Debugger/Debugger Windows/Locals window
      - The stack trace is available from "Debugger/Windows/Stack trace"
      - When the application is running, it may execute some system code.
        If we break the execution by clicking on the "Cancel" button,
        quite often we may find ourselves outside of the application,
        in the system code. The value of the IP register is 0xFFFFFFFF in this
        case, and stack trace shows only system calls and a lot of 0xFFFFFFFFs.
        It means that IDA could not locate the current execution position inside
        the application. We recommend to set more breakpoints inside the
        application, resume the execution and interact with application by
        clicking on its windows, selecting menu items, etc.
        The same thing can occur when we step out the application or
        step into the system code. In the last case we can use "Run until
        return" debugger command to return to the application code.
    

    Locals window

        IDA considers the method frame registers, slots, and
        variables (v0, v1, ...) as local variables.
        To see their values we have to open the "Locals" window
        from the "Debugger/Debugger windows/Locals" menu item.
    
        If the information about the frame is available (the symbol table is
        intact) then IDA shows the method arguments, the method local variables
        with names and other non-named variables.
        Otherwise some variable values will not be displayed because IDA
        does not know their types. Variables without type information are
        marked with "Bad type" in the "Locals" window.
        To see the variable value in this case please use the "Watches" window.
    

    Watches window

        To open the "Watches" window please select the "Debugger/Windows/Watches"
        menu item. In this window we can add any variable to watch its value.
    
        Please note that we have to specify type of variable if it is not known.
        Use C-style casts:
            (Object*)v0
            (String)v6
            (char*)v17
            (int)v7
    
        We do not need to specify the real type of an object variable,
        the "(Object*)" cast is enough.  IDA can derive the real object type
        itself.
    
        ATTENTION! An incorrect type may cause the Dalvik VM to crash.
    
        There is not much we can do about it. Our recommendation is to never
        cast an integer variable to an object type, the Dalvik VM usually
        crashes if we do that. But the integer cast "(int)" is safe in practice.
    
        Keeping the above in the mind, do not leave the cast entries
        in the "Watches" window for a long time. Delete them before any
        executing instruction that may change the type of the watched variable
    

    See also Debugger submenu.

    Remote GDB Debugger

    Remote GDB Debugger module allows for debugging code using the GDB remote serial protocol. For this, the debuggee must contain a so-called “GDB stub” that controls the execution and handles the remote protocol commands. There are many implementations of such stubs available with different capabilities. The module has been tested with the following GDB stubs: gdbserver: Windows (Cygwin), Linux (ARM, MIPS, PowerPC) VMWare: x86 (16/32 bit) QEMU: x86 (16/32 bit), ARM, MIPS, PowerPC OpenOCD: ARM It is quite possible that the module will work with other stubs. Note that only x86, ARM, MIPS and PowerPC processors are supported at the moment.

    Some GDB stubs support so-called “monitor” commands. For example, VMWare stub can return extra info about system registers. Use the command line at the bottom of the main IDA window to send such commands. The output will be displayed in the message window. Hint: most stubs have a “help” command (if they support any commands at all).

    The module also makes the following function available from IDC: string send_dbg_command(string command);

     NOTE
    

    When using instant debugging, you will need to tell IDA on which CPU the target is running. This is done in the Remote GDB Debugger options dialog, available via “Debugger specific options” button in the Process options dialog shown when you choose Remote GDB Debugger from the Run or Attach menu.

     NOTE
    

    Many GDB stubs do not report the address that triggered a hardware breakpoint. In this case, IDA will report a memory breakpoint hit as a generic TRAP signal. Examine the previous instruction to see if it referenced a memory location with breakpoint. When continuing from such a breakpoint, choose not to pass the signal to the program.

     NOTE
    

    IDA can be used together with a J-Link debug probe from SEGGER Microcontroller GmbH:

    https://segger.com/jlink-debug-probes.html

    See also

    Remote GDB Debugger options

    Max packet size

            Maximum packet size supported by the GDB stub (in bytes).
            Some stubs can crash on big packets, e.g. memory reads. IDA
            will try to split such requests in smaller chunks so that
            replies should fit in this size. You can enter -1 to
            autodetect (in this case IDA will use the size of the
            "g" packet reply as the max packet size).
    

    Timeout

            Default timeout in milliseconds for remote GDB stub responses.
            Some targets can be slow to respond, so increase this value
            when having problems, e.g. with disappearing memory bytes.
    

    Run a program before starting debugging Check to enable external program options. Processor This option is only visible when starting debugger without a database. Use it to specify on which CPU the target is running. For some processors you can also specify the endianness. Software breakpoints at EIP+1

            Most GDB stubs for x86 report software breakpoint hits with EIP one byte after
            the breakpoint address. However, some emulators report the actual breakpoint
            address. This option allows IDA to recognize such situations.
            Recommendations: uncheck for QEMU, check for others.
    

    Use CS:IP in real mode

            When debugging real-mode (16-bit) code, the stub can send either
            just 16 bits of IP register or the full EIP (CS<<4 + IP).
            Enable this option in the former case.
            Recommendations: check for QEMU, uncheck for others.
    

    See also

    Debugging with gdbserver

    gdbserver is a GDB stub implemented as a separate program. It runs a program to be debugged or attaches to a process and then waits for commands. The remote GDB debugger module has been tested with gdbserver available with Cygwin and Linux.

    To debug a specific program from the start, run the following command:

        gdbserver localhost:23946 <program>
    

    and then choose Debugger,Attach,<process running on target> in IDA.

    To debug a running process:

        gdbserver --multi localhost:23947
    

    then choose Debugger,Attach,<enter PID to attach> in IDA and enter the PID of the process to attach to.

    Another method of debugging a running process is:

        gdbserver localhost:23947 --attach <PID>
    

    then choose Debugger,Attach,<process running on target> in IDA.

    To start a program from inside IDA, first launch the debugger server:

        gdbserver --multi localhost:23947
    

    Then use Debugger,Start process or Debugger,Run in IDA.

     NOTE
    

    The –multi option is only available in GDB 6.8 or higher.

    Back to Remote GDB Debugger

    Debugging with VMWare

    VMWare Workstation 6.5 is recommended for debugging, though earlier versions may work too. Only 32-bit debugging is supported.

    In order to enable debugging with GDB protocol, add the following lines to the .vmx file of the virtual machine:

       debugStub.listen.guest32 = "TRUE"
       debugStub.hideBreakpoints= "TRUE"
    

    To debug the VM startup, use:

       monitor.debugOnStartGuest32 = "TRUE"
    

    Please note that the execution will start in the BIOS.

    To accept connections from remote computers, the following line must be specified:

       debugStub.listen.guest32.remote = "TRUE"
    

    VMWare Workstation will listen on port 8832.

    Tips:

    Since the GDB server does not report the memory layout, it must be specified manually. For example, to debug BIOS startup code, create a 16-bit segment from F0000 to 10000 with base F000.

    Use the GDB command line to get extra info about the registers. For example, use “r cr0” to see current value of the cr0 register or “r cs” to see the base, limit and other attributes of the CS selector in protected mode.

    Back to Remote GDB Debugger

    Debugging with OpenOCD

    Make sure the following line is present in the .cfg file for your target:

     gdb_port 3333
    

    Edit the port number if necessary. Specify that port in the process options and use the Debugger, Attach command.

    Tips: Use the GDB command line (see Output window) to send commands directly to OpenOCD interpreter.

    Debugging with QEMU

    Using the “Run external program” option it is easy to debug small ARM, MIPS or PowePC code snippets directly from inside IDA.

    1) Download and install QEMU. Win32 builds can be downloaded from http://homepage3.nifty.com/takeda-toshiya/qemu/.

    2) Edit cfg\gdb_arch.cfg file and change the “set QEMUPATH” line to point to the install directory of QEMU.

    3) In Remote GDB Debugger options (Debugger|Debugger options, Set specific options), enable “Run a program before debugging”.

    4) Click “Choose a configuration” and choose a predefined configuration. Choose “for snippets”, if mentioned.

    5) If necessary, edit the command line or memory map.

    6) Click OK, OK to confirm and close the options dialog.

    7) In Debugger|Process options make sure that Hostname is set to “localhost” and port is non-zero.

    8) Select the code range to emulate or at least the first instruction. Alternatively, you can rename the starting address “ENTRY” and end address as “EXIT”.

    9) Choose Debugger|Run or press F9.

    IDA will write the database into an ELF file (if %e was specified), start QEMU with the specified command line and connect to its GDB stub. It will set the SP and PC values so that the code can be stepped through.

    NOTE: While it can be very useful, QEMU emulation has certain limitations: 1) the memory map is usually fixed at compile time. So if your program addresses intersect some of the system regions as specified by the memory map, IDA will refuse to start debugging. In that case, you can either rebase the program so that it fits into RAM regions or check other QEMU board configurations for a compatible memory layout.

    2) the emulation starts at the system (kernel) level when there is no OS loaded. That means that system calls and imported functions will not work.

    3) the hardware access will only work to the extent emulated by QEMU. If the code you are emulating does not match the chosen board configuration of QEMU, the code accessing the hardware most likely will not work properly, if at all.

    See also:

    External programs and GDB Debugger

    The “Run a program before debugging” option in Remote GDB Debugger options allows to automatically run a program (such as a debugging server) when starting a debugging session. If you enable it, the following options become available:

    Command line

            Command line of the program to run. The following special symbols can be used:
    

    %i: input file name from the Process options dialog %p: port number from the Process options dialog %e: file name of a temporary ELF file created from the database contents Initial SP

            IDA will set the SP (or a similar register) after connecting to the server
    

    Choose a configuration

            Load one of the pre-defined configurations (command line, memory map and SP value)
            described in the gdb_arch.cfg file.
    

    Memory map

            Edit the memory map for the external server. It will be used during debugging.
    

    One use of these options is to debug small code snippets using the QEMU emulator.

    See also

    Debugging code snippets with QEMU

    Using the “Run external program” option it is easy to debug small ARM, MIPS or PowePC code snippets directly from inside IDA.

    1) Download and install QEMU. Win32 builds can be downloaded from http://homepage3.nifty.com/takeda-toshiya/qemu/.

    2) Edit cfg\gdb_arch.cfg file and change the “set QEMUPATH” line to point to the install directory of QEMU.

    3) In Remote GDB Debugger options (Debugger|Debugger options, Set specific options), enable “Run a program before debugging”.

    4) Click “Choose a configuration” and choose a predefined configuration. Choose “for snippets”, if mentioned.

    5) If necessary, edit the command line or memory map.

    6) Click OK, OK to confirm and close the options dialog.

    7) In Debugger|Process options make sure that Hostname is set to “localhost” and port is non-zero.

    8) Select the code range to emulate or at least the first instruction. Alternatively, you can rename the starting address “ENTRY” and end address as “EXIT”.

    9) Choose Debugger|Run or press F9.

    IDA will write the database into an ELF file (if %e was specified), start QEMU with the specified command line and connect to its GDB stub. It will set the SP and PC values so that the code can be stepped through.

    NOTE

    While it can be very useful, QEMU emulation has certain limitations:

    1) the memory map is usually fixed at compile time. So if your program addresses intersect some of the system regions as specified by the memory map, IDA will refuse to start debugging. In that case, you can either rebase the program so that it fits into RAM regions or check other QEMU board configurations for a compatible memory layout.

    2) the emulation starts at the system (kernel) level when there is no OS loaded. That means that system calls and imported functions will not work.

    3) the hardware access will only work to the extent emulated by QEMU. If the code you are emulating does not match the chosen board configuration of QEMU, the code accessing the hardware most likely will not work properly, if at all.

    See also

    PIN debugger

    The PIN debugger is a remote debugger plugin used to record execution traces. It allows to record traces on Linux and Windows (x86 and x86_64) from any of the supported IDA platforms (Windows, Linux and MacOSX). Support for MacOSX targets is not yet available. Please see the section PIN support for MacOSX for more details on this subject.

    To use the PIN debugger plugin the following steps must be carried out:

    • Download the appropriate version of PIN from http://www.pintool.org

    • Build the PIN tool

      - Configure the debugger specific options in
        Debugger Options, Set specific options.
      
      PIN debugger plugin has the following configuration options:
      

    - PIN Binary Path: Full path to the pin binary.

    • PIN Tool Path: Directory where the idadbg.so or .dll PIN tool resides.
    • Tracing options:
    • Instruction tracing: trace individual instructions
    • Basic block tracing: trace basic blocks
    • Function tracing: trace functions
    • Recording of register values: record register values or not. If this option is disabled, only EIP/RIP will be recorded.
    • PIN Tool options:
    • Autolaunch pin for “localhost”: When this option is set and the host name specified in Debugger, Process Options is “localhost”, the PIN tool will be executed by IDA. Otherwise IDA expects the PIN tool to be already running and listening. Please refer to Connecting a remote PIN tool instance from IDA for more details.
    • Debug mode: This flag allows one to see what’s happening in the PIN tool side. It prints out some debugging information.
    • Extra-arguments: Additional command line arguments to be used when constructing the command line to launch PIN locally. The extra arguments can be added before the PIN tool specification (before ’-t /path/to/pin/tool) or after the PIN tool (after ‘-t /path/to/pin/tool’ but before ‘– application’). Please consult the section “Command Line Switches” of the Intel PIN manual for more details. Optionally you can launch PIN yourself and connect to it from IDA. See Connecting a remote PIN tool instance from IDA for more details.

    Building the PIN tool

    Building the PIN tool

    Before using the PIN tracer the PIN tool module (distributed only in source code form) must be built as the Intel PIN license disallows redistributing PIN tools in binary form.

    Please refer to the Debugging Linux/Windows Applications with PIN Tracer tutorial to learn how to build our PIN tool.

    Connecting a remote PIN tool instance from IDA

    For local debugging the PIN tool can be automatically launched by IDA. For remote debugging it must be launched manually, as in the following example:

      $ /path/to/pin -t /path/to/idadbg/lib -p PORT -- APPLICATION [ARGUMENTS]
    

    Where PORT is the port that the PIN tool will listen for incoming connections from IDA. APPLICATION is the target application to be traced and the optional parameter ARGUMENTS are the arguments to be passed to the target application. Please note that on Win64 it may be required to specify the path to specific x64 binary instead to the pin.bat batch file.

    To attach to an already running process instead of starting a new one a command like the following one must be executed:

      $ /path/to/pin -pid PID -t /full/path/to/idadbg/lib/with.extension -p PORT
    

    Where PID is the pid of the running process to attach and PORT the port that the PIN tool will listen for incoming connections.

    The hostname and port where the PIN tool is listening for incoming connections should be specified in IDA. See the Debugger, Process options dialog.

    After successfully launching the PIN tool the IDA debugger can be launched by pressing F9 or selecting Debugger, Start Process.

    PIN accepts the following optional environment variables and command line arguments:

      - Environment variables:
        IDAPIN_DEBUG: Set this environment variable to 1 or higher to print
        debugging information.
    
      - Command line arguments:
        -p number: Port where the PIN tool will listen for incoming connections from IDA
        -idadbg [0|1|2]: Same as the IDAPIN_DEBUG environment variable
    

    PIN support for MacOSX

    Recording traces on MacOSX target is not supported yet. Versions equal or prior to 2.12-55942 does not have support for the API PIN_SpawnInternalThread, which is needed by IDA to communicate with the PIN tool.

    However, it’s possible to record traces from a Linux or Windows target using the MacOSX version of IDA.

    Replayer debugger

    The replayer debugger is a pseudo-debugger used to replay recorded traces.

    The replayer debugger supports replaying traces recorded with any of the currently supported debuggers, ranging from local Linux or win32 debuggers to remote GDB targets. Currently supported targets include x86, x86_64, ARM, MIPS and PPC.

    To use the replayer debugger you will need first to record a trace by enabling instruction tracing, function tracing or basic block tracing with another debugger. Then, after loading a recorded trace in the Tracing window, select the replay debugger from the debugger’s dropdown list and start the debugger normally as you would do with any other debugger.

    One of the advantages of the replay debugger module over re-executing the debuggee is that in the replayer debugger it is possible to step not only forward, but also backwards, making it easier to analyze what happened during the execution of the recorded trace.

    There are two types of traces that can be replayed: instruction level traces or partial traces. Instruction level traces are recorded by enabling instruction tracing and partial traces are recorded using either function tracing or basic block tracing. When a trace is recorded with instruction tracing enabled all register values are saved. With basic block or function level tracing only the instruction pointer is saved. Additionally, in basic block tracing the register values are also saved when the last instruction of a basic block is reached or a call in the middle of a basic block is about to be executed.

    The replayer debugger module adds a new menu item: Debugger, Step Back command. It can be used to step back to the previous instruction when replaying a recorded trace.

    Additional IDC functions provided by the replayer debugger

    Bochs debugger

    The Bochs debugger plugin uses the Bochs internal command line debugger. For more about the internal debugger: http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html

    To use the Bochs debugger plugin, the following steps must be carried out:

    • Download and install Bochs v2.6.x from: http://bochs.sourceforge.net/getcurrent.html For Mac OS or Linux, please refer to the following guide: bochs_linux_primer

      - Open or create an IDB file in IDA and select the Bochs debugger
      
      - Configure the debugger specific options in
            Debugger Options, Set specific options.
        One of three possible modes of operation can be selected: image, idb, or pe.
      

    Because the debugger plugin uses the Bochs command line debugger, it has the following limitations:

      - Breakpoints: the Bochs debugger has the limit of 10 physical, 10
        virtual, and 10 linear breakpoints. Since IDA uses some breakpoints
        for its own purposes, only 20 breakpoints can be set by the user
    
      - Watchpoints: the Bochs debugger has the limit of 16 read and 16 write
        watchpoints
    
      - FPU registers, MMX, XMM, control, task and segment registers cannot be modified
    

    There are ways to overcome some of the limitations mentioned above by downloading Bochs source code and modifying it. For example, the number of allowed breakpoints can be increased.

    The Bochs debugger configuration dialog box has the following entries:

      BOCHSRC
        This is the path to the Bochs configuration file template. It contains
        special variables prefixed with "$". These variables should not be
        modified or changed by the user, as they are automatically filled by the
        plugin. Other entries can be modified as needed.
    

    Operation mode The user can choose between Disk Image, IDB and PE operation modes.

      Delete image files upon session end
        If enabled, IDA will automatically delete the Bochs disk images used for
        the debugging session (this option only applies to IDB and PE operation modes).
        If the plugin (in IDB operation mode) finds a previously created image, it verifies that it
        corresponds to the database and uses it as is. Unchecking this option
        for the IDB operation mode will speed up launching the debugger.
    
      64-bit emulation
        This options enables 64bit emulation. It is only present in the 64-bit version of IDA.
        By default, the Bochs plugin will try to detect whether to choose 32 or 64-bit emulation.
    

    Default configuration parameters are taken from ida\cfg\dbg_bochs.cfg.

    The Bochs debugger module adds a new menu item: Debugger, Bochs Command. It can be used to send arbitrary commands to Bochs. The command output is displayed in the message window (there is also an IDC counterpart of this function, please refer to “startup.idc” file). This command is very useful but may interfere with IDA, especially if the user modifies breakpoints or resume execution outside IDA.

    See also:

    Bochs Disk Image operation mode

    The disk image operation mode is used to run Bochs with any Bochs disk image.

    A simple way to get started is to launch IDA and disassemble the bochsrc file associated with your disk image. IDA will recognize bochsrc files, parse the contents, determine the associated disk image and create a new database containing the first sector of the disk image (usually the boot sector).

    The database does not have to correspond to the disk image: it could in fact start as an empty database, then user could convert the needed segments to loader segments for later analysis. The following script can be used for that purpose:

            attrs = get_segm_attr(desired__segment__start, SEGATTR_FLAGS);
            attrs = (attrs & ~SFL_DEBUG) | SFL_LOADER;
            set_segm_attr(desired__segment__start, SEGATTR_FLAGS, attrs);
    

    If the disk image switches to protected mode with memory paging enabled, IDA will use the page table mapping to display segments. For 16-bit applications, IDA automatically creates a default DOS memory map (Interrupt vector table, Bios Data Area, User Memory and BIOS ROM). Also, the Bochs Debugger plugin will try to guess the debugger segment bitness, nonetheless the user can edit the bitness manually.

    Moreover, the Bochs internal debugger provides the ability to add hardware like breakpoints, known as watchpoints, but the addresses must be physical addresses. In order to use the disk image operation mode in a more convenient way, the plugin will convert the virtual addresses to physical addresses (if page table information is present) before adding the hardware breakpoint. This mechanism will not always work, please check the FAQ for more information. For hardware breakpoint on execute, the plugin will use the selected address as-is and create a physical breakpoint.

    The following parameters can be specified for the disk image operation mode:

      - The bochsrc file which contains the configuration for the Bochs virtual machine in question.
        The bochsrc file should be entered in:
        Debugger -> Process Options -> Application (other fields are ignored)
    
      - Use virtual breakpoints when protected mode is enabled:
        This parameter is set in the Debugger Specific options.
        It will allow the plugin to use "vb" command to create
        virtual breakpoints (using cs:eip), instead of using the "lb" which
        creates linear breakpoints (using only "eip"). It is useful when
        debugging code where the "cs" segment selector base is not zero.
    

    This is a small example on how to debug a given disk image:

    1. Prepare the needed bochs virtual machine files (bochsrc, disk image, floppy image if needed, etc…)

    2. Load the bochsrc file into IDA. IDA will automatically create a database.

    (Step 2, is optional. It is possible to use a database of your choice, but remember to point its “Debugger->Process Options->Input file” to the bochsrc file)

    3. Make sure the “Disk image” operation mode is selected (If Step 2 was used, then Disk image operation mode will be selected automatically)

    4. Enable “Debugger Options->Suspend on debugging start”, and start debugging!

    In the disk image operation mode, the Bochs debugger plugin does not handle or report exceptions, if they must be caught and handled, please put breakpoints in the IDT or IVT entries.

    See also:

    Bochs IDB operation mode

    The IDB operation mode, as its name implies, takes the current database as the input and runs it under the Bochs debugger. This mode can be used to debug any x86 32 or 64-bit code. Please note that the code executes with privilege ring 3.

    The following parameters can be specified in the IDB operation mode:

      - Entry address: the address where the execution starts.
        This parameter can be specified in three ways (listed in order of
        precedence):
          - by renaming the desired location as "ENTRY" (global name)
          - by selecting an address range with the mouse or keyboard.
            The selection start address is used as the entry point
          - by positioning the cursor at a given position and running the
            debugger
    
      - Exit address (optional): the address where the execution ends.
        This parameter can be specified in two ways:
          - by renaming the desired location as "EXIT" (global name). Please note that
            the emulation will stop at the item following the exit label.
          - by selecting an address range with the mouse or keyboard
            The selection end address is used as the exit point
        If the exit address is not specified, the execution will continue until
        an exception occurs. However, if the exit address is reached, the debugger
        will ask the user if emulation should be continued or not.
    
      - Startup stack size: number of KBs to allocate for the stack segment.
        The stack segment is automatically created and named as "STACK".
    

    It may also prove useful to enable the “Debugger Setup/Suspend on debugging start” so that IDA automatically suspends the process before executing the first instruction.

    While debugging, exceptions may occur and are caught by IDA. Please note that these exceptions are raw machine exceptions. For example, instead of an access violation exception, a page fault exception is generated.

    See also:

    Bochs PE operation mode

    The PE operation mode can be used to load PE files and debug them in a MS Windows like environment.

    The current limitations include:

      - Thread or process manipulation are not supported
    
      - Limited support for PE+
    
      - We provide implementations of a limited number of system calls. Feel
        free to implement missing functions using IDC scripts or DLLs.
    
      - LoadLibrary() will fail on unknown DLLs: the list of desired DLLs must
        be specified before running the debugger in the startup.idc file
    
      - Limited emulation environment: IDA does not emulate the complete MS Windows
        operating system: it just provides the basic environment for a
        32bit PE file to run (please check the features below). There are many
        ways how the debugged program can detect that it runs in an emulated
        environment.
    

    PE executables feature list:

    - SEH support: we try to mimic MS Windows as much as possible. For example, the ICEBP instruction is a privileged instruction, but Windows reports back a single step exception. Similarly, MS Windows does not distinguish between 0xCC and 0xCD 0x03, so when an exception occurs, it reports that the exception address is always one byte before the trap. So if it was an INT 0x3 (CD03), the exception address will point to the 0x03 (in the middle of the instruction).

    - TLS callbacks: TLS callbacks are normally parsed by IDA and presented as entry points. They will be called by the debugger before jumping to the main entry point of the application. Turning on the “Debugger Setup/Suspend on debugging start” may be a good idea since it will make all this logic clearly visible.

    - Emulation of NT structures: Some malware do not use GetProcAddress() or GetModuleHandle(). Instead, they try to parse the system structures and deduce these values. For this we also provide and build the basic structure of TIB, PEB, PEB_LDR_DATA, LDR_MODULE(s) and RTL_USER_PROCESS_PARAMETERS. Other structures can be built in the bochs_startup() function of the startup.idc file.

    PE/PE+ executables feature list:

    - Extensible API emulation: The user may provide an implementation of a any API function using scripts. The plugin supports IDC language by default, but if there are any other registered and active external languages, then external language will be used. Currently, the plugin ships with preconfigured IDC and Python scripts (please refer to startup.idc/startup.py).

    It is also possible to take a copy of all the API and startup scripts and place them next to the database in question. This will tell the Bochs debugger plugin that these scripts are to be used with the current database directory. Such mechanism makes it possible to customize API/startup scripts for different databases.

    In the following example, kernel32!GlobalAlloc is implemented via IDC like this:

     (file name: api_kernel32.idc)
     ///func=GlobalAlloc entry=k32_GlobalAlloc purge=8
     static k32_GlobalAlloc()
     {
       eax = BochsVirtAlloc(0, BochsGetParam(2), 1);
       return 0;
     }
     ///func=GlobalFree entry=k32_GlobalFree purge=4
     static k32_GlobalFree()
     {
       eax = BochsVirtFree(BochsGetParam(1), 0);
       return 0;
     }
    

    A simple MessageBoxA replacement can be:

     (file name: api_user32.idc)
     ///func=MessageBoxA entry=messagebox purge=0x10
     static messagebox()
     {
       auto param2; param2 = BochsGetParam(2);
       msg("MessageBoxA has been called: %s\n",
            get_strlit_contents(param2, -1, STRTYPE_C));
    
       // Supply the return value
       eax = 1;
    
       // Continue execution
       return 0;
     }
    

    To access the stack arguments passed to a given IDC function, please use the BochsGetParam() IDC function.

    For a full reference on using IDC to implement API calls, please refer to ida\plugins\bochs\api_kernel32.idc file.

    - Remap a DLL path (from the startup.idc script):

        /// map /home/johndoe/sys_dlls/user32.dll=d:\winnt\system32\user32.dll
        /// map /home/johndoe/sys_dlls/kernel32.dll=d:\winnt\system32\kernel32.dll
    

    - Specify additional DLL search path (and optionally change the mapping):

        /// map /home/johndoe/sys_dlls/=d:\winnt\system32
      Or:
    
        /// map c:\projects\windows_xpsp2_dlls\=c:\windows\system32
      Or just as a search path without mapping:
    
        /// map c:\program files\my program
      You need to add the appropriate terminating slashes
    

    - Redefine the environment variables: the environment variables can be redefined in startup.idc

        /// env PATH=c:\windows\system32\;c:\programs    /// env USERPROFILE=c:\Users\Guest
    
      In Linux, if no environment variable is defined in the startup file then no environment strings will be present.
      In Windows, we take the environment variables from the system if none were defined.
    

    - Use native code: it is possible to write a custom Win32/64 DLL and map it into the process space.

    Existing APIs can then be redirected to custom written functions. For example:

      ///func=GetProcAddress entry=bochsys.BxGetProcAddress
      ///func=ExitProcess entry=bochsys.BxExitProcess
      ///func=GetModuleFileNameA entry=bochsys.BxGetModuleFileNameA
      ///func=GetModuleHandleA entry=bochsys.BxGetModuleHandleA
    

    Here we redirect some functions to bochsys.dll that modify the memory space of the application. Please note that bochsys.dll is a special module, IDA is aware of it. Custom functions are declared like this:

      (file name: api_kernel32.idc)
      ///func=GetCommandLineA entry=mydll.GetCommandLineA purge=0
    

    Then in startup.idc file, the following line must be added:

       /// load mydll.dll
    

    Custom DLLs are normal DLLs that can import functions from any other DLL. However, it is advisable that the custom DLL is kept small in size and simple, by not linking it to the runtime libraries.

    - Helper IDC functions: a set of helper IDC functions are available when the debugger is active. For more information, please refer to “startup.idc”.

    - Less demanding PE loader: Most PE files can be loaded and run, including system drivers, DLL and some PE files that cannot be run by the operating system.

    - Dependency resolution: In the PE operation mode, the plugin will recursively load all DLLs referenced by the program. All DLLs that are not explicitly marked with “stub” in startup.idc will be loaded as is. It is important to “stub” all system DLLs for faster loading. The PE loader creates empty stubs for undefined functions in stubbed DLLs. For example, the following line defines a stub that will always return 0 for CreateFileA:

      /// func=CreateFileA retval=0
    

    Since CreateFileA is mentioned in the IDS files and IDA knows how many bytes it purges from the stack, there is no need to specify the “purge” value. For other functions that are not known to IDA, a full definition line would look like:

      /// func=FuncName purge=N_bytes retval=VALUE
    

    - Startup and Exit scripts: It is possible to assign IDC functions that run when the debugging session starts or is about to terminate (before the application continues from the PROCESS_EXITED event). In addition to running code at startup, the startup script serves a role in telling the PE loader which DLLs are to be mapped for the current debugging session. For example:

      /// stub ntdll.dll
      /// stub kernel32.dll
      /// stub user32.dll
      /// stub shell32.dll
      /// stub shlwapi.dll
      /// stub wininet.dll
    

    These lines list the DLLs that will be used during the debugging session. IDA creates empty stubs for all functions from these DLLs. Non-trivial implementations of selected functions can be specified in api_xxxx.idc files, where xxxx is the module name.

    API and startup scripts are searched first in the current directory and then in the ida/plugins/bochs directory.

    - Memory allocation limit: The PE loader has a simple memory manager. It is used for the initial memory allocation at the loading stage and for dynamic memory allocation during the debugging session. No memory limits are applied at the loading stage: the loader will load all modules regardless of their size. However, when the debugging session starts, a limit applies on how much memory can be dynamically allocated. This limit is specified in the debugger specific options as “Max allocatable memory”. Memory allocation will fail once this limit is reached.

    Some notes on bochsys.dll:

    - BxIDACall: This exported function is used as a trap to suspend the code execution in Bochs and perform some actions in IDA. For example, when the target calls kernel32.VirtualAlloc, it is redirected to bochsys.BxVirtualAlloc, which calls BxIDACall, which triggers IDA:

      kernel32.VirtualAlloc -> bochsys.BxVirtualAlloc -> BxIDACall -> IDA bochs plugin
    

    A breakpoint can be set on this function to monitor all API calls that are handled by IDA.

    - BxUndefinedApiCall: This exported function is executed when the application calls an unimplemented function. Setting a breakpoint on it will allow discovering unimplemented functions and eventually implementing them as IDC or DLL functions. It can also be used to determine when unpacking/decryption finishes (provided that all functions used by the unpacker have been defined).

    See also:

    Bochs debugger FAQ

    General:

    - How are breakpoints treated by IDA Bochs Plugin: Bochs debugger does not use breakpoints by inserting 0xCC at the given address. Instead, since it is an emulator, it constantly compares the current instruction pointer against the breakpoint list. Data breakpoints are supported by Bochs and are known as “watchpoints”. If the user creates hardware breakpoints, IDA will automatically create Bochs watchpoints.

    - How to select the Bochs operation mode programmatically: using IDC: it is possible to use process_config_line() function to pass a key=value. For example, process_config_line(“DEFAULT_MODE=1”) will select the disk image operation mode. (Please refer to cfg\dbg_bochs.cfg for list of configurable options).

    - When debugging, IDA undefines instructions: if the “Debugger options / Reconstruct stack” is checked and the stack pointer is in the same segment as the currently executing code, then IDA might undefine instructions. To solve this program, uncheck the reconstruct stack option.

    - How to convert from physical to linear addresses and vice versa: Bochs internal debugger provides two useful commands for this: “info tab” and “page”.

    Disk image operation mode:

    - Data/Software breakpoints are not always triggered: During a debugging session, when a breakpoint is created while the protected mode/paging is enabled, the page table information is used to translate addresses and correctly create the breakpoint. When debugging session is started again, IDA cannot access translation tables to re-create the same breakpoint, thus the breakpoint will be created without any translation information (it will be treated as physical addresses) This is why those breakpoints are not triggered. As a workaround, we suggest disabling those breakpoints and re-enable them when paging is enabled. This problem can also arise when the “use virtual breakpoints” option is enabled.

    IDB/PE operation mode:

    - Cannot map VA: Sometimes, IDA may display a message stating that a given VA could not be mapped. This mainly happens because both IDB/PE operation modes use virtual addresses from 0x0 to 0x9000 and from 0xE0000000 to 0xFFFFFFFF internally. To solve the problem, please rebase the program to another area:

      - IDB operation mode: use Edit, Segment, Rebase program
      - PE operation mode: rebase the input file using a third party utility
    

    PE operation mode:

    - Dynamic DLL loading: sometimes, when running a program, the plugin may attempt to load a DLL that is not declared in the stub or load section of the startup script. In this case, please write down the name of the DLL, then add it to the startup script, and restart the debug session. It is possible to create a local copy, next to your database, of startup scripts so that these scripts will be used with this database only.

    - Disk image loading slow: The disk image produced in the PE operation mode can be as big as 20MB. The reason for this slow loading is most probably because the plugin tries to load all referenced DLLs instead of stubbing them. To fix this, when the process starts, please take note of the loaded DLLs list (using IDA / Modules List) then add the desired module names in the startup.* / “stub” section. See also: Bochs debugger

    Local debugging

    WinDbg Debugger
    WinDbg: Time Travel Debugging
    Linux debugger
    Intel/ARM macOS debugger

    WinDbg Debugger

    The WinDbg debugger plugin uses Microsoft’s Debugging Engine COM interfaces from the Debugging Tools package.

    In order to use the WinDbg debugger plugin, please download the latest debugging tools from https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools.

    The WinDbg debugger can be used to debug local programs as well as remote programs. This is controlled via the connection string in the “Process Option” dialog. If it is left blank, it means that a local debugging is in effect. Otherwise, a debug engine compatible connection string is expected. IDA will display an error message if the connection string could not be accepted: in that case, try using the same connection string with “cdb”, or “windbg” and see if it works.

    Configuration options

    Debugger-specific options can be changed from Debugger -> Debugger options -> Set specific options.

    Windbg debugger plugin has the following configuration options:

    • Debugging mode
      • User mode - Check this option to debug MS Windows applications.
      • Kernel mode debugging - Check this option when debugging the kernel.
      • Non-Invasive user-mode process attach - Check this option to enable attaching to user-mode processes non-invasively.
      • Kernel mode debugging with reconnect and initial break - Select this option
        when debugging a kernel and when the connection string contains ‘reconnect’. This option
        will assure that the debugger breaks as soon as possible after a reconnect.
    • Output flags - These flags tell the debugging engine which kind of output
      messages to display and which to omit.

    ida.cfg options

    WinDbg debugger plugin has the following options that can be configured in cfg/ida.cfg (in the installation folder):

    • DBGTOOLS - This should be configured to point to the same
      folder where Microsoft Debugging Tools are installed. The plugin will try to
      guess where the tools are, but if it fails, a manual intervention will be required.
      If this option is not set, then the plugin will try to use dbgeng.dll from
      MS Windows system folder, while normal debug operations will work, extensions will not.

    Features

    Send commands to the debugger engine

    After the debugging session is started, you can send commands to the debugger engine.

    Use the “.” key to switch to the command line and start typing commands.

    Please note that while it is possible to send any command to the engine, commands that change the execution status should not be used: go (“g”), step (“t”), step into (“p”), etc…

    The WinDbg debugger module adds a new menu item: Debugger -> WinDbg command. It can be used to send arbitrary commands to the debugger engine. The command output is displayed in the output window.

    Symbol information

    If the symbol path is configured properly, then the debugger engine will fetch debug symbols from the appropriate location (symbol server, cache, etc.)

    Example: if the following environment variable is set windbg will download the symbols from the specified paths:

    _NT_SYMBOL_PATH=srv*c:\pdb\_cache*http://msdl.microsoft.com/download/symbols
    

    Multi-processor support

    Debugger Engine will create a virtual thread for each processor that it finds. Similarly, IDA will present these processors as threads.

    Remote debugging support

    It is possible to use the process server “dbgsrv.exe” to enable remote debugging. For example:

    1. Run dbgsrv -t tcp:port=PORT_NUM,server=HOST_NAME

    2. Verify that the server is correctly running by listing all process
      servers on the given HOST_NAME:

      cdb -QR \\HOST_NAME
      
    3. Finally, run IDA and specify the following connection string:

      tcp:port=PORT_NUM,server=HOST_NAME
      

    Use WinDbg extensions

    It is possible to use the extension commands that usually work with WinDbg. Make sure that the “Debugging Tools folder” setting is properly set so that this feature works.

    Kernel debugging

    It is possible to debug the kernel the same way as it is
    done with WinDbg. Simply setup the target kernel and configure the WinDbg plugin by checking the “kernel mode debugging” option and by typing a correct connection string.

    If the user detaches from a kernel session (using Debugger -> Detach from process), the debugged kernel will resume. However, if the user selects Debugger -> Terminate process,
    the kernel will be suspended (it will wait until another client attaches to it).

    Dump files support

    It is possible to load into IDA dump files generated either manually (using the “.dump” command) or crash dumps generated from a crashed process or kernel. For reference, check the windmp file loader.

    After the dump has been loaded, it is possible to run the debugger and investigate the crash by typing WinDbg commands into the command line window.
    For example, one could check the call-stack or use any other WinDbg extension.

    External breakpoints

    It is possible to use the command line to create breakpoints that are not supported by IDA but are supported by the debugging engine. In such cases, any unknown (external) breakpoints will cause IDA to suspend execution when triggered.

    API

    Additional IDC functions provided by the WinDbg debugger

    WinDbg: Time Travel Debugging

    IDA supports WinDbg Time-Travel debugging. When used with a compatible version of WinDbg, you can load a .run file into IDA, similarly to a crash dump.

    Installation

    Only the standalone version of WinDbg supports Time Travel Debugging. The version of WinDbg from Debugging Tools for Windows can not be used to load TTD traces.

    Downloading WinDbg

    You can find the list of current ways to download WinDbg here: https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/

    You can either install WinDbg onto your system or extract it manually.

    Copying WinDbg files

    WinDbg is an AppX package, and Windows by default forbids the execution of files in its installation folder. It is required to copy the files to another directory to use them with IDA.

    You can find the installation directory for WinDbg by opening a PowerShell window and running:

    Get-AppxPackage Microsoft.WinDbg | select InstallLocation
    

    For example, for version 1.2410.110001.0 the path might be C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2410.11001.0_x64__8wekyb3d8bbwe. In general, users do not have access to list the C:\Program Files\WindowsApps folder by default, however it is possible to navigate to the WinDbg subfolder directly by pasting the path into Explorer.

    Please copy the amd64 subdirectory into a directory of your choice and update the DBGTOOLS path in ida.cfg to point to the copied folder. The folder pointed to by DBGTOOLS should contain a dbgeng.dll file.

    Manually extracting WinDbg files

    If you do not want to install WinDbg onto your system, you can instead download and extract it manually by doing the following:

    1. Download the .appinstaller file from https://aka.ms/windbg/download
    2. Open the .appinstaller file as xml in a text editor. Take the value of Uri= on the line containing the <MainBundle definition and download the file specified by it, e.g., from <MainBundle Name="Microsoft.WinDbg" Version="1.2410.11001.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Uri="https://windbg.download.prss.microsoft.com/dbazure/prod/1-2410-11001-0/windbg.msixbundle" /> download the https://windbg.download.prss.microsoft.com/dbazure/prod/1-2410-11001-0/windbg.msixbundle file.
    3. Extract the windbg_win-x64.msix file from the downloaded .msixbundle (it is a zip file with a custom extension)
    4. Extract the amd64 folder from the windbg_win-x64.msix file (it is a zip file with a custom extension)

    Once you have followed these steps, update the DBGTOOLS path in ida.cfg to point to the copied folder. The folder pointed to by DBGTOOLS should contain a dbgeng.dll file.

    Features

    Time travel

    The WinDbg time travel implementation uses a trace file that you later load. Unlike a crash dump you can still continue execution, however this works by navigating through a recorded instruction log. You cannot change registers or affect the program behavior.

    Additional UI actions are available when loading a time travel log. You can use the UI to continue the execution both forwards and backwards by selecting either the normal “Continue” action, or the “Continue backwards” action. Additionally, the “Step into (backwards)”, “Step over (backwards)”, “Run to cursor (backwards)” actions become available, however they do not work with source-level debugging.

    You can access these actions either using the toolbar or from the “Debugger” menu.

    Screenshot with the new actions highlighted

    Commands

    The !positions command can be used to show the current position in the trace.

    The !tt command can be used to travel to a specific position in the trace that you have obtained before.

    For more details, please see the Microsoft documentation page.

    The dx command can be used to query information about the trace, such as memory writes or reads to a specific address. See this tutorial for how to use it.

    Linux debugger

    The Linux debugger has the following particularities and limitations:

    • The debugger server can handle only one IDA client at a time
    • By default, the 64-bit debugger will try to load “libunwind-x86_64.so.8” and “libunwind-ptrace.so.0” in order to help with stack recovery.
    • ARMLinux: hardware breakpoints are not supported
    • ARMLinux: The THUMB mode is not supported

    Configuration options

    Debugger-specific options can be changed from Debugger -> Debugger options -> Set specific options.

    The linux debugger has the following configuration options:

    • Path to libunwind

      • “libunwind-x64_64.so.8” (the default) - the debugger will try to load libunwind “libunwind-x86_64.so.8” + “libunwind-ptrace.so.0” pair using the regular ‘ld’ search path.
      • “libunwind-x64_64.so” (note the lack of “.8” at the end) - like the default, except the debugger will look for “libunwind-x86_64.so” and “libunwind-ptrace.so” (this is particularly useful for working with libunwind “dev” packages)
      • absolute path to “libunwind-x64_64.so.8” or “libunwind-x64_64.so” - the debugger will try to load libunwind only from the provided path.
      • absolute path to “libunwind-x64_64.so[.8]” - the debugger will try to load the two libraries from there (the absolute path to “libunwind-ptrace.so[.0]” will be derived from that of “libunwind-x64_64.so[.8]”)
      • left blank - don’t use libunwind to collect stack traces

      By default this is set to libunwind-x86_64.so meaning the default path will be used to load libunwind-x86_64.so(.8) and libunwind-ptrace.so(.0). If an absolute path is provided, both libraries will be loaded from this path. If left empty, the call stack will be analyzed by IDA and not libunwind.

    See also:

    Intel/ARM macOS debugger

    On macOS, the suggested approach is to use Remote debugging with one of the mac_server* binaries that are shipped with IDA - even when debugging apps on your local machine.

    Using a standalone debug server application makes it easier to get around the codesigning and debugging restrictions that are built into macOS. Note that this is also the approach used by lldb. Internally lldb uses a dedicated debugserver that implements the core debugger engine - so IDA does the same.

    It is possible to use the Local Mac OS X Debugger in ida.app, but you must run IDA as root.

    For a deeper dive into macOS debugging, see our tutorial.

    See also

    Debugger tutorials

    Here you can find a comprehensive set of step-by-step tutorials categorized by different debugging types and platforms.

    General introduction into debugging with IDA

    Local debugging tutorials

    Windows local debugging:

    Linux local debugging:

    Remote debugging tutorials

    PIN Tracer:

    Other specialized debugging tutorials

    Android/Dalvik debugging:

    XNU debugging:

    QEMU debugging:

    Trace and replay debugger features:

    Appcall mechanism:

    Archived tutorials

    Outdated tutorials that no longer apply have been moved to the archive.

    Debugging Dalvik Programs

    Last updated on September 27, 2023 — v0.3

    Preface

    Starting with version 6.6, IDA Pro can debug Android applications written for the Dalvik Virtual Machine. This includes source level debugging too. This tutorial explains how to set up and start a Dalvik debugging session.

    Installing Android Studio

    First of all we have to install the Android SDK from the official site Android Studio.

    Environment Variables

    IDA needs to know where the adb utility resides, and tries various methods to locate it automatically. Usually IDA finds the path to adb, but if it fails then we can define the ANDROID_SDK_HOME or the ANDROID_HOME environment variable to point to the directory where the Android SDK is installed to.

    Android Device

    Start the Android Emulator or connect to the Android device.

    Information about preparing a physical device for development can be found at Using Hardware Devices.

    Check that the device can be correctly detected by adb:

    $ adb devices
    List of devices attached
    emulator-5554 device
    

    Installing the App

    IDA assumes that the debugged application is already installed on the Android emulator/device.

    Please download:

    {% file src=“MyFirstApp.apk.zip” %}

    and

    {% file src=“MyFirstApp.src.zip” %}

    from our site. We will use this application in the tutorial.

    We will use adb to install the application:

    $ adb -s emulator-5554 install MyFirstApp.apk
    

    Loading Application into IDA

    IDA can handle both .apk app bundles, or just the contained .dex files storing the app’s bytecode. If we specify an .apk file, IDA can either extract one of the contained .dex files by loading it with the ZIP load option, or load all classes*.dex files when using the APK loader.

    dalvik apk loader

    Dalvik Debugger Options

    The main configuration of the dalvik debugger happens resides in “Debugger > Debugger Options > Set specific options”:

    dalvik options

    Connection Settings

    ADB executable

    As mentioned above IDA tries to locate the adb utility. If IDA failed to find it then we can set the path to adb here.

    Connection string

    Specifies the argument to the adb connect command. It is either empty (to let adb figure out a meaningful target) or a <host>[:<port>] combination to connect to a remote device somewhere on the network.

    Emulator/device serial number

    Serial number of an emulator or a device. Passed to adb``'s -s option. This option is useful if there are multiple potential target devices running. For the official Android emulator, it is typically emulator-5554.

    Start Application

    Fill from AndroidManifest.xml

    Press button and point IDA to either the APK or the AndroidManifest.xml file of the mobile app. IDA then automatically fetches the package name and application start activity, as well as the debuggable flag from the specified file.

    Package Name

    Package name containing the activity to be launched by the debugger.

    Activity

    Start activity to be launched by the debugger.

    Alternative Start Command

    Usually IDA builds the start command from the package and activity name and launches the APK from the command line as follows:

    am start -D -n '<package>/<activity>' -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
    

    If that does not match your desired debugging setup, you can enter an alternative start command here. Note that you have to provide package and activity as part of the startup command.

    APK Debuggable

    The value of the debuggable flag, as extracted from the AndroidManifest.xml or the APK. APKs that do not have the debuggable flag set (most do not) cannot be started on unpatched phones. Hence, while this value is false, IDA will display a (silencable) warning when starting a debugging session. To produce a debuggable APK that has the flag set to true, please revert to third-party tooling.

    Detect Local Variable Types

    This controls the behavior of IDA’s type guessing engine. “Always” and “Never” are pretty self-explanatory: The options force-enable or force-disable type guessing. “Auto” means that type guessing is disabled for Android APIs < 28 and enabled on APIs >= 28. If you work with very old (i.e. API 23 and lower) Android devices and experience crashes during debugging, set this option to “Never”. Note that when type guessing is disabled, IDA automatically assumes int for unknown variable types, which causes warnings on API 30 and above.

    Local Variables with Type Guessing Deactivated

    dalvik type guessing off

    Local Variables with Type Guessing Activated

    dalvik type guessing on

    Other Options

    Show object ID

    If active, IDA shows the object ID assigned by the Java VM for composite (non-trivial) types in the local variables window.

    Preset BPTs

    If active, IDA sets breakpoints at the beginning of all (non-synthetic, non-empty) methods of the start activity class specified in the Activity field above.

    Path to Sources

    To use source-level debugging we have to set paths to the application source files. We can do it using the “Options > Sources path” menu item.

    Our Dalvik debugger presumes that the application sources reside in the current (“.”) directory. If this is not the case, we can map current directory (“.”) to the directory where the source files are located.

    Let us place the source files DisplayMessageActivity.java and MainActivity.java in the same directory as the MyFirstApp.apk package. This way we do not need any mapping.

    Setting Breakpoints

    Before launching the application it is reasonable to set a few breakpoints. We can rely on the decision made by IDA (see above the presetBPTs option) or set breakpoints ourselves. A good candidate is the onCreate method of the application’s main activity.

    We can use the activity name and the method name onCreate to set a breakpoint:

    dalvik names

    Naturally, we can set any other breakpoints any time. For example, we can do it later, when we suspend the application.

    Starting the Debugger

    At last we can start the debugger. Check that the Dalvik debugger backend is selected. Usually it should be done automatically by IDA:

    dalvik debugger slct

    If the debugger backend is correct, we are ready to start a debugger session. There are two ways to do it:

    • Launch a new copy of the application (Start process)
    • Attach to a running process (Attach to process)

    Launching the App

    To start a new copy of the application just press <F9> or use the “Debugger > Start process” menu item. The Dalvik debugger will launch the application, wait until application is ready and open a debugger session to it.

    We may wait for the execution to reach a breakpoint or press the “Cancel” button to suspend the application.

    In our case let us wait until execution reach of onCreate method breakpoint.

    Attaching to a Running App

    Instead of launching a new process we could attach to a running process and debug it. For that we could have selected the “Debugger > Attach to process…​” menu item. IDA will display a list of active processes.

    dalvik attach

    We just select the process we want to attach to.

    Particularities of Dalvik Debugger

    All traditional debug actions like Step into, Step over, Run until return and others can be used. If the application sources are accessible then IDA will automatically switch to the source-level debugging.

    Below is the list of special things about our Dalvik debugger:

    • In Dalvik there is no stack and there is no SP register. The only available register is IP.
    • The method frame registers and slots (v0, v1, …​) are represented as local variables in IDA. We can see them in the “Debugger > Debugger Windows > Locals” window (see below)
    • The stack trace is available from “Debugger > Debugger windows > Stack trace” (the hot key is <Ctrl-Alt-S>).
    • When the application is running, it may execute some system code. If we break the execution by clicking on the “Cancel” button, quite often we may find ourselves outside of the application, in the system code. The value of the IP register is 0xFFFFFFFF in this case, and stack trace shows only system calls and a lot of 0xFFFFFFFF. It means that IDA could not locate the current execution position inside the application. We recommend to set more breakpoints inside the application, resume the execution and interact with application by clicking on its windows, selecting menu items, etc. The same thing can occur when we step out the application.
    • Use “Run until return” command to return to the source-level debugging if you occasionally step into a method and the value of the IP register becomes 0xFFFFFFFF.

    Locals Window

    IDA considers the method frame registers, slots, and variables (v0, v1, …​) as local variables. To see their values we have to open the “Locals” window from the “Debugger > Debugger windows > Locals” menu item.

    At the moment the debugger stopped the execution at the breakpoint which we set on onCreate method.

    dalvik stop bpt

    Perform “Step over” action (the hot key is <F8>) two times and open the “Locals” window, we will see something like the following:

    dalvik locals

    If information about the frame is available (the symbol table is intact) or type guessing is enabled then IDA shows the method arguments, the method local variables with names and other non-named variables. Otherwise some variable values will not be displayed because IDA does not know their types.

    Variables without type information are marked with “Bad type” in the “Locals” window. To see the variable value in this case please use the “Watch view” window and query them with an explicit type (see below).

    Watch View Window

    To open the “Watch view” window select the “Debugger > Debugger windows > Watch view” menu item. In this window we can add any variable to watch its value.

    dalvik watches

    note that we have to specify type of variable if it is not known. Use C-style casts:

    • (Object*)v0
    • (String)v6
    • (char*)v17
    • (int)v7

    We do not need to specify the real type of an object variable, the “(Object*)” cast is enough. IDA can derive the real object type itself.

    Attention! On Android API versions 23 and below an incorrect type may cause the Dalvik VM to crash. There is not much we can do about it. Our recommendation is to never cast an integer variable to an object type, the Dalvik VM usually crashes if we do that. But the integer cast “(int)” is safe in practice.

    Keeping the above in the mind, do not leave the cast entries in the “Watch view” window for a long time. Delete them before any executing instruction that may change the type of the watched variable.

    Overall we recommend to debug on a device that runs at least Android API 24.

    Troubleshooting

    • Check the path to adb in the “Debugger specific options”
    • Check the package and activity names
    • Check that the emulator is working and was registered as an adb device. Try to restart the adb daemon.
    • Check that the application was successfully installed on the emulator/device
    • Check the output window of IDA for any errors or warnings
    • Turn on more debug print in IDA with the -z50000 command line switch.
    • Android APIs 24 and 25 are known to return wrong instruction sizes during single stepping. Try migrating to a different Android API if you have trouble with single steps.
    • IDA exposes a subset of the JDWP specification as IDC commands. (Usually the name from the specification prefixed with JDWP_).
    • Android APIs 23 and below crash if type guessing is enabled. Remedy this by setting the Detect Local Variable Types option to Never or migrate to a newer Android API.

    IDA Win32 Local Debugging

    The IDA Debugger allows you to either start a new process (Run) or attach itself to an existing process (Attach)

    instant_debugger_menu

    Let’s select “Local Windows debugger”. What we get is a list of currently running processes to which we can attach with a simple click.

    connect_to_local

    and here is the result once we are attached to the program.

    attached_to_local

    IDA Linux Local Debugging

    Debugging Linux Applications with IDA Pro, locally

    Last updated on July 29, 2020 — v0.1

    You may already know that IDA lets you debug an application from an already existing IDB, by selecting the debugger using the drop-down debugger list.

    drop down debugger list

    However, it is also possible to start IDA in a way that it will initially create an empty IDB, and then either:

    • start a new process under its control
    • attach to an existing process

    Launch IDA with a fresh new process

    To do so, you will have to launch IDA from the command line, like so:

    ida -rlinux /bin/ls
    

    IDA will then launch the /bin/ls program, and break at its entrypoint

    starting new process

    Attaching IDA to an existing process

    For this example, we’ll launch, from a shell, a /usr/bin/yes process, and attach to.

    Now, we’ll launch IDA so it offers a selection of processes to (and use quick filtering (Ctrl+F) to quickly find our process):

    ida -rlinux+
    
    attaching to process

    IDA will then attach to the selected process, and leave it suspended at the place it was when it was attached to:

    attached to process

    IDA Linux to Win64 Debugging

    One of the fanciest options offered by the IDA 4.8 debugger is the debugging of Windows executables from a Linux machine. The 64 bits remote debugging server is started on the Windows64 machine.

    and IDA for Linux is started with the following command line

    idat [email protected]+

    the command line switch specifies the debugger type (windows in this case), the machine name/IP (192.168.1.56) and the last + specifies that a list of running processes will be requested from the target machine. IDA will then display that list and you’ll be able to connect to processes on the Windows64 machine.

    and here is the 64 bit program, ready to be debugged under Linux.

    IDA Win32 to Linux Debugging

    Connecting a Windows Debuging session to a Linux machine is essentially similar to a Windows to Windows connection. The Linux remote debugger server is started on the command line.

    then connect to the Linux Machine by selecting the attach to remote Linux command. We can then select the process we want to debug and connect to it with a simple click.

    we are now connected to the remote process running on the Linux machine.

    Debugging Mac OSX Applications with IDA Pro

    Debugging Mac OSX Applications with IDA Pro

    Last updated on March 6, 2021 — v2.0

    Overview

    IDA Pro fully supports debugging native macOS applications.

    Intel x86/64 debugging has been supported since IDA 5.6 (during OSX 10.5 Leopard), but due to IDA’s use of libc++ we can only officially support debugging on OSX 10.9 Mavericks and later. Apple Silicon arm64 debugging for macOS11 is also supported since IDA 7.6.

    Note that this task is riddled with gotchas, and often times it demands precise workarounds that are not required for other platforms. In this tutorial we will purposefully throw ourselves into the various pitfalls of debugging on a Mac, in the hopes that learning things the hard way will ultimately lead to a smoother experience overall.

    Begin by downloading samples:

    {% file src=“samples.zip” %}

    which contains the sample applications used in this writeup.

    Codesigning & Permissions

    It is important to note that a debugger running on macOS requires special permissions in order to function properly. This means that the debugger itself must be codesigned in such a way that MacOS allows it to inspect other processes.

    The main IDA Pro application is not codesigned in this way. Later on we’ll discuss why.

    To quickly demonstrate this, let’s open a binary in IDA Pro and try to debug it. In this example we’ll be debugging the helloworld app from samples.zip:

    {% file src=“samples.zip” %}

    on MacOSX 10.15 Catalina using IDA 7.5. Begin by loading the file in IDA:

    $ alias ida64="/Applications/IDA\ Pro\ 7.5/ida64.app/Contents/MacOS/ida64"
    $ ida64 helloworld
    

    Now go to menu Debugger>Select debugger and select Local Mac OS X Debugger:

    choose mac debugger

    Immediately IDA should print a warning message to the Output window:

    This program must either be codesigned or run as root to debug mac applications.
    

    This is because IDA is aware that it is not codesigned, and is warning you that attempting to debug the target application will likely fail. Try launching the application with shortcut F9. You will likely get this error message:

    elevated permissions

    Codesigning IDA Pro might resolve this issue, but we have purposefully decided not to do this. Doing so would require refactoring IDA’s internal plugin directory structure so that it abides by Apple’s bundle structure guidelines. This would potentially break existing plugins as well as third-party plugins written by users. We have no plans to inconvenience our users in such a way.

    Also note that running IDA as root will allow you to use the Local Mac OS X Debugger without issue, but this is not advisable.

    A much better option is to use IDA’s mac debug server - discussed in detail in the next section.

    Using the Mac Debug Server

    A good workaround for the debugging restrictions on macOS is to use IDA’s debug server - even when debugging local apps on your mac machine. The mac debug server is a standalone application that communicates with IDA Pro via IPC, so we can ship it pre-codesigned and ready for debugging right out of the box:

    $ codesign -dvv /Applications/IDA\ Pro\ 7.5/idabin/dbgsrv/mac_server64
    Executable=/Applications/IDA Pro 7.5/ida.app/Contents/MacOS/dbgsrv/mac_server64
    Identifier=com.hexrays.mac_serverx64
    Format=Mach-O thin (x86_64)
    CodeDirectory v=20100 size=6090 flags=0x0(none) hashes=186+2 location=embedded
    Signature size=9002
    Authority=Developer ID Application: Hex-Rays SA (ZP7XF62S2M)
    Authority=Developer ID Certification Authority
    Authority=Apple Root CA
    Timestamp=May 19, 2020 at 4:13:31 AM
    

    Let’s try launching the server:

    $ /Applications/IDA\ Pro\ 7.5/idabin/dbgsrv/mac_server64
    IDA Mac OS X 64-bit remote debug server(MT) v7.5.26. Hex-Rays (c) 2004-2020
    Listening on 0.0.0.0:23946...
    

    Now go back to IDA and use menu Debugger>Switch debugger to switch to remote debugging:

    switch debugger

    Now use Debugger>Process options to set the Hostname and Port fields to localhost and 23946.

    (Note that the port number was printed by mac_server64 after launching it):

    process options1

    Also be sure to check the option Save network settings as default so IDA will remember this configuration.

    Now go to _main in the helloworld disassembly, press F2 to set a breakpoint, then F9 to launch the process. Upon launching the debugger you might receive this prompt from the OS:

    developer tools

    macOS is picky about debugging permissions, and despite the fact that mac_server is properly codesigned you still must explicitly grant it permission to take control of another process. Thankfully this only needs to be done once per login session, so macOS should shut up until the next time you log out (we discuss how to disable this prompt entirely in the Debugging Over SSH section below).

    After providing your credentials the debugger should start up without issue:

    helloworld

    Using a Launch Agent

    To simplify using the mac server, save the following XML as com.hexrays.mac_server64.plist in ~/Library/LaunchAgents/:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.hexrays.mac_server64</string>
        <key>ProgramArguments</key>
        <array>
            <string>/Applications/IDA Pro 7.5/dbgsrv/mac_server64</string>
            <string>-i</string>
            <string>localhost</string>
        </array>
        <key>StandardOutPath</key>
        <string>/tmp/mac_server64.log</string>
        <key>StandardErrorPath</key>
        <string>/tmp/mac_server64.log</string>
        <key>KeepAlive</key>
        <true/>
    </dict>
    </plist>
    

    Now mac_server64 will be launched in the background whenever you log in. You can connect to it from IDA at any time using the Remote Mac OS X Debugger option. Hopefully this will make local debugging on macOS almost as easy as other platforms.

    Debugging System Applications

    There are some applications that macOS will refuse to allow IDA to debug.

    For example, load /System/Applications/Calculator.app/Contents/MacOS/Calculator in IDA and try launching the debugger. You will likely get this error message:

    permission denied

    Despite the fact that mac_server64 is codesigned, it still failed to retrieve permission from the OS to debug the target app. This is because Calculator.app and all other apps in /System/Applications/ are protected by System Integrity Protection and they cannot be debugged until SIP is disabled. Note that the error message is a bit misleading because it implies that running mac_server64 as root will resolve the issue - it will not. Not even root can debug apps protected by SIP.

    Disabling SIP allows IDA to debug applications like Calculator without issue:

    calc

    The effects of SIP are also apparent when attaching to an existing process. Try using menu Debugger>Attach to process, with SIP enabled there will likely only be a handful of apps that IDA can debug:

    proclist1

    Disabling SIP makes all system apps available for attach:

    proclist2

    It is unfortunate that such drastic measures are required to inspect system processes running on your own machine, but this is the reality of MacOS. We advise that you only disable System Integrity Protection when absolutely necessary, or use a virtual machine that can be compromised with impunity.

    Debugging System Libraries

    With IDA you can debug any system library in /usr/lib/ or any framework in /System/Library/.

    This functionality is fully supported, but surprisingly it is one of the hardest problems the mac debugger must handle. To demonstrate this, let’s try debugging the _getaddrinfo function in libsystem_info.dylib.

    Consider the getaddrinfo application from samples.zip:

    {% file src=“samples.zip” %}

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
      if ( argc != 2 )
      {
        fprintf(stderr, "usage: %s <hostname>\n", argv[0]);
        return 1;
      }
    
      struct addrinfo hints;
      memset(&hints, 0, sizeof(hints));
    
      hints.ai_family = AF_INET;
      hints.ai_flags |= AI_CANONNAME;
    
      struct addrinfo *result;
      int code = getaddrinfo(argv[1], NULL, &hints, &result);
      if ( code != 0 )
      {
        fprintf(stderr, "failed: %d\n", code);
        return 2;
      }
    
      struct sockaddr_in *addr_in = (struct sockaddr_in *)result->ai_addr;
      char *ipstr = inet_ntoa(addr_in->sin_addr);
      printf("IP address: %s\n", ipstr);
    
      return 0;
    }
    

    Try testing it out with a few hostnames:

    $ ./getaddrinfo localhost
    IP address: 127.0.0.1
    $ ./getaddrinfo hex-rays.com
    IP address: 104.26.10.224
    $ ./getaddrinfo foobar
    failed: 8
    

    Now load libsystem_info.dylib in IDA and set a breakpoint at _getaddrinfo:

    $ ida64 -o/tmp/libsystem_info /usr/lib/system/libsystem_info.dylib
    
    getaddrinfo bpt

    Choose Remote Mac OS X Debugger from the Debugger menu and under Debugger>Process options be sure to provide a hostname in the Parameters field. IDA will pass this argument to the executable when launching it:

    process options2

    Before launching the process, use Ctrl+S to pull up the segment list for libsystem_info.dylib. Pay special attention to the __eh_frame and __nl_symbol_ptr segments. Note that they appear to be next to each other in memory:

    segments1

    This will be important later.

    Finally, use F9 to launch the debugger and wait for our breakpoint at _getaddrinfo to be hit. We can now start stepping through the logic:

    getaddrinfo bpt2

    Everything appears to be working normally, but use Ctrl+S to pull up the segment information again. We can still see __eh_frame, but it looks like __nl_symbol_ptr has gone missing:

    segments2

    It is actually still present, but we find it at a much higher address:

    segments3

    Recall that we opened the file directly from the filesystem (/usr/lib/system/libsystem_info.dylib). However this is actually not the file that macOS loaded into memory. The libsystem_info image in process memory was mapped in from the dyld_shared_cache, and the library’s segment mappings were modified before it was inserted into the cache.

    IDA was able to detect this situation and adjust the database so that it matches the layout in process memory. This functionality is fully supported, but it is not trivial. Essentially the debugger must split your database in half, rebase all code segments to one address, then rebase all data segments to a completely different address.

    It is worth noting there is another approach that achieves the same result, but without so much complexity.

    Debugging Modules in dyld_shared_cache

    As an alternative for the above example, note that you can load any module directly from a dyld_shared_cache file and debug it. For example, open the shared cache in IDA:

    $ ida64 -o/tmp/libsystem_info2 /var/db/dyld/dyld_shared_cache_x86_64h
    

    When prompted, select the “single module” option:

    dyld1

    Then choose the libsystem_info module:

    dyld2

    Select the Remote Mac OS X Debugger and for Debugger>Process options use the exact same options as before:

    process options2

    Now set a breakpoint at _getaddrinfo and launch the process with F9.

    After launching the debugger you might see this warning:

    dyld3

    This is normal. Modules from the dyld_shared_cache will contain tagged pointers, and IDA patched the pointers when loading the file so that analysis would not be hindered by the tags. IDA is warning us that the patches might cause a discrepancy between the database and the process, but in this case we know it’s ok. Check Don’t display this message again and don’t worry about it.

    Launching the process should work just like before, and we can start stepping through the function in the shared cache:

    dyld4

    This time there was no special logic to map the database into process memory. Since we loaded the module directly from the cache, segment mappings already match what’s expected in the process. Thus only one rebasing operation was required (as apposed to the segment scattering discussed in the previous example).

    Both techniques are perfectly viable and IDA goes out of its way to fully support both of them. In the end having multiple solutions to a complex problem is a good thing.

    Debugging Objective-C Applications

    When debugging macOS applications it is easy to get lost in some obscure Objective-C framework. IDA’s mac debugger provides tools to make debugging Objective-C code a bit less painful.

    Consider the bluetooth application from samples.zip:

    {% file src=“samples.zip” %}

    #import <IOBluetooth/IOBluetooth.h>
    
    int main(void)
    {
      NSArray *devices = [IOBluetoothDevice pairedDevices];
      int count = [devices count];
      for ( int i = 0; i < count; i++ )
      {
        IOBluetoothDevice *device = [devices objectAtIndex:i];
        NSLog(@"%@:\n", [device name]);
        NSLog(@"  paired:    %d\n", [device isPaired]);
        NSLog(@"  connected: %d\n", [device isConnected]);
      }
      return 0;
    }
    

    The app will print all devices that have been paired with your host via Bluetooth. Try running it:

    $ ./bluetooth
    2020-05-22 16:27:14.443 bluetooth[17025:15645888] Magic Keyboard:
    2020-05-22 16:27:14.443 bluetooth[17025:15645888]   paired:    1
    2020-05-22 16:27:14.443 bluetooth[17025:15645888]   connected: 1
    2020-05-22 16:27:14.443 bluetooth[17025:15645888] Apple Magic Mouse:
    2020-05-22 16:27:14.443 bluetooth[17025:15645888]   paired:    1
    2020-05-22 16:27:14.443 bluetooth[17025:15645888]   connected: 1
    2020-05-22 16:27:14.443 bluetooth[17025:15645888] iPhone SE:
    2020-05-22 16:27:14.443 bluetooth[17025:15645888]   paired:    0
    2020-05-22 16:27:14.443 bluetooth[17025:15645888]   connected: 0
    

    Let’s try debugging this app. First consider the call to method +[IOBluetoothDevice pairedDevices]:

    objc1

    If we execute a regular instruction step with F7, IDA will step into the _objc_msgSend function in libobjc.A.dylib, which is probably not what we want here. Instead use shortcut Shift+O. IDA will automatically detect the address of the Objective-C method that is being invoked and break at it:

    objc2

    This module appears to be Objective-C heavy, so it might be a good idea to extract Objective-C type info from the module using right click -> Load debug symbols in the Modules window:

    objc3

    This operation will extract any Objective-C types encoded in the module, which should give us some nice prototypes for the methods we’re stepping in:

    objc4

    Let’s continue to another method call - but this time the code invokes a stub for _objc_msgSend that IDA has not analyzed yet, so its name has not been properly resolved:

    objc5

    In this case Shift+O should still work:

    objc6

    Shift+O is purposefully flexible so that it can be invoked at any point before a direct or indirect call to _objc_msgSend. It will simply intercept execution at the function in libobjc.A.dylib and use the arguments to calculate the target method address.

    However, you must be careful. If you use this action in a process that does not call _objc_msgSend, you will lose control of the process. It is best to only use it when you’re certain the code is compiled from Objective-C and an _objc_msgSend call is imminent.

    Decompiling Objective-C at Runtime

    The Objective-C runtime analysis performed by Load debug symbols will also improve decompilation.

    Consider the method -[IOBluetoothDevice isConnected]:

    objc8

    Before we start stepping through this method we might want to peek at the pseudocode to get a sense of how it works. Note that the Objective-C analysis created local types for the IOBluetoothDevice class, as well as many other classes:

    objc7

    This type info results in some sensible pseudocode:

    objc9

    We knew nothing about this method going in - but it’s immediately clear that device connectivity is determined by the state of an io_service_t handle in the IOBluetoothObject superclass, and we’re well on our way.

    Debugging Over SSH

    In this section we will discuss how to remotely debug an app on a mac machine using only an SSH connection. Naturally, this task introduces some unique complications.

    To start, copy the mac_server binaries and the bluetooth app from samples.zip:

    {% file src=“samples.zip” %}

    to the target machine:

    $ scp <IDA install dir>/dbgsrv/mac_server* user@remote:
    $ scp bluetooth user@remote:
    

    Now ssh to the target machine and launch the mac_server:

    $ ssh user@remote
    user@remote:~$ ./mac_server64
    IDA Mac OS X 64-bit remote debug server(MT) v7.5.26. Hex-Rays (c) 2004-2020
    Listening on 0.0.0.0:23946...
    

    Now open the bluetooth binary on the machine with your IDA installation, select Remote Mac OS X Debugger from the debugger menu, and for Debugger>Process options set the debugging parameters. Be sure to replace <remote user> and <remote ip> with the username and ip address of the target machine:

    process options3

    Try launching the debugger with F9. You might get the following error message:

    permission denied

    This happened because debugging requires manual authentication from the user for every login session (via the Take Control prompt discussed under Using the Mac Debug Server, above).

    But since we’re logged into the mac via SSH, the OS has no way of prompting you with the authentication window and thus debugging permissions are refused.

    Note that mac_server64 might have printed this workaround:

    WARNING: The debugger could not acquire the necessary permissions from the OS to
    debug mac applications. You will likely have to specify the proper credentials at
    process start. To avoid this, you can set the MAC_DEBMOD_USER and MAC_DEBMOD_PASS
    environment variables.
    

    But this is an extreme measure. As an absolute last resort you can launch the mac_server with your credentials in the environment variables, which should take care of authentication without requiring any interaction with the OS. However there is a more secure workaround.

    In your SSH session, terminate the mac_server process and run the following command:

    $ security authorizationdb read system.privilege.taskport > taskport.plist
    

    Edit taskport.plist and change the authenticate-user option to false:

    <key>authenticate-user</key>
    <false/>
    

    Then apply the changes:

    $ sudo security authorizationdb write system.privilege.taskport < taskport.plist
    

    This will completely disable the debugging authentication prompt (even across reboots), which should allow you to use the debug server over SSH without macOS bothering you about permissions.

    Dealing With Slow Connections

    When debugging over SSH you might experience some slowdowns. For example you might see this dialog appear for several seconds when starting the debugger:

    symbols1

    During this operation IDA is fetching function names from the symbol tables for all dylibs that have been loaded in the target process. It is a critical task (after all we want our stack traces to look nice), but it is made complicated by the sheer volume of dylibs loaded in a typical macOS process due to the dyld_shared_cache. This results in several megabytes of raw symbol names that mac_server must transmit over the wire every time the debugger is launched.

    We can fix this by using the same trick that IDA’s Remote iOS Debugger uses to speed up debugging - by extracting symbol files from the dyld cache and parsing them locally. Start by downloading the ios_deploy utility from our download center, and copy it to the remote mac:

    $ scp ios_deploy user@remote:
    

    Then SSH to the remote mac and run it:

    $ ./ios_deploy symbols -c /var/db/dyld/dyld_shared_cache_x86_64h -d mac_symbols
    Extracting symbols from /var/db/dyld/dyld_shared_cache_x86_64h => mac_symbols
    Extracting symbol file: 1813/1813
    mac_symbols: done
    $ zip -r mac_symbols.zip mac_symbols
    

    Copy mac_symbols.zip from the remote machine to your host machine and unzip it. Then open Debugger>Debugger options>Set specific options and set the Symbol path field:

    symbols2

    Now try launching the debugger again, it should start up much faster.

    Also keep the following in mind:

    • Use /var/db/dyld/dyld_shared_cache_i386 if debugging 32-bit apps
    • You must perform this operation after every macOS update. Updating the OS will update the dyld_shared_cache, which invalidates the extracted symbol files.
    • The ios_deploy utility simply invokes dyld_shared_cache_extract_dylibs_progress from the dsc_extractor.bundle library in Xcode. If you don’t want to use ios_deploy there are likely other third-party tools that do something similar.

    Debugging arm64 Applications on Apple Silicon

    IDA 7.6 introduced the ARM Mac Debugger, which can debug any application that runs natively on Apple Silicon.

    On Apple Silicon, the same rules apply (see Codesigning & Permissions above). The Local ARM Mac Debugger can only be used when run as root, so it is better to use the Remote ARM Mac Debugger with the debug server (mac_server_arm64), which can debug any arm64 app out of the box (see Using the Mac Debug Server).

    We have included arm64 versions of the sample binaries used in the previous examples. We encourage you to go back and try them. They should work just as well on Apple Silicon.

    Debugging arm64e System Applications

    Similar to Intel Macs, IDA cannot debug system apps on Apple Silicon until System Integrity Protection is disabled.

    But here macOS introduces another complication. All system apps shipped with macOS are built for arm64e - and thus have pointer authentication enabled. This is interesting because ptruath-enabled processes are treated much differently within the XNU kernel. All register values that typically contain pointers (PC, LR, SP, and FP) will be signed and authenticated by PAC.

    Thus, if a debugger wants to modify the register state of an arm64e process, it must know how to properly sign the register values. Only arm64e applications are allowed to do this (canonically, at least).

    You may have noticed that IDA 7.6 ships with two versions of the arm64 debug server:

    arm64e1

    mac_server_arm64e is built specifically for the arm64e architecture, and thus will be able to properly inspect other arm64e processes. We might want to try running this version right away, but by default macOS will refuse to run any third-party software built for arm64e:

    arm64e2

    According to Apple, this is because the arm64e ABI is not stable enough to be used generically. In order to run third-party arm64e binaries you must enable the following boot arg:

    $ sudo nvram boot-args=-arm64e_preview_abi
    

    After rebooting you can finally run mac_server_arm64e:

    arm64e3

    This allows you to debug any system application (e.g. /System/Applications/Calculator.app) without issue:

    arm64e4
    arm64e5

    Also note that the arm64e ABI limitation means you cannot use the Local ARM Mac Debugger to debug system arm64e apps, since IDA itself is not built for arm64e. It is likely that Apple will break the arm64e ABI in the future and IDA might cease to work. We want to avoid this scenario entirely.

    Using the Remote ARM Mac Debugger with mac_server_arm64e is a nice workaround. It guarantees ida.app will continue to work normally regardless of any breakages in the arm64e ABI, and we can easily ship new arm64e builds of the server to anybody who needs it.

    Apple Silicon: TL;DR

    To summarize:

    • Use mac_server_arm64 if you’re debugging third-party arm64 apps that aren’t protected by SIP
    • Use mac_server_arm64e if you’re feeling frisky and want to debug macOS system internals. You must disable SIP and enable nvram boot-args=-arm64e_preview_abi, then you can debug any app you want (arm64/arm64e apps, system/non-system apps, shouldn’t matter).

    Support

    If you have any questions about this writeup or encounter any issues with the debugger itself in your environment, don’t hesitate to contact our support.

    Our Mac support team has years of experience keeping the debugger functional through rapid changes in the Apple developer ecosystem. It is likely that we can resolve your issue quickly.

    Debugging iOS Applications using CoreDevice (iOS 17 and up)

    This guide shows a walkthrough of how one can use IDA Pro to debug an app installed using Xcode on a device running iOS 17 or iOS 18. The pre-debugging setup is specific to non-jailbroken devices running iOS 18 with a macOS host but the steps in IDA can be reused for most iOS/iPadOS targets (jailbroken, Corellium) with a different platform as the host. The iOS debugger is available with all platforms IDA supports though due to Apple’s iOS tools being available on macs only, the workflow is easier on macOS.

    Tested on macOS 15.0 (24A335) using Xcode 16.0 (16A242) with an iPhone 11 running iOS 18.0 (22A3354).

    1. Installing an app on a non-jailbroken device

    Since it’s the simplest way to install an app onto an iOS device, we’ll be using Xcode to quickly build and install a sample app onto our target device.

    Create an iOS Game app by choosing the appropriate template:

    Xcode template selection dialog with iOS Game selected

    Enter a Product name, make note of the resulting Bundle Identifier. For the scope of this guide, the rest of the project options aren’t relevant.

    Xcode project options dialog with “spritegame” as the Product Name and the Bundle Identifier “com.acme.spritegame” highlighted in red

    In the main Xcode window, ensure that the appropriate target device (Run Destinations) is selected.

    Xcode target device selection with an iPhone “red_iphone11” selected

    If the device hasn’t been paired, a warning may appear requesting you to accept the “Trust” prompt on the device to pair with the host. If the device hasn’t been used for development recently, Xcode will install a Developer Disk Image to enable development services. It will also copy and extract the shared cache symbols to the host (in ~/Library/Developer/Xcode/iOS DeviceSupport/<device_and_os_version>/).

    If you try to Run (clicking on the “play” icon or using CMD-R) the app, an error may appear prompting you to select a development team. Xcode requires that a developer certificate is selected for the signing of the application.

    Xcode error: “Signing for “spritegame” requires a development team. Select a development team in the Signing & Capabilities editor.“

    The developer team can be selected via the Signing & Capabilities editor.

    Xcode Signing & Capabilities editor with an arrow pointing at the selected team

    Now that a developer certificate was selected for the app, it must also be trusted on the device. If you attempt to Run the app, another warning should appear prompting you to trust the certificate on the device. (Please follow those instructions to trust that certificate)

    Xcode error: “The request to open “com.acme.spritegame” failed.“ “Verify that the Developer App certificate for your account is trusted on your device. Open Settings on the device and navigate to General -> VPN & Device Management, then select your Developer App certificate to trust it.”

    Finally, Run the app and ensure that it starts properly on the target device.

    Xcode bar showing that spritegame is running on red_iphone11

    2. Setting up the debug environment, launching the app

    Debugging an application on an iPhone is enabled by the debugserver that will attach to the application’s process. The debugserver communicates with clients using (an extended version of) the GDB protocol. IDA comes with an iOS debugger that can “talk” that same protocol. The techniques necessary to prepare the debugging environment on an iPhone have evolved over time (and will likely keep evolving) but fundamentally the goal is always to establish a connection with a debugserver.

    The device communication stack was revamped with iOS 17. Devices expose a series of remote services (through remoted which is visible via Bonjour). One of those services is a debugproxy which is… a proxy to the debugserver. debugproxy is a secure service, it is not available to any client. To gain access to secure services, a trusted tunnel must be setup (requires the device to be paired with the host), between the host and the device (the service to set up the tunnel is itself available via remoted).

    One of the primary frameworks used for these communications is CoreDevice, with it Apple also provides devicectl which is a very convenient utility that can be used to automate certain tasks to control devices. We will use devicectl to perform certain tasks such as launching an application on the device. Unfortunately devicectl doesn’t provide a direct interface to setup a trusted tunnel and retrieve ports of services exposed through it. It is however possible to reuse some commands of devicectl to create a tunnel and keep it open. In addition, the ports of services are written to system logs after the tunnel is set up so we can recover them with a few tricks.

    To make commands provided below immediately usable, we’ll define two helper environment variables. The device name is the same as the one that was used for the target device in Xcode, it can also be found using xcrun devicectl list devices. The bundle identifier is the identifier of the application we’d like to debug

    export DEVICE_NAME="red_iphone11"
    export BUNDLE_ID="com.acme.spritegame"
    

    Trigger the creation of a trusted tunnel

    To request the creation of the trusted tunnel, the devicectl device notification observe command was selected because it can keep the tunnel open for an arbitrary amount of time (controlled using the timeout). Here the name for the Darwin notification (‘foobar’) to observe is one that will presumably never be posted. The timeout (3000[s]) was chosen to be long enough for a debugging session.

    Retrieve the details of the debugproxy service (provided through the trusted tunnel) from the system logs. The command below will filter for the specific log messages we’re looking for (ipv6 address of device through tunnel and port of debugproxy service). In short log show (see log(1)) will show messages from the system logs; --last 5m will limit the search to the past 5 minutes (the tunnel should have been created when the previous command was started so 5 minutes ought to be enough); The messages we’re looking for are “Info” messages so --info is necessary; --predicate is used for message filters.

    log show --last 5m --info --predicate '((eventMessage CONTAINS "Adding remote service") && (eventMessage CONTAINS "debugproxy")) || (eventMessage CONTAINS "Tunnel established - interface")'  --style compact
    

    NOTE: if no log messages match the filter, it is recommended to force the recreation of the tunnel

    • kill the remotepairingd daemon: sudo pkill -9 remotepairingd
    • retry previous two steps

    Some applications can keep the tunnel open, examples: Xcode, Console and Safari. It is preferable to close them before creating the tunnel. If multiple sets of messages match the filter (with different connection details), only the last one should be considered (previous connections would likely be stale).

    2024-09-23 10:04:31.396 Df remotepairingd[1067:8211ab] [com.apple.dt.remotepairing:remotepairingd] device-138 (00008030-000D3988119A802E): Tunnel established - interface: utun5, local fd57:8329:afda::2-> remote fd57:8329:afda::1
    2024-09-23 10:04:31.422 I  remoted[342:81eff3] [com.apple.RemoteServiceDiscovery:remoted] coredevice-15> Adding remote service "com.apple.internal.dt.remote.debugproxy": {
    	Properties => {
    		Features => [<capacity = 1>
    			0: com.apple.coredevice.feature.debugserverproxy
    		]
    		ServiceVersion => 1
    		UsesRemoteXPC => true
    	}
    	Entitlement => com.apple.private.CoreDevice.canDebugApplicationsOnDevice
    	Port => 49350
    }
    

    The relevant pieces of information in the messages are:

    remote fd57:8329:afda::1 in the first message and Port => 49350 in the second message.

    TIP: There are some really good third party tools out there such as DoronZ’s pymobiledevice3 that reimplement the necessary machinery to create a trusted tunnel and make services available.

    Launch the app (--start-stopped will make it wait at the process entry point)

    xcrun devicectl device process launch -d $DEVICE_NAME --start-stopped $BUNDLE_ID
    

    Retrieve the PID of the process.

    xcrun devicectl device info processes -d $DEVICE_NAME | grep $(awk '{print A[split($1, A, "\.")]}' <<< $BUNDLE_ID)
    
    820   /private/var/containers/Bundle/Application/4629EEFD-0AD5-4B3C-B773-FD7D643BC376/spritegame.app/spritegame
    

    We have now created a trusted tunnel, found the connection details necessary for the debugproxy, launched an app and fetched its PID.

    3. Debugging in IDA

    Open the application executable (typically located in ~/Library/Developer/Xcode/DerivedData/<project_id>/Build/Products/Debug-iphoneos/<appname>.app/<appname>, the path to the build folder can also be retrieved via Xcode Product>Copy Build Folder Path) in IDA.

    Open the Debugger>Process options.. dialog.

    IDA with menu bar open on Debugger>Process options…

    Fill-in the Hostname (address) and Port of the debugproxy. Please use the ones retrieved from the system logs earlier.

    The Application and Parameters fields can safely be ignored since we’ll be attaching to a process. For this example the input file is the main executable for the application, as such the Input file field doesn’t need to be modified.

    IDA debug application setup dialog with Hostname and Port fields filled-in

    Open the Debugger specific options.

    IDA can speed up the loading of shared cache symbols if they have been copied and extracted to the host machine, it is highly recommended to provide the Symbol path (normally ~/Library/Developer/Xcode/iOS DeviceSupport/<device_and_os_version>/Symbols). Launch debugserver automatically should be disabled as it is used to communicate with devices using the MobileDevice framework (no longer a viable option as of iOS 17). Accept this dialog.

    IDA iOS configuration dialog with Symbol path field filled-in

    Optionally, open the Debugger options and enable Suspend on debugging start. The Debugger setup dialog can then be closed as well as the Debug application setup dialog.

    IDA Debug options dialog with “Suspend on debugging start” checkbox checked.

    Now that the necessary connection details have been given to IDA, we can attach to the target process.

    Open Debugger>Attach to process… We will provide the PID manually so accept this dialog.

    IDA Choose process dialog with a single entry “<enter a PID to attach>”

    Enter the PID of the target process retrieved earlier using devicectl and accept this dialog.

    IDA dialog asking for a PID input

    Profit! The Debugging session should start.

    IDA debugging session successfully started, IDA View showing PC on first instruction of __dyld_start

    Debugging iOS Applications with IDA Pro

    Copyright 2020 Hex-Rays SA

    Overview

    This tutorial discusses optimal strategies for debugging native iOS applications with IDA Pro.

    IDA Pro supports remote debugging on any iOS version since iOS 9 (including iPadOS). Debugging is generally device agnostic so it shouldn’t matter which hardware you’re using as long as it’s running iOS. The debugger itself can be used on any desktop platform that IDA supports (Mac/Windows/Linux), although using the debugger on Mac makes more features available.

    Note that IDA supports debugging on both jailbroken and non-jailbroken devices. Each environment provides its own unique challenges and advantages, and we will discuss both in detail in this writeup.

    Getting Started

    The quickest way to get started with iOS debugging is to use Xcode to install a sample app on your device, then switch to IDA to debug it.

    In this example we’ll be using an iPhone SE 2 with iOS 13.4 (non-jailbroken) while using IDA 7.5 SP1 on OSX 10.15 Catalina. Start by launching Xcode and use menu File>New>Project… to create a new project from one of the iOS templates, any of them will work:

    After selecting a template, set the following project options:

    Note the bundle identifier primer.idatest, it will be important later. For the Team option choose the team associated with your iOS Developer account, and click OK. Before building be sure to set the target device in the top left of the Xcode window:

    Now launch the build in Xcode. If it succeeds then Xcode will install the app on your device automatically.

    Preparing a Debugging Environment

    Now that we have a test app installed on our device, let’s prepare to debug it. First we must ensure that the iOS debugserver is installed on the device. Since our device is not jailbroken, this is not such a trivial task. By default iOS restricts all remote access to the device, and such operations are managed by special MacOS Frameworks.

    Fortunately Hex-Rays provides a solution. Download the ios_deploy utility from our download center. This is a command-line support utility that can perform critical tasks on iOS devices without requiring a jailbreak. Try running it with the listen phase. If ios_deploy can detect your device it will print a message:

    $ ios_deploy listen
    Device connected:
    - name:    iPhone SE 2
    - model:   iPhone SE 2
    - ios ver: 13.4
    - build:   17E8255
    - arch:    arm64e
    - id:      XXXXXXXX-XXXXXXXXXXXXXXXX
    

    Use the mount phase to install DeveloperDiskImage.dmg, which contains the debugserver:

    $ export DEVELOPER=/Applications/Xcode.app/Contents/Developer
    $ export DEVTOOLS=$DEVELOPER/Platforms/iPhoneOS.platform/DeviceSupport
    $ ios_deploy mount -d $DEVTOOLS/13.4/DeveloperDiskImage.dmg
    

    The device itself is now ready for debugging. Now let’s switch to IDA and start configuring the debugger. Load the idatest binary in IDA, Xcode likely put it somewhere in its DerivedData directory:

    $ alias ida64="/Applications/IDA\ Pro\ 7.5\ sp1/ida64.app/Contents/MacOS/ida64"
    $ export XCDATA=~/Library/Developer/Xcode/DerivedData
    $ ida64 $XCDATA/idatest/Build/Products/Debug-iphoneos/idatest.app/idatest
    

    Then go to menu Debugger>Select debugger… and select Remote iOS Debugger:

    When debugging a binary remotely, IDA must know the full path to the executable on the target device. This is another task that iOS makes surprisingly difficult. Details of the filesystem are not advertised, so we must use ios_deploy to retrieve the executable path. Use the path phase with the app’s bundle ID:

    $ ios_deploy path -b primer.idatest
    /private/var/containers/Bundle/Application/<UUID>/idatest.app/idatest
    

    Use this path for the fields in Debugger>Process options…

    NOTE: the path contains a hex string representing the application’s 16-byte UUID. This id is regenerated every time you reinstall the app, so you must update the path in IDA whenever the app is updated on the device.

    Now go to Debugger>Debugger options>Set specific options… and ensure the following fields are set:

    Make special note of the Symbol path option. This directory contains symbol files extracted from your device. Both IDA and Xcode use these files to load symbol tables for system libraries during debugging (instead of reading the tables in process memory), which will dramatically speed up debugging.

    Xcode likely already created this directory when it first connected to your device, but if not you can always use ios_deploy to create it yourself:

    $ ios_deploy symbols
    Downloading /usr/lib/dyld
    Downloading 0.69 MB of 0.69 MB
    Downloading /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e
    Downloading 1648.38 MB of 1648.38 MB
    Extracting symbol file: 1866/1866
    /Users/troy/Library/Developer/Xcode/iOS DeviceSupport/13.4 (17E8255)/Symbols: done
    

    Also ensure that the Launch debugserver automatically option is checked. This is required for non-jailbroken devices since we have no way to launch the server manually. This option instructs IDA to establish a connection to the debugserver itself via the MacOS Frameworks, which will happen automatically at debugging start.

    Lastly, Xcode might have launched the test application after installing it. Use the proclist phase to retreive the app’s pid and terminate it with the kill phase:

    $ ios_deploy proclist -n idatest
    32250
    $ ios_deploy kill -p 32250
    

    Finally we are ready to launch the debugger. Go to main in IDA’s disassembly view, use F2 to set a breakpoint, then F9 to launch the process, and wait for the process to hit our breakpoint:

    You are free to single step, inspect registers, and read/write memory just like any other IDA debugger.

    Source Level Debugging

    You can also use IDA to debug the source code of your iOS application. Let’s rebuild the idatest application with the DWARF with dSYM File build setting:

    Since the app is reinstalled, the executable path will change. We’ll need to update the remote path in IDA:

    $ ios_deploy path -b primer.idatest
    

    Be sure to enable Debugger>Use source-level debugging, then launch the process. At runtime IDA will be able to load the DWARF source information:

    Note that the debugserver does not provide DWARF information to IDA - instead IDA looks for dSYM bundles in the vicinity of the idb on your local filesystem. Thus if you want IDA to load DWARF info for a given module, both the module binary and its matching dSYM must be in the same directory as the idb, or in the idb’s parent directory.

    For example, in the case of the idatest build:

    $ tree
    .
    ├── idatest.app
    │   ├── idatest
    │   └── idatest.i64
    └── idatest.app.dSYM
        └── Contents
            └── Resources
                └── DWARF
                    └── idatest
    

    IDA was able to find the idatest binary next to idatest.i64, as well as the dSYM bundle next to the parent app directory.

    If IDA can’t find DWARF info on your filesystem for whatever reason, try launching IDA with the command-line option -z440010, which will enable much more verbose logging related to source-level debugging:

    Looking for Mach-O file "idatest.app/idatest.dSYM/Contents/Resources/DWARF/idatest"
    File "idatest.app/idatest.dSYM/Contents/Resources/DWARF/idatest" exists? -> No.
    Looking for Mach-O file "idatest.app.dSYM/Contents/Resources/DWARF/idatest"
    File "idatest.app.dSYM/Contents/Resources/DWARF/idatest" exists? -> Yes.
    Looking for cpu=16777228:0, uuid=7a09f307-7503-3c0d-a182-ab552c1bf182.
    Candidate: cpu=16777228:0, uuid=7a09f307-7503-3c0d-a182-ab552c1bf182.
    Found, with architecture #0
    DWARF: Found DWARF file "idatest.app.dSYM/Contents/Resources/DWARF/idatest"
    

    Debugging DYLD

    IDA can also be used to debug binaries that are not user applications. For example, dyld.

    The ability to debug dyld is a nice advantage because it allows us to observe critical changes in the latest versions of iOS (especially regarding the shared cache) before a jailbreak is even available. We document this functionality here in the hopes it will be useful to others as well.

    In this example we’ll be using IDA to discover how dyld uses ARMv8.3 Pointer Authentication to perform secure symbol bindings. Start by loading the dyld binary in IDA. It is usually found here:

    ~/Library/Developer/Xcode/iOS DeviceSupport/13.4 (17E8255)/Symbols/usr/lib/dyld
    

    The target application will be a trivial helloworld program:

    #include <stdio.h>
    
    int main(void)
    {
      puts("hello, world!\n");
      return 0;
    }
    

    Compile and install this app on your device, then set the following fields in Debugger>Process options…

    Under Debugger>Debugger options, enable Suspend on debugging start. This will instruct IDA to suspend the process at dyld’s entry point, before it has begun binding symbols. Now launch the process with F9 - immediately the process will be suspended at __dyld_start:

    Double-click on the helloworld module to bring up its symbol list and go to the _main function:

    Note that function sub_1009CBF98 is the stub for puts:

    The stub reads a value from off_109CC000, then performs a branch with pointer authentication. We can assume that at some point, dyld will fill off_109CC000 with an authenticated pointer to puts. Let’s use IDA to quickly track down this logic in dyld.

    The iOS debugger supports watchpoints. Now would be a good time to use one:

    ida_dbg.add_bpt(0x1009CC000, 8, BPT_WRITE)
    

    Resume the process and wait for dyld to trigger our watchpoint:

    The instruction STR X21 [X19] triggered the watchpoint, and note the value in X21 (BB457A81BA95ADD8) which is the authenticated pointer to puts. Where did this value come from? We can see that X21 was previously set with MOV X21, X0 after a call to this function:

    dyld3::MachOLoaded::ChainedFixupPointerOnDisk::Arm64e::signPointer
    

    It seems like we’re on the right track. Also note that IDA was able to extract a nice stack trace despite dyld’s heavy use of PAC instructions to authenticate return addresses on the stack:

    Address    Module  Function
    100CA5E14  dyld    ____ZNK5dyld311MachOLoaded21fixupAllChainedFixups_block_invoke
    100CA5EEC  dyld    dyld3::MachOLoaded::walkChain
    100CA5BF0  dyld    dyld3::MachOLoaded::forEachFixupInAllChains
    100CA5B50  dyld    dyld3::MachOLoaded::fixupAllChainedFixups
    100CA2210  dyld    ____ZN5dyld36Loader18applyFixupsToImage_block_invoke.68
    100CB0218  dyld    dyld3::MachOAnalyzer::withChainStarts
    100CA2004  dyld    ____ZN5dyld36Loader18applyFixupsToImage_block_invoke_3
    100CB3314  dyld    dyld3::closure::Image::forEachFixup
    100CA15EC  dyld    dyld3::Loader::applyFixupsToImage
    100CA0A00  dyld    dyld3::Loader::mapAndFixupAllImages
    100C88784  dyld    dyld::launchWithClosure
    100C86BE0  dyld    dyld::_main
    100C81228  dyld    dyldbootstrap::start
    100C81034  dyld    __dyld_start
    

    This leads us to the following logic in the dyld-733.6 source:

    // authenticated bind
    newValue = (void*)(bindTargets[fixupLoc->arm64e.bind.ordinal]);
    if (newValue != 0)
    	newValue = (void*)fixupLoc->arm64e.signPointer(fixupLoc, newValue);
    

    Here, fixupLoc (off_109CC00) and newValue (address of puts) are passed as the loc and target arguments for Arm64e::signPointer:

    uint64_t discriminator = authBind.diversity;
    if ( authBind.addrDiv )
    	discriminator = __builtin_ptrauth_blend_discriminator(loc, discriminator);
    switch ( authBind.key ) {
      case 0: // IA
        return __builtin_ptrauth_sign_unauthenticated(target, 0, discriminator);
      case 1: // IB
        return __builtin_ptrauth_sign_unauthenticated(target, 1, discriminator);
      case 2: // DA
        return __builtin_ptrauth_sign_unauthenticated(target, 2, discriminator);
      case 3: // DB
        return __builtin_ptrauth_sign_unauthenticated(target, 3, discriminator);
    }
    

    Thus, the pointer to puts is signed using its destination address in helloworld:__auth_got as salt for the signing operation. This is quite clever because the salt value is subject to ASLR and therefore cannot be guessed, but at this point the executable has already been loaded into memory – so it won’t change by the time the pointer is verified in the stub.

    To see this in action, use F4 to run to the BRAA instruction in the stub and note the values of the operands:

    The branch will use the operands to verify that the target address has not been modified after it was originally calculated by dyld. Since we haven’t done anything malicious, one more single step should take us right to puts:

    Just for fun, let’s rewind the process back to the start of the stub:

    IDC>PC = 0x1009CBF98
    

    Then overwrite the authenticated pointer to puts with a raw pointer to printf:

    ida_bytes.put_qword(0x1009CC000, ida_name.get_name_ea(BADADDR, "_printf"))
    

    Now when we step through the stub, the BRAA instruction should detect that the authenticated pointer has been modified, and it will purposefully crash the application by setting PC to an invalid address:

    Any attempt to resume execution will inevitably fail:

    It seems we now have an understanding of secure symbol bindings in dyld. Fascinating!

    Debugging the DYLD Shared Cache

    This section discusses how to optimally debug system libraries in a dyld_shared_cache.

    NOTE: full support for dyld_shared_cache debugging requires IDA 7.5 SP1

    Debugging iOS system libraries is a challenge because the code is only available in the dyld cache. IDA allows you to load a library directly from the cache, but this has its own complications. A single module typically requires loading several other modules before the analysis becomes useful. Fortunately IDA is aware of these annoyances and allows you to debug such code with minimal effort.

    To start, consider the following sample application that uses the CryptoTokenKit framework:

    #import <CryptoTokenKit/CryptoTokenKit.h>
    
    int main(void)
    {
      TKTokenWatcher *watcher = [[TKTokenWatcher alloc] init];
      NSArray *tokens = [watcher tokenIDs];
      for ( int i = 0; i < [tokens count]; i++ )
        printf("%s\n", [[tokens objectAtIndex:i] UTF8String]);
      return 0;
    }
    

    Assume this program has been compiled and installed on the device as ctk.app.

    Instead of debugging the test application, let’s try debugging the CryptoTokenKit framework itself - focusing specifically on the -[TKTokenWatcher init] method.

    Initial Analysis

    First we’ll need access to the dyldcache that contains the CryptoTokenKit framework. The best way to obtain the cache is to extract it from the ipsw package for your device/iOS version. This ensures that you are working with the original untouched cache that was installed on your device.

    When opening the cache in IDA, choose the load option Apple DYLD cache for arm64e (single module) and select the CryptoTokenKit module:

    Wait for IDA to finish the initial analysis of CryptoTokenKit. Immediately we might notice that the analysis suffers because of references to unloaded code. Most notably many Objective-C methods are missing a prototype, which is unusual:

    However this is expected. Modern dyld caches store all Objective-C class names and method selectors inside the libobjc module. Objective-C analysis is practically useless without these strings, so we must load the libobjc module to access them. Since a vast majority of modules depend on libobjc in such a way, it is a good idea to automate this in a script.

    For a quick fix, save the following idapython code as init.py:

    # improve functions with branches to unloaded code
    idaapi.cvar.inf.af &= ~AF_ANORET
    
    def dscu_load_module(module):
        node = idaapi.netnode()
        node.create("$ dscu")
        node.supset(2, module)
        load_and_run_plugin("dscu", 1)
    
    # load libobjc, then analyze objc types
    dscu_load_module("/usr/lib/libobjc.A.dylib")
    load_and_run_plugin("objc", 1) 
    

    Then reopen the cache with:

    $ ida64 -Sinit.py -Oobjc:+l dyld_shared_cache_arm64e
    

    This will tell IDA to load libobjc immediately after the database is created, then perform the Objective-C analysis once all critical info is in the database. This should make the initial analysis acceptable in most cases. In the case of CryptoTokenKit, we see that the Objective-C prototypes are now correct:

    Now let’s go to the -[TKTokenWatcher init] method invoked by the ctk application:

    If we right-click on the unmapped address 0x1B271C01C, IDA provides two options in the context menu:

    In this case the better option is Load ProVideo:__auth_stubs, which loads only the stubs from the module and properly resolves the names:

    This is a common pattern in the latest arm64e dyldcaches, and it is quite convenient for us. Loading a handful of __auth_stubs sections is enough to resolve most of the calls in CryptoTokenKit, which gives us some nice analysis for -[TKTokenWatcher init] and its helper method:

    Debugger Configuration

    Now that the static analysis is on par with a typical iOS binary, let’s combine it with dynamic analysis. We can debug this database by setting the following options in Debugger>Process options:

    Here we set the Input file field to the full path of the CryptoTokenKit module. This allows IDA to easily detect the dyldcache slide at runtime. When CryptoTokenKit is loaded into the process, IDA will compare its runtime load address to the imagebase in the current idb, then rebase the database accordingly.

    By default the imagebase in the idb corresponds to the first module that was loaded:

    IDC>msg("%a", get_imagebase())
    CryptoTokenKit:HEADER:00000001B8181000
    

    Thus, it is easiest to set Input file to the module corresponding to the default imagebase.

    Note however that we could also use this configuration:

    Provided that we update the imagebase in the idb to the base of the libobjc module:

    ida_nalt.set_imagebase(ida_segment.get_segm_by_name("libobjc.A:HEADER").start_ea)
    

    This will result in the same dyld slide and should work just as well, because the the imagebase and the Input file field both correspond to the same module. This is something to keep in mind when debugging dyldcache idbs that contain multiple libraries.

    Now let’s try launching the debugger. Set a breakpoint at -[TKTokenWatcher initWithClient:], use F9 to launch the process, then wait for our breakpoint to be hit:

    IDA was able to map our database (including CryptoTokenKit, libobjc, and the satellite __auth_stubs sections) into process memory. We can single step, resume, inspect registers, and perform any other operation that is typical of an IDA debugging session.

    Further Analysis

    Note that after terminating the debugging session you can continue to load new modules from the cache. If a dyld slide has been applied to the database, new modules will be correctly loaded into the rebased address space. This did not work in previous versions of IDA.

    For example, after a debugging session we might notice some more unresolved calls:

    IDA is aware that the address space has shifted, and it will load the new code at the correct address:

    You are free to load new modules and relaunch debugging sessions indefinitely.

    Debugging System Applications

    The previous examples used custom applications to demonstrate IDA’s debugging capabilities. In this case IDA can utilize the debugserver included in Apple’s iOS developer tools, but there are situations in which this server is not sufficient for our needs.

    The debugserver will refuse to debug any application that we didn’t build ourselves. To demonstrate this, try launching IDA with an empty database and use Debugger>Attach>Remote iOS Debugger to attach to one of the system daemons:

    You will likely get this error message:

    It is possible to install a custom version of the debugserver that can debug system processes, but this requires a jailbroken device. We document the necessary steps and IDA configuration here. The device used in this example is an iPhone 8 with iOS 13.2.2, jailbroken with checkra1n 0.10.1.

    Patching the debugserver

    First we must obtain a copy of the debugserver binary from the DeveloperDiskImage.dmg:

    $ export DEVELOPER=/Applications/Xcode.app/Contents/Developer
    $ export DEVTOOLS=$DEVELOPER/Platforms/iPhoneOS.platform/DeviceSupport
    $ hdiutil mount $DEVTOOLS/13.2/DeveloperDiskImage.dmg
    $ cp /Volumes/DeveloperDiskImage/usr/bin/debugserver .
    

    Now save the following xml as entitlements.plist:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>task_for_pid-allow</key> <true/>
    	<key>get-task-allow</key> <true/>
    	<key>platform-application</key> <true/>
    	<key>com.apple.springboard.debugapplications</key> <true/>
    	<key>run-unsigned-code</key> <true/>
    	<key>com.apple.system-task-ports</key> <true/>
    </dict> 
    </plist>
    

    Then use ldid to codesign the server:

    $ ldid -Sentitlements.plist debugserver
    

    This will grant the debugserver permission to debug any application, including system apps. Now we can copy the server to the device and run it:

    $ scp debugserver root@iphone-8:/usr/bin/
    $ ssh root@iphone-8
    iPhone-8:~ root# /usr/bin/debugserver 192.168.1.7:1234
    debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.98 for arm64.
    Listening to port 1234 for a connection from 192.168.1.7...
    

    Note that we specified 192.168.1.7 which is the IP of the host machine used in this example. Be sure to replace this with the IP of your host so that the server will accept incoming connections from IDA.

    IDA Configuration

    To enable debugging with the patched debugserver, set the following options in dbg_ios.cfg:

    // don't launch the debugserver. we did it manually
    AUTOLAUNCH = NO
    // your device's UUID. this is used when fetching the remote process list
    DEVICE_ID = "";
    // debugging symbols extracted by Xcode
    SYMBOL_PATH = "~/Library/Developer/Xcode/iOS DeviceSupport/13.2.2 (17B102)/Symbols";
    

    We’re now ready to open a binary in IDA and debug it. Copy the itunesstored binary from your device, it is typically found here:

    /System/Library/PrivateFrameworks/iTunesStore.framework/Support/itunesstored
    

    After loading the binary use Debugger>Select debugger and choose Remote iOS Debugger, then under Debugger>Process options set the following fields:

    Since we set AUTOLAUNCH = NO, IDA now provides the Hostname and Port fields so we can specify how to connect to our patched debugserver instance.

    Now use Debugger>Attach to process and choose itunesstored from the process list. Since we have modified the debugserver it should agree to debug the target process, allowing IDA to create a typically robust debugging environment:

    \

    Note that although we’re not using the debugserver from DeveloperDiskImage.dmg, IDA still depends on other developer tools to query the process list. We discuss how to install the DeveloperDiskImage in the Getting Started section above, but for a quick workaround you can always just specify the PID manually:

    Now that we’ve successfully attached to a system process, let’s do something interesting with it. Consider the method -[PurchaseOperation initWithPurchase:]. This logic seems to be invoked when a transaction is performed in the AppStore. Set a breakpoint at this method, then open the AppStore on your device and try downloading an app (it can be any app, even a free one).

    Immediately our breakpoint is hit, and we can start unwinding the logic that brought us here:

    Stepping through this function, we see many Objective-C method call sites:

    Instead of using F7 to step into the _objc_msgSend function, we can use shortcut Shift-O to take us directly to the Objective-C method that is being invoked:

    We discuss the Shift-O action in detail in our mac debugger primer, but it is worth demonstrating that this action works just as well in arm64/iOS environments.

    It seems that we’re well on our way to reverse-engineering transactions in the AppStore. The remaining work is left as an exercise for the reader :)

    Conclusion

    Hopefully by now we’ve shown that IDA’s iOS Debugger is quite versatile. It can play by Apple’s rules when debugging on a non-jailbroken device, and it can also be configured to use an enhanced debugserver when a jailbreak is available.

    Also keep in mind that all previous examples in this writeup should work equally well with the patched debugserver. We encourage you to go back and try them.


















    \

    Troubleshooting

    IDA uses the Remote GDB Protocol to communicate with the iOS debugserver. Thus, the best way to diagnose possible issues is to log the packets transmitted between IDA and the server. You can do this by running IDA with the -z10000 command-line option:

    $ ida64 -z10000 -L/tmp/ida.log
    

    Often times these packets contain messages or error codes that provide clues to the issue.

    For more enhanced troubleshooting, you can also enable logging on the server side. Go to Debugger>Debugger options>Set specific options and set the Syslog flags field:

    This will instruct the debugserver to log details about the debugging session to the iOS system log (all valid flags are documented under the SYSLOG_FLAGS option in dbg_ios.cfg).

    Start collecting the iOS system log with:

    $ ios_deploy syslog -f /tmp/sys.log
    

    Then launch the debugger. Now both the client (/tmp/ida.log) and the server (/tmp/sys.log) will log important events in the debugger session, which will often times reveal the issue.`

    Notes

    This tutorial replaces the old iOS debugging tutorial, which is available here.

    IDA Linux Local Debugging

    You may either start a local debugging session on a new process or start a local debugging session and attach it to an existing process. Both options are accessible through the command line.

    ida -rlinux MY_PROGRAM

    will start the program, create a temporary database that allows the user to work with the target at once.

    start_local_process.png

    The command

    ida -rlinux+

    will offer you a choice of running processes to connect to.

    select_local_process

    and we can proceed with our local Linux debugging session.

    attached_to_local_process

    Debugging Linux/Windows Applications with PIN Tracer module

    Introduction

    The PIN tracer is a remote debugger plugin used to record execution traces. It allows to record traces on Linux and Windows (x86 and x86_64) from any of the supported IDA platforms (Windows, Linux and MacOSX). Support for MacOSX targets is not yet available.

    {% hint style=“info” %} IDA PIN Tool Sources:
    The PIN tool for the latest versions of IDA can be found in the Download Center of My Hex-Rays portal, under SDK and Utilities.
    For older versions of IDA, refer to the direct links. {% endhint %}

    PIN support for MacOSX

    Recording traces on MacOSX target is not supported yet.

    However, it’s possible to record traces from a Linux or Windows target using the MacOSX version of IDA.

    Building the PIN tool

    Before using the PIN tracer the PIN tool module (distributed only in source code form) must be built as the Intel PIN license disallows redistributing PIN tools in binary form.

    First, download PIN, and unpack it on your hard drive.

    the PIN tools are a little sensitive to spaces in paths. Therefore, we recommend unpacking in a no-space path. E.g., “C:\pin”, but not “C:\Program Files (x86)\.

    The building process of the PIN tool is different for Windows and Linux.

    Building on Windows

    1. Install Visual Studio. It is possible to build the PIN tool with the Express version of Visual Studio for C++.
    2. Download the IDA pintool sources from:
    1. Unpack the .zip file into /path/to/pin/source/tools/
    2. Open /path/to/pin/source/tools/idapin/IDADBG.sln in Visual Studio, select the correct build configuration (either Win32 or x64) and build the solution.

    Alternatively you can use GNU make:

    1. Install GNU make as a part of cygwin or MinGW package
    2. Unpack the .zip file into /path/to/pin/source/tools/
    3. Prepare Visual Studio environment (e.g., %VCINSTALLDIR%\Auxiliary\Build\vcvars32.bat for 32-bit pintool or %VCINSTALLDIR%\Auxiliary\Build\vcvars64.bat for 64-bit one)
    4. cd /path/to/pin/source/tools/idapin
    5. make

    Building on Linux

    1. Install GCC 3.4 or later
    2. Download the IDA pintool sources from:
    3. Unpack the .zip file into /path/to/pin/source/tools/
    4. Open a console, and do the following (only for versions of PIN prior to 3.0):
      1. cd /path/to/pin/ia32/runtime
      2. ln -s libelf.so.0.8.13 libelf.so
      3. cd /path/to/pin/intel64/runtime
      4. ln -s libelf.so.0.8.13 libelf.so
      5. cd /path/to/pin/source/tools/Utils
      6. ls testGccVersion 2>/dev/null || ln -s ../testGccVersion testGccVersion
    5. cd /path/to/pin/source/tools/idapin
    $ make TARGET=ia32
    

    for building the x86 version, or

    $ make TARGET=intel64
    

    for the x64 version.

    URL Schema

    (*) Where ‘$(IDAMAJMIN)’ is the IDA version major/minor. E.g., for IDA 7.6, the final URL would be: https://hex-rays.com/hubfs/freefile/idapin76.zip

    NOTE: These URL links are intended for older versions of the PIN tool. To download the PIN tool for the latest versions of IDA, please visit the Download Center in My Hex-Rays portal.

    Pintool 6.9 and higher are compatible with versions 6.5-6.8 of IDA so currently you can use them.

    Start process

    Once the PIN tool module is built we can use it in IDA. Open a binary in IDA and wait for the initial analysis to finish. When it’s done select the PIN tracer module from the debuggers drop down list or via Debugger > Select debugger:

    pin debugger select

    After selecting the PIN tracer module select the menu Debugger > Debugger options > Set specific options. The following new dialog will be displayed:

    pin options

    In this dialog at least the following options are mandatory:

    1. PIN executable: This is the full path to the PIN binary (including the “pin.exe” or “pin” file name). In some versions “pin.sh” may exist – in this case you should use it.
    2. Directory with idadbg: This is the directory where the idadbg.so or idadbg.dll PIN tool resides. Please note that only the directory must be specified.

    Fill the form with the correct paths and press OK in this dialog and enable option Autolaunch PIN for localhost.

    We can interact with the PIN tracer like with any other debugger module: add breakpoints and step into or step over functions by pressing F7 or F8 alternatively.

    Now we put a breakpoint in the very first instruction of function main

    pin bpt in main

    and launch the debugger by pressing the F9 key or by clicking the Start button in the debugger toolbar.

    pin starting debug session

    Make several steps by pressing F8. We can see all the instructions that were executed changed their color:

    pin debug several steps

    Now let the application run and finish by pressing F9 again. After a while the process will terminate and IDA will display a dialog telling us that is reading the recorded trace. Once IDA reads the trace the debugger will stop and the instructions executed will be highlighted (like with the built-in tracing engine) as in the following picture:

    pin ended debug session

    We can see in the graph view mode the complete path the application took in some specific function by switching to the graph view, pressing space bar and then pressing “w” to zoom out:

    pin execution flow

    Attach to an existing process

    Instead of launching a new process we could attach to a running process and debug it. For that we could have selected the “Debugger > Attach to process…​” menu item. IDA will display a list of active processes.

    pin attaching to process

    We just select the process we want to attach to. IDA will then attach to the selected process, and leave it suspended at the place it was when it was attached to:

    pin attached to process

    Remote debugging

    In case of remote debugging you can run IDA and PIN backend on different platforms.

    Starting the remote PIN backend

    The first thing to do, is to start the PIN debugging backend on the target machine. Command line depends of bitness of the target application.

    $ <path-to-pin> -t <path-to-pintool> -p <port> -- <application> <application-options>
    

    For example, a 64-bit application ls would be started for debugging by the following comand:

    $ /usr/local/pin/pin \
      -t /usr/local/pin/source/tools/idapin/obj-intel64/idadbg64.so \
      -p 23947 -- \
      /bin/ls
    

    whereas a 32-bit one hello32 as follows:

    /usr/local/pin/pin \
      -t /usr/local/pin/source/tools/idapin/obj-ia32/idadbg.so \
      -p 23947 -- \
      ./hello32
    

    there is a more complicated way to start an application regardless bitness:

    /usr/local/pin/pin \
      -t64 /usr/local/pin/source/tools/idapin/obj-intel64/idadbg64.so \
      -t /usr/local/pin/source/tools/idapin/obj-ia32/idadbg.so \
      -p 23947 -- \
      /usr/bin/ls
    

    Also you can attach to already running programs:

    $ <path-to-pin> -pid <pid-to-attach> -t <path-to-pintool> -p <port> --
    

    For example:

    pin attaching remote64

    Connecting IDA to the backend

    The next step is to select PIN tracer module in IDA via Debugger > Select debugger and switch IDA to remote PIN backend. For this you should disable option Autolaunch PIN for localhost in the PIN options dialod (Debugger > Debugger options > Set specific options):

    pin options remote

    and then tell IDA about the backend endpoint, through the menu action Debugger > Process options…​

    pin setting process options

    Once IDA knows what host to contact (and on what port), debugging an application remotely behaves exactly the same way as if you were debugging it locally.

    Debugging Windows Applications with IDA Bochs Plugin

    Check the tutorial about debuggind Windows apps with IDA Bochs: {% file src=“bochs_tut.pdf” %}

    Debugging Windows Applications with IDA WinDbg Plugin

    Quick overview:

    The Windbg debugger plugin is an IDA Pro debugger plugin that uses Microsoft’s debugging engine (dbgeng) that is used by Windbg, Cdb or Kd.

    To get started, you need to install the latest Debugging Tools from Microsoft website: https://msdn.microsoft.com/en-us/windows/hardware/hh852365

    or from the Windows SDK / DDK package.

    Please make sure you should install the x86 version of the debugging tools which is used by both IDA Pro and IDA Pro 64. The x64 version will NOT work.

    After installing the debugging tools, make sure you select « Debugger / Switch Debugger » and select the WinDbg debugger.

    Also make sure you specify the correct settings in the “Debugger specific options” dialog:

    • User mode: Select this mode for user mode application debugging (default mode)

    • Kernel mode: Select this mode to attach to a live kernel.

    • Non Invasive debugging: Select this mode to attach to a process non-invasively

    • Output flags: These flags tell the debugging engine which kind of output messages to display and which to omit

    • Kernel mode debugging with reconnect and initial break: Select this option when debugging a kernel and when the connection string contains ‘reconnect’. This option will assure that the debugger breaks as soon as possible after a reconnect.

      To make these settings permanent, please edit the IDA\cfg\dbg_windbg.cfg file.

      **
      To specify the debugging tools folde**r you may add to the PATH environment variable the location of Windbg.exe or edit %IDA%\cfg\ida.cfg and change the value of the DBGTOOLS key.

      After the debugger is properly configured, edit the process options and leave the connection string value empty because we intend to debug a local user-mode application.

    Now hit F9 to start debugging:

    The Windbg plugin is very similar to IDA Pro’s Win32 debugger plugin, nonetheless by using the former, one can benefit from the command line facilities and the extensions that ship with the debugging tools.

    For example, one can type “!chain” to see the registered Windbg extensions:

    “!gle” is another command to get the last error value of a given Win32 API call.

    Another benefit of using the Windbg debugger plugin is the use of symbolic information.

    Normally, if the debugging symbols path is not set, then the module window will only show the exported names. For example kernel32.dll displays 1359 names:

    Let us configure a symbol source by adding this environment variable before running IDA:

    set _NT_SYMBOL_PATH=srv*C:\Temp\pdb*http://msdl.microsoft.com/download/symbols

    It is also possible to set the symbol path directly while debugging:

    and then typing “.reload /f” to reload the symbols.

    Now we try again and notice that more symbol names are retrieved from kernel32.dll:

    Now we have 5818 symbols instead!

    It is also possible to use the “x” command to quickly search for symbols:

    (Looking for any symbol in any module that contains the word “continue”)

    Debugging a remote process

    We have seen how to debug a local user mode program, now let us see how to debug a remote process.

    First let us assume that “pcA” is the target machine (where we will run the debugger server and the debugged program) and “pcB” is the machine where IDA Pro and the debugging tools are installed.

    To start a remote process:

    • On “pcA”, type:
    • dbgsrv -t tcp:port=5000

    (change the port number as needed)

    • On “pcB”, setup IDA Pro and Windbg debugger plugin:
      • “Application/Input file”: these should contain a path to the debuggee residing in “pcA”
      • Connection string: tcp:port=5000,server=pcA

    Now run the program and debug it remotely.

    To attach to a remote process, use the same steps to setup “pcA” and use the same connection string when attaching to the process.

    More about connection strings and different protocols (other than TCP/IP) can be found in “debugger.chm” in the debugging tools folder.

    Debugging the kernel with VMWare

    We will now demonstrate how to debug the kernel through a virtual machine.

    In this example we will be using VMWare 6.5 and Windows XP SP3.

    Configuring the virtual machine:

    Run the VM and then edit “c:\boot.ini” file and add one more entry (see in bold):

    [operating systems]

    multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=“Microsoft Windows XP Professional” /noexecute=optin /fastdetect multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=“Local debug” /noexecute=optin /fastdetect /debug /debugport=com1 /baudrate=115200

    For MS Windows Vista please see: http://msdn.microsoft.com/en-us/library/ms791527.aspxp

    Actually the last line is just a copy of the first line but we added the “/debug” switch and some configuration values.

    Now shutdown the virtual machine and edit its hardware settings and add a new serial port with option “use named pipes”:

    Press “Finish” and start the VM. At the boot prompt, select “Local debug” from the boot menu:

    Configuring Windbg debugger plugin:

    Now run IDA Pro and select Debugger / Attach / Windbg

    Then configure it to use “Kernel mode” debugging and use the following connection string:

    com:port=\.\pipe\com_1,baud=115200,pipe

    It is possible to use the ‘reconnect’ keyword in the connection string:

    com:port=\.\pipe\com_1,baud=115200,pipe,reconnect

    Also make sure the appropriate option is selected from the debugger specific options.

    Please note that the connection string (in step 1) refers to the named pipe we set up in the previous steps.

    Finally, press OK to attach and start debugging.

    When IDA attaches successfully, it will display something like this:

    If you do not see named labels then try checking your debugging symbols settings.

    Note: In kernel mode IDA Pro will display one entry in the threads window for each processor.

    For example a two processor configuration yields:

    VMWare configuration

    Threads in IDA

    This screenshot shows how we are debugging the kernel and changing the disassembly listing (renaming stack variables, or using structure offsets):

    At the end you can detach from the kernel and resume it or detach from the kernel and keep it suspended.

    To detach and resume, simply select the “Debugger / Detach”, however to detach and keep the kernel suspended select “Debugger / Terminate Process”.

    Debugging the kernel through kdsrv.exe

    In some cases, when debugging a 64bit kernel using a 1394 cable then 64bit drivers are needed, thus dbgeng (32bits) will not work. To workaround this problem we need to run the kernel debugger server from the x64 debugging tools folder and connect to it:

    • Go to “Debugging Tools (x64)” installation
    • Run kdsrv.exe (change the port number/transport appropriately):
      • kdsrv -t tcp:port=6000
    • Now run ida64 and specify the following connection string (change the transport value appropriately):
      • kdsrv:server=@{tcp:port=6000,server=127.0.0.1},trans=@{com:port=\.\pipe\com_3,baud=115200,pipe}

    Using the Bochs debugger plugin in Linux

    Introduction

    This guide illustrates how to configure the Bochs debugger plugin under Linux/MacOS. Downloading and compiling Bochs Please download the Bochs source code tarball and extract it.

    tar zxf bochs-2.5.1.tar.gz
    

    Run the ‘configure’ script (it is possible to pass other switches) and make sure that the switches marked in bold are present:

    ./configure --enable-sb16 --enable-ne2000 --enable-all-optimizations \ --enable-cpu-level=6 --enable-x86-64 --enable-pci \ --enable-clgd54xx --enable-usb --enable-usb-ohci \ --enable-show-ips --with-all-libs \ --enable-debugger --disable-readline
    

    Note: under MacOS Lion 10.7.3 use the following switches:

    ./configure --enable-cpu-level=6 --with-nogui --enable-debugger --enable-disasm --enable-x86-debugger --enable-x86-64 --disable-readline --enable-all-optimizations --enable-sb16 --enable-ne2000 --enable-pci --enable-acpi --enable-clgd54xx --enable-usb --enable-usb-ohci --enable-show-ips
    

    For a complete installation guide please check: http://bochs.sourceforge.net/doc/docbook/user/compiling.html. Now run “make” and “make install”. Then type “whereis bochs” to get something like:

    lallous@ubuntu:~/dev/bochs-2.5.1$ whereis bochsbochs: /usr/local/bin/bochs /usr/local/lib/bochs
    

    Configuring IDA and the Bochs debugger plugin

    Opening a database and selecting the Bochs debugger

    After installing Bochs, run IDA Pro and open a Windows PE file and select ‘Debugger -> switch debugger’ and select “Local Bochs Debugger”:

    If a PE file was loaded, then the Bochs debugger plugin will operate in “PE mode”:

    In case the other two modes (IDB or Disk Image mode) are used then there is no need to specify any additional configurations options, otherwise please continue reading this guide. Before launching the debugger with F9, the Bochs debugger plugin needs to know where to find the MS Windows DLLs and which environment variables to use. Attempting to run the debugger without configuring it may result in errors like this:

    Here is a basic list of DLLs that are needed by most programs:

    • advapi32.dll
    • comctl32.dll
    • comdlg32.dll
    • gdi32.dll
    • kernel32.dll
    • msvcrt.dll
    • mswsock.dll
    • ntdll.dll
    • ntoskrnl.exe
    • shell32.dll
    • shlwapi.dll
    • urlmon.dll
    • user32.dll
    • wininet.dll
    • ws2_32.dll
    • wsock32.dll

    Let us create a directory in $HOME/bochs_windir/ and place those DLLs there. Specifying the Windows DLL path and environment variables using the startup file The startup file is a script file found in idadir\plugins\bochs directory. If IDC was the currently active language then startup.idc is used, otherwise startup.ext (where ext is the extension used by the currently selected extlang). In this tutorial we will be working with IDC, so we will edit the startup.idc file. (Please note that changes to this file will affect all databases. For local changes (database specific configuration) take a copy of the startup script file and place it in the same directory as the database then modify it). It is possible to specify a path map for a complete directory, for example:

    /// path /home/lallous/bochs_windir/=c:\windows\system32
    

    This line means that /home/lallous/bochs_windir/* will be visible to the debugged program as c:\windows\system32* (for example /home/lallous/bochs_windir/ntdll.dll will be visible as c:\windows\system32\ntdll.dll)

    If all DLLs referenced by the program are in the bochs_windir directory, then running the process again should work:

    (Bochs has already started and IDA switched to debugging mode.) There are two things that should be configured. Press “.” to switch to the output window (or use the Debugger / Modules list window to inspect the modules list):

    1.	The path to bochsys.dll is still not properly mapped. In our case, we need to add the following line to the startup file: 
    ```
    /// map /Users/elias/idasrc/current/bin/idaq.app/Contents/MacOS/plugins/bochs/bochsys.dll=c:\windows\system32\bochsys.dll
    ```
    (As opposed to the path keyword that maps complete directories, the map keyword to map individual files).
    
    To hide the presence of bochsys.dll, simply map it to another name: 
    ```
    /// map /Users/elias/idasrc/current/bin/idaq.app/Contents/MacOS/plugins/bochs/bochsys.dll=c:\windows\system32\kvm.dll
    ```
    6.	The executable's path: we also need to add a map for the executable itself or a path entry for the whole folder: 
    ```
    /// path /Users/elias/idasrc/current/bin/=c:\malware
    ```
    

    Now, after we run the program again we should get a more correct module list:

    It is equally important to specify some environment variables. We will use the env keyword to define all the environment variables:

    /// env PATH=c:\windows;c:\tools/// env USERPROFILE=C:\Users\Guest
    

    Specifying the Windows DLL path and environment variables using environment variables An alternative way of configuring the DLLs path and environment variables is to use the IDABXPATHMAP and the IDABXENVMAP environment variables. To specify the path map, export the following environment variable:

    $ export IDABXPATHMAP=/home/lallous/bochs_windir/=c:/windows/system32;\         /home/lallous/dev/idaadv/plugins/bochs/=c:/windows/system32;\         /home/lallous/temp=c:/malware
    

    (Please note that the forward slash (/) will be replaced with a backslash automatically by the plugin) Similarly, specify the environment variables with the IDABXENVMAP environment variable:

    $ export IDABXENVMAP="USERPROFILE=c:/Users/Guest++PATH=c:/windows;c:\tools"
    

    (Please note that we used the ++ to separate between multiple variables)

    In case you require to do specific changes (per database) to the startup file then please take a copy of it and place it in the same directory as the database. Refer to the help IDA Pro help file for more information.

    Debugging Windows Kernel with VMWare and IDA WinDbg Plugin

    Debugging the Windows Kernel with VMWare and IDA WinDbg Plugin

    We will now demonstrate how to debug the kernel through a virtual machine.

    In this example we will be using VMware Workstation 15 Player and Windows 7.

    It is highly recommended to read the article Windows driver debugging with WinDbg and VMWare

    Configuring the virtual machine

    Run the VM and use the bcedit command1 to configure the boot menu as stated in the article.

    vm bcdedit

    Edit the VM hardware settings and add a new serial port with option use named pipe:

    vm settings

    Restart the VM to debug. At the boot prompt, select the menu item containing [debugger enabled] from the boot menu.

    Configuring Windbg debugger plugin

    The connection string com:port=\\.\pipe\com_2,baud=115200,pipe,reconnect for Windbg plugin should refer to the named pipe we set up in the previous steps.

    Starting the debugger step by step

    Start IDA Pro with an empty database:

    > ida64 -t sample.i64
    

    Select the Windbg debugger using “Debugger > Select debugger”:

    windbg select

    Then configure it to use “Kernel mode debugging” debugging in the “Debugger specific options” dialog:

    windbg specific options

    After the debugger is properly configured, edit the process options and set the connection string:

    windbg app setup

    Finally, start debugging using “Debugger > Attach to process”:

    windbg attach

    IDA Pro may display a wait box “Refreshing module list” for some time. Then it will display something like this:

    windbg start

    Starting the debugger using a command line option

    The simplest way to start WinDbg Plugin is to run IDA Pro with the following option:

    > ida64 -rwindbg{MODE=1}@com:port=\\.\pipe\com_2,baud=115200,pipe,reconnect+0 sample.i64
    
    • {MODE=1} means “Kernel mode”
    • +0 means the “<Kernel>” process

    Debugging

    In kernel mode IDA Pro will display one entry in the threads window for each processor.

    For example a two processor configuration2 yields:

    windbg threads

    This screenshot shows how we are debugging the kernel and changing the disassembly listing (renaming stack variables, or using structure offsets):

    disasm listing

    At the end you can detach from the kernel and resume it or detach from the kernel and keep it suspended.

    To detach and resume, simply select the “Debugger > Detach from process”, however to detach and keep the kernel suspended select “Debugger > Terminate Process”.

    Debugging the kernel through kdsrv.exe

    In some cases, when debugging a 64bit kernel using a 1394 cable then 64bit drivers are needed, thus dbgeng (32bits) will not work. To workaround this problem we need to run the kernel debugger server from the x64 debugging tools folder and connect to it:

    • Go to “Debugging Tools (x64)” installation
    • Run kdsrv.exe (change the port number/transport appropriately):
      • kdsrv -t tcp:port=6000
    • Now run ida64 and specify the following connection string (change the transport value appropriately):
      • kdsrv:server=@{tcp:port=6000,server=127.0.0.1},trans=@{com:port=\\.\pipe\com_3,baud=115200,pipe}

    1. or edit the c:\boot.ini file for Windows XP

    2. as was specified in the VM hardware settings

    Debugging Linux Kernel under VMWare using IDA GDB debugger

    Current versions of VMWare Workstation include a GDB stub for remote debugging of the virtual machines running inside it. In version 5.4, IDA includes a debugger module which supports the remote GDB protocol. This document describes how to use it with VMWare. As an example, we’ll debug a Linux kernel.

    Debugging a Linux kernel

    Let’s assume that you already have a VM with Linux installed. Before starting the debugging, we will copy symbols for the kernel for easier navigation later. Copy either /proc/kallsyms or /boot/Sytem.map* file from the VM to host.

    Now edit the VM’s .vmx file to enable GDB debugger stub:

    Add these lines to the file:

    debugStub.listen.guest32 = “TRUE”

    debugStub.hideBreakpoints= “TRUE”

    monitor.debugOnStartGuest32 = “TRUE”

    Save the file.

    In VMWare, click “Power on this virtual machine” or click the green Play button on the toolbar.

    A black screen is displayed since VMWare is waiting for a debugger to connect.

    Start IDA.

    If you get the welcome dialog, choose “Go”.

    Choose Debugger | Attach | Remote GDB debugger.

    Enter “localhost” for hostname and 8832 for the port number.

    Choose <attach to the process started on target> and click OK.

    We land in the BIOS, but since we’re not interested in debugging it, we can skip directly to the kernel. Inspect the kallsyms or System.map file you downloaded from the guest and search for the start_kernel symbol:

    Copy the address, and navigate to it in IDA (Jump | Jump to addres… or just “g”).

    Press F2 or choose “Add breakpoint” from the context menu.

    Check “Hardware breakpoint” and select “Execute” in “Modes”. Click OK.

    Press F9. You will see loading messages and then the execution will stop at the entrypoint.

    Adding symbols

    Symbols are very useful during debugging, and we can use the kallsyms or System.map file to add them to IDA. Go to File | Python command… and paste the following short script (don’t forget to edit the file path):

    ksyms = open(r“D:\kallsyms“) # path to the kallsyms/map file
    &#xNAN;for line in ksyms:
    &#xNAN;if line[9]==‘A’: continue # skip absolute symbols
    &#xNAN;addr = int(line[:8], 16)
    &#xNAN;name = line[11:-1]
    &#xNAN;if name[-1]==‘]’: continue # skip module symbols
    &#xNAN;idaapi.set_debug_name(addr, name)
    &#xNAN;MakeNameEx(addr, name, SN_NOWARN)
    &#xNAN;Message(”%08X: %s\n“%(addr, name))

    Click OK and wait a bit until it finishes. After that you should see the symbols in the disassembly and name list:

    Happy debugging!

    Copyright 2009 Hex-Rays SA

    Windows Debugger Hub

    Since version 4.3, IDA offers a PE Windows debugger in addition to its Windows disassembler. The Windows debugger in IDA combines the power of static disassembly to dynamic debugging to allow its users to debug unknown binaries at a level close to source code. A Linux version of the debugger is also available, there is some more information about it here here

    The Windows Debugger in IDA:

    • is able to debug any file supported by the Windows DBG interface, including true 64 bits files.
    • can benefit from all the features of the Windows Disassembler, including interactivity, scripting and plugins.
    • offer local debugging of Windows executables.
    • can connect to other Windows machines running our remote debugging server and debug Windows executables.
    • can connect to our Linux remote debugging server and allows you to debug Linux executables from a familiar Windows environment.

    Below: the Windows Debugger working locally.

    Below: the Windows Debugger about to debug a remote Linux binary.

    A typical use of the remote Windows debugger would be the analysis of a hostile Linux binary or a hostile Windows binary on a safe and clean machine. The IDA Windows debugger brings unprecedented flexibility and security to the virus analyst. Another typical use of the remote Windows debugger would be Linux debugging in a comfortable, well-known GUI.

    Here are a few links to the IDA Windows Debugger on our site:

    IDA: Linux Debugger

    Since version 4.7, IDA offers a console Linux debugger and a console Linux disassembler (since version 5.1 IDA also offers a Mac OS X debugger and disassembler). The Linux version of IDA brings the power of combined disassembly and debugging to the Linux world.

    The Linux version of IDA:

    • is able to disassemble any file supported by the Windows version.
    • supports all the features of the Windows console version, including interactivity, scripting and plugins.
    • offer local debugging of Linux executables.
    • can connect to Windows machines running our debugging server and debug Windows executables.
    • remote debugging server that allows you to debug Linux programs from another Linux machine, or even a Windows one.

    Below: the Linux Debugger working locally.

    Below: the Windows Debugger about to debug a remote Linux binary.

    Below: the Windows Debugger in a remote debugging session.

    A typical use of the remote linux debugger would be the safe analysis of an hostile Windows binary: the Linux debugger, for example, brings unprecedented flexibility and security to the virus analyst. A typical use of the remote Windows debugger would be Linux debugging in a comfortable, well known GUI.

    The IDA debugger, disassembler and remote debuggers are not sold separately but are included in the normal IDA distribution.

    Debugging a Windows executable locally and remotely

    Debugging a Windows executable locally and remotely

    Last updated on September 01, 2020 - v0.2

    This short tutorial introduces the main functionality of the IDA Debugger on Windows. IDA supports debugging of various binaries on various platforms, locally and remotely, but in this tutorial we will focus on debugging regular applications running on Windows.

    Let’s see how the debugger can be used to locally debug a simple buggy C console program compiled under Windows.

    Please use sample.exe.idb from samples.zip:

    {% file src=“samples.zip” %}

    to follow this tutorial.

    The buggy program

    This program computes averages of a set of values (1, 2, 3, 4 and 5). Those values are stored in two arrays: one containing 8 bit values, the other containing 32-bit values.

    #include <stdio.h>
    
    char char_average(char array[], int count)
    {
      int i;
      char average;
      average = 0;
      for (i = 0; i < count; i++)
      average += array[i];
      average /= count;
      return average;
    }
    
    int int_average(int array[], int count)
    {
      int i, average;
      average = 0;
      for (i = 0; i < count; i++)
      average += array[i];
      average /= count;
      return average;
    }
    
    void main(void)
    {
      char chars[] = { 1, 2, 3, 4, 5 };
      int integers[] = { 1, 2, 3, 4, 5 };
      printf("chars[] - average = %d\n",
      char_average(chars, sizeof(chars)));
      printf("integers[] - average = %d\n",
      int_average(integers, sizeof(integers)));
    }
    

    Running this program gives us the following results:

    >sample.exe
    chars[] - average = 3
    integers[] - average = -65498543
    

    Obviously, the computed average on the integer array is wrong. Let us use the IDA debugger to understand the origin of this error.

    Loading the file

    The debugger is completely integrated into IDA: to debug, we usually load the executable into IDA and create a database. We can disassemble the file interactively, and all the information which he will have added to the disassembly will be available during debugging. If the disassembled file is recognized as debuggable, the Debugger menu automatically appears in main window:

    debugger menu

    Since IDA has many debugger backends, we have to select the desired backend. We will use Local Windows debugger in our tutorial:

    select debugger

    Instruction breakpoints

    Once we located our int_average() function in the disassembly (it is at 0x40104A), we can add a breakpoint at its entry point, by selecting the Add breakpoint command in the popup menu, or by pressing the F2 key:

    add bpt

    Program execution

    Now we can start the execution. We can launch the debugger by pressing the F9 key or by clicking the Start button in the debugger toolbar. IDA displays a big warning message before really starting the debugger:

    debugger warning

    Indeed, running untrusted binaries on your computer may compromise it, so you should never run them. Since in our tutorial we are playing with a toy sample, it is okay, we can accept him. However, please consider using remote debugging for untrusted binaries.

    Once we accept it, the program runs until it reaches our breakpoint:

    start debugger

    Address evaluation

    By analyzing the disassembled code, we can now locate the loop which computes the sum of the values, and stores the result in EAX. The [edx+ecx*4] operand clearly shows us that EDX points to the array and ECX is used as an index in it. Thus, this operand will successively point to each integer from the integers array:

    loop header

    Step by step and jump targets

    Let us advance step by step in the loop, by clicking on the adequate button in the debugger toolbar or by pressing the F8 key. If necessary, IDA draws a green arrow to show us the target of a jump instruction:

    green arrow

    The bug uncovered

    Now, let’s have a look at value of [esp+count]. The ECX register (our index in the array) is compared to this register at each iteration: so, we can conclude that it is used as a counter in the loop. But, we also observe that it contains a rather strange number of elements: 14h (= 20). Remember that our original array contains only 5 elements! It seems we just found the source of our problem…​

    compare to 20

    Hardware breakpoints

    To be sure, let us add a hardware breakpoint, just behind the last value of our integers array (in fact, on the first value of the chars array). If we reach this breakpoint during the loop, it will indeed prove that we read integers outside our array. For that jump to EDX, which points to the array, by clicking on a small arrow in the CPU register view:

    jump to edx

    IDA displays a sequence of bytes, so we need to create an array. Do the following:

    • press Alt-D, D to create a doubleword
    • press * and specify the size of 5 elements
    create array

    Let us add a hardware breakpoint with a size of 4 bytes (the size of an integer) in Read/Write mode immediately after our array. Please note that the cursor is located after the array we created:

    add hwbpt

    As foreseen, if we continue the execution, the hardware breakpoint detects a read access to the first byte of the chars array.

    hwbpt hit

    Please note that EIP points to the instruction following the one which caused the hardware breakpoint! It is in fact rather logical: to cause the hardware breakpoint, the preceding instruction has been fully executed, so EIP now points to the next one.

    hwbpt hit2

    Caller’s mistake

    By looking at the disassembly, we see that the value stored in [esp+count] comes from the count argument of our int_average() function. Let us try to understand why the caller gives us such a strange argument: if we go the call of int_average(), we easily locate the push 14h instruction, passing an erroneous count value to our function.

    buggy push

    Now, by looking closer at the C source code, we understand our error: we used the sizeof() operator, which returns the number of bytes in the array, rather than returning the number of items in it! As, for the chars array, the number of bytes was equal to the number of items, we didn’t notice the error…​

    Debugging a remote process

    Our debuggers support debugging processes running on a remote computer. We just need to set up a remote debugging session and then we can debug the same way as in local debugging. Let us consider the following three simple steps.

    Starting the remote server

    Regardless of the platform where IDA itself runs (be it Windows, Mac, or Linux), we need to launch a remote debugger server on the computer where the remotely debugged application will run.

    For Windows, we have two different debugger servers:

    • for 32-bit programs, use win32_remote.exe
    • for 64-bit programs, use win64_remote64.exe

    So, we copy the relevant debugger server to the remote computer and launch it:

    starting the server

    If the debugger server is accessible by others, it is a good idea to use a password for the connection (the -P command line option).

    Once this is done, we can return to the local computer, where we will run IDA, and configure it.

    Configuring IDA to connect to the remote server

    We have to select the Remote Windows debugger:

    selecting remote debugger

    and specify the correct values in the Debugger > Process options dialog:

    setting remote host and port

    Please note that the Application, Input file, and Directory must be correct on the remote computer. We may eventully specify command line arguments for the application in the Parameters field.

    If you have specified a password when launching the remote debugger server, you must specify it in the Password field.

    Starting a debug session

    Once we have configured IDA, the rest is the same as with local debugging: press F9 to start a debugging session.

    Attaching to a running process

    In some cases we cannot launch the debugged process ourselves. Instead, we need to attach to an existing process. This is possible and very easy to do: just select Debugger > Attach to process from the menu and select the desired process.

    Other features

    IDA debugger gives you access to the entire process memory, allowing you to use all powerful features: you can create structure variables in memory, draw graphs, create breakpoints in DLLs, define and decompile functions, etc. It is even possible to single step in the pseudocode window, if you have the decompiler installed!

    pseudocode step

    The way the debugger reacts to exceptions is fully configurable by the user. The user can select various Actions to be performed when the breakpoint is hit. An IDC or Python can be executed upon hitting a breakpoint:

    bpt script

    We invite you to play with the debugger and discover its many unique and powerful features!

    Debugging the XNU Kernel with IDA Pro

    Copyright 2019 Hex-Rays SA

    Purpose

    IDA 7.3 introduces the Remote XNU Debugger. It is designed to communicate with the GDB stub included with popular virtualization tools, namely VMWare Fusion (for OSX) and Corellium (for iOS). The debugger allows you to observe the Darwin kernel as it is running, while at the same time utilising the full power of IDA’s analysis capabilities. It works equally well on Mac, Windows, and Linux.

    This writeup is intended to quickly get you familiar with debugger, as well as offer some hints to make the experience as smooth as possible.

    Debugging OSX with VMWare

    To get started with debugging OSX, we will perform a simple experiment. This is the same experiment outlined in this great writeup by GeoSn0w, but we will be performing the equivalent in IDA - which we hope you’ll find is much simpler.

    Begin with the following setup:

    1. create an OSX virtual machine with VMWare Fusion. in this example the virtual machine is OSX 10.13.6, but the experiment should work with any recent OSX version.

    2. open Terminal in the VM and enable some basic XNU debugging options:

      $ sudo nvram boot-args="slide=0 debug=0x100 keepsyms=1"
      
    3. shut down the VM and add the following line to the .vmx file:

      debugStub.listen.guest64 = "TRUE"
      
    4. power on the virtual machine, open Terminal, and run this command:

       $ uname -v
       Darwin Kernel Version 17.7.0 ... root:xnu-4570.71.17~1/RELEASE_X86_64	
      

      Let’s use IDA to modify this version string.

    Launch IDA, and when prompted with the window IDA: Quick start, choose Go to start with an empty database. Then go to menu Debugger>Attach>Remote XNU Debugger and set the following options:

    Click OK, then select <attach to the process started on target>, and wait for IDA to attach. This step might take a few seconds (later we’ll discuss how to speed things up). Once attached, the target is usually suspended in machine_idle:

    IDA should have printed the message FFFFFF8000200000: process kernel has started, meaning it successfully detected the kernel image in memory. Now let’s find the version string. Conveniently, the string appears in the kernel’s symbol table, so we can simply use shortcut G and enter the name _version to jump right to it:

    Use IDAPython to overwrite the bytes at this address:

    idaapi.dbg_write_memory(0xFFFFFF8000AF6A00, "IDAPRO")
    

    Resume the process and allow the VM to run freely. Go back to Terminal in the VM and run the same command as before:

    $ uname -v
    IDAPRO Kernel Version 17.7.0 ... root:xnu-4570.71.17~1/RELEASE_X86_64
    

    The output should look almost the same, except Darwin has been replaced with IDAPRO. So, we have modified kernel memory without breaking anything! You can continue to explore memory, set breakpoints, pause and resume the OS as you desire.

    Using the KDK

    If you have installed a Kernel Development Kit from Apple, you can set KDK_PATH in dbg_xnu.cfg to enable DWARF debugging:

    KDK_PATH = "/Library/Developer/KDKs/KDK_10.13.6_17G4015.kdk";
    

    Even if there is no KDK available for your OSX version, you can still utilise the KDK_PATH option in IDA to speed up debugging. For example, in the experiment above we could have done the following:

    1. make your own KDK directory:

      $ mkdir ~/MyKDK
      
    2. copy the kernelcache from your VM:

      $ scp user@vm:/System/Library/PrelinkedKernels/prelinkedkernel ~/MyKDK
      
    3. decompress the kernelcache:

      $ kextcache -c ~/MyKDK/prelinkedkernel -uncompressed
      
    4. set KDK_PATH in dbg_xnu.cfg:

      KDK_PATH = "~/MyKDK";
      

    Now whenever IDA needs to extract information from the kernel or kexts, it will parse the kernelcache file on disk instead of parsing the images in memory. This should be noticeably faster.

    Debugging a Development Kernel

    Our next goal is to use the KDK to create a rich database that can be used to debug XNU in greater detail. In this example we will debug the development kernel included in the Apple KDK. Let’s open this file in IDA:

    $ export KDK=/Library/Developer/KDKs/KDK_10.13.6_17G4015.kdk
    $ export KERNELS=$KDK/System/Library/Kernels
    $ ida64 -okernel.i64 $KERNELS/kernel.development
    

    Wait for IDA to load the DWARF info and complete the autoanalysis. This may take a few minutes, but we only need to do it once.

    While we wait, we can prepare the virtual machine to use the development kernel instead of the release kernel that is shipped with OSX (Note: System Integrity Protection must now be disabled in the VM). Open Terminal in the VM and run the following commands:

    1. copy the development kernel from the KDK:

      $ sudo scp user@host:"\$KERNELS/kernel.development" /System/Library/Kernels/
      
    2. reconstruct the kernelcache:

      $ sudo kextcache -i /
      
    3. reboot:

      $ sudo shutdown -r now
      
    4. after rebooting, check that the development kernel was properly installed:

       $ uname -v
       ... root:xnu-4570.71.17~1/DEVELOPMENT_X86_64
      

    The VM is now ready for debugging.

    IDA Configuration

    Return to IDA and use Debugger>Select debugger to select Remote XNU Debugger. Then open Debugger>Process options and set the following fields:

    Now go to Debugger>Debugger options>Set specific options and make sure the KDK path field is set:

    You can ignore the other options for now, and press OK.

    Assembly-Level Debugging + DWARF

    IDA supports source-level debugging for the XNU Kernel. However for demonstration purposes we will focus on assembly-level debugging, while taking advantage of source-level DWARF information like local variables. This is a bit more stable, and is still quite useful.

    Before attaching the debugger, open Options>Source paths… and un-check the checkbox:

    Then click Apply. This will prevent IDA from complaining when it can’t find a source file.

    Finally, select Debugger>Attach to process>attach to the process started on target. After attaching, jump to function dofileread, and use F2 to set a breakpoint. Resume the debugger and and wait for the breakpoint to be hit (typically it will be hit right away, if not try simply running a terminal command in the guest). Once XNU hits our breakpoint, open Debugger>Debugger windows>Locals:

    We can now perform detailed instruction-level debugging with the assistance of DWARF. You can continue to single step, set breakpoints, and inspect or modify local variables just like any other IDA debugger.

    KEXT Debugging

    IDA also supports debugging kext binaries. To demonstrate this, we will debug IONetworkingFamily, a submodule of IOKit that is typically shipped with the KDK. Begin by opening the binary in IDA:

    $ export KEXTS=$KDK/System/Library/Extensions
    $ ida64 -onet.i64 $KEXTS/IONetworkingFamily.kext/Contents/MacOS/IONetworkingFamily
    

    Select Remote XNU Debugger from the debugger menu. Then in Debugger>Process options, set:

    Note that we provide the bundle ID of the kext (com.apple.iokit.IONetworkingFamily) as the Input file field. This allows the debugger to easily identify the target kext at runtime.

    Also note that loading all kexts in kernel memory can be a slow operation, which is why it is disabled by default. Open Debugger>Debugger options>Set specific options and ensure the KDK path field is set, then set the KEXT Debugging option to KDK only:

    This tells the debugger to only load kexts that are present in the KDK. Since the KDK binaries are on the local filesystem, IDA can parse the kexts in a negligible amount of time - which is ideal since we’re really only interested in IONetworkingFamily.

    Now power on your VM and allow it to boot up. Once it is running idle, attach the debugger. Immediately IDA should detect the kernel and all relevant kexts in memory, including IONetworkingFamily:

    Double-click to bring up the debug names for this module, and search for IONetworkInterface::if_ioctl:

    Now set a breakpoint at this function and resume the OS. Typically the breakpoint will be hit right away, but if it isn’t try performing an action that requires a network interface (for instance, performing a google search). Once execution breaks in the kext we can use the database to debug it in detail:

    Debugging a Prelinked Kernelcache

    For simplicity, all of the examples up until now have dealt with a subset of the kernel, but it is also possible to load a complete prelinked kernelcache in IDA and debug it. Naturally, we have some suggestions for this.

    Extending the KDK

    If you’re interested in debugging the entire prelinked kernel, the biggest concern is speed. IDA must create a detailed and accurate depiction of kernel memory, which could contain hundreds of kext modules. If we’re not careful, this can be slow.

    Fortunately there is an easy solution. Try the following:

    1. create a writable copy of Apple’s KDK:

      $ cp -r /Library/Developer/KDKs/KDK_10.13.6_17G4015.kdk ~/MyKDK
      
    2. copy the kernelcache from your VM to the new KDK:

      $ scp user@vm:/System/Library/PrelinkedKernels/prelinkedkernel ~/MyKDK
      
    3. decompress the kernelcache:

      $ kextcache -c ~/MyKDK/prelinkedkernel -uncompressed
      

    Now IDA can use both the KDK and the kernelcache to extract debugging information for almost any kext at runtime. This should be fast.

    Loading the Kernelcache

    When loading a kernelcache, IDA now offers more load options:

    In this example we want to load everything, so choose the kernel + all kexts option and wait for IDA to load all the subfiles and finish the autoanalysis. This will take a while but there’s no way around it, it’s a lot of code.

    IMPORTANT NOTE: Try to avoid saving the IDA database file in the KDK directory. It is important to keep irrelevant files out of the KDK since they might slow down IDA’s KDK parsing algorithm.

    Now we might want to improve the static analysis by loading DWARF info from the KDK. In IDA 7.3 the dwarf plugin supports batch-loading all DWARF info from a KDK into a kernelcache database. Currently this feature must be invoked manually, so we have provided this script to make it easier.

    Copy kdk_utils.py to the plugins directory of your IDA installation. This plugin will create a new menu Edit>Other>KDK utils, with two new menu actions:

    • Load KDK: This action will automatically detect all matching DWARF files in a given KDK, then apply the DWARF info to the subfiles in the database (including the kernel itself).
    • Load DWARF for a prelinked KEXT: This action is useful if you have DWARF info for a prelinked kext that is not included in Apple’s KDK. For a given DWARF file, the action will find a matching kext in the database and apply the DWARF info to this subfile.

    Try opening Edit>Other>KDK utils>Load KDK and provide the KDK path:

    Wait for IDA to scan the KDK for matching DWARF files and load them. This operation can also take a while, but it’s worth it for all the extra structures, prototypes, and names that are added to the database. In the end we have a very detailed database that we are ready to use for debugging.

    Now open Debugger>Process options and set the following options:

    Then open Debugger>Debugger options>Set specific options and set the following fields:

    Note that we set the KEXT Debugging option to all. This tells the debugger to detect every kext that has been loaded into memory and add it to the Modules list, including any non-prelinked kexts (there are likely only a handful of them, so it doesn’t hurt).

    Finally, power on the VM and attach to it with Debugger>Attach to process>attach to the process started on target. IDA should be able to quickly generate modules for the kernel and all loaded kexts:

    You are now free to explore the entire running kernel! Try performing any of the previous demos in this writeup. They should work about the same, but now they are all possible with one single database.

    Kernel ASLR + Rebasing

    It is worth noting that rebasing has been heavily improved in IDA 7.3. Even large databases like the one we just created can now be rebased in just a few seconds. Previous IDA versions would take quite a bit longer. Thus, IDA should be able to quickly handle kernel ASLR, even when working with prelinked kernelcaches.

    Debugging the OSX Kernel Entry Point

    In this example we demonstrate how to gain control of the OS as early as possible. This task requires very specific steps, and we document them here. Before we begin, we must make an important note about a limitation in VMWare’s GDB stub.

    Physical Memory

    Currently VMWare’s 64-bit GDB stub does not allow us to debug the kernel entry point in physical memory. According to VMWare’s support team, the correct approach is to use the 32-bit stub to debug the first few instructions of the kernel, then switch to a separate debugger connected to the 64-bit stub once the kernel switches to 64-bit addressing.

    Since IDA’s XNU debugger does not support 32-bit debugging, this approach is not really feasible (and it’s not very practical anyway).

    Workaround

    Rather than add support for the 32-bit stub just to handle a few instructions, the official approach in IDA is to break at the first function executed in virtual memory (i386_init). This allows us to gain control of the OS while it is still in the early stages of initialization, which should be enough for most use cases.

    Here’s how you can do it:

    1. Disable ALSR for the kernel. Open Terminal in the VM and run the following command:

      sudo nvram boot-args="slide=0"
      

      Then power off the VM.

    2. Add this line to the .vmx file:

      debugStub.hideBreakpoints = "TRUE"
      

      This ensures that hardware breakpoints are enabled in the GDB stub. For most versions of VMWare, TRUE is the default value, but it’s better to be safe.

    3. Also add this line to the .vmx file:

      monitor.debugOnStartGuest64 = "TRUE"
      

      This will tell VMWare to suspend the OS before it boots.

    4. Power on the VM. It will remain suspended until we attach the debugger.

    5. Load a kernel binary in IDA, and set the following XNU debugger options:

      Note that we un-checked the Debug UEFI option. This option is explained in detail in the UEFI Debugging section, but for now just ensure it is disabled. This will prevent IDA from doing any unnecessary work.

    6. Attach the debugger. The VM will be suspended in the firmware before the boot sequence has begun:

    7. Now jump to the function _i386_init and set a hardware breakpoint at this location:

      idaapi.add_bpt(here(), 1, BPT_EXEC)
      

      We must use a hardware breakpoint because the kernel has not been loaded and the address is not yet valid. This is why steps 1 and 2 were important. It ensures the stub can set a breakpoint at a deterministic address, without trying to write to memory.

    8. Resume the OS, and wait for our breakpoint to be hit:

      IDA should detect that execution has reached the kernel and load the kernel module on-the-fly. You can now continue to debug the kernel normally.

    UEFI Debugging

    It is possible to debug the EFI firmware of a VMWare Fusion guest. This gives us the unique opportunity to debug the OSX bootloader. Here’s how it can be easily done in IDA:

    First copy the bootloader executable from your VM:

    $ scp user@vm:/System/Library/CoreServices/boot.efi .
    

    Now shut down the VM and add this line to the .vmx file:

    monitor.debugOnStartGuest64 = "TRUE"
    

    Load the boot.efi binary in IDA, open Debugger>Debugger options, check Suspend on library load/unload, and set Event condition to:

    get_event_id() == LIB_LOADED && get_event_module_name() == "boot"
    

    This will suspend the OS just before the bootloader entry point is invoked. Note: For some older versions of OSX, the bootloader will be named “boot.sys”. You can check the name under the .debug section of the executable.

    Now select Remote XNU Debugger from the Debugger menu, and set the following fields in Debugger>Process options:

    We’re now ready to start debugging the bootloader. Power on the VM (note that the VM is unresponsive since it is suspended), and attach to it with Debugger>Attach to process. After attaching IDA will try to detect the EFI_BOOT_SERVICES table. You should see the debugger print something like this to the console:

    7FFD7430: EFI_BOOT_SERVICES
    

    Now resume the process. You should see many UEFI drivers being loaded, until eventually boot.efi is loaded and IDA suspends the process:

    At this point, the bootloader entry point function is about to be invoked. Jump to _ModuleEntryPoint in boot.efi and press F4. We can now step through boot.efi:

    GetMemoryMap

    To facilitate UEFI debugging, IDA provides an IDC helper function: xnu_get_efi_memory_map. This function will invoke EFI_BOOT_SERVICES.GetMemoryMap in the guest OS and return an array of EFI_MEMORY_DESCRIPTOR objects:

    IDC>extern map;
    IDC>map = xnu_get_efi_memory_map();
    IDC>map.size
         35.       23h          43o
    IDC>map[4]
    object
    	Attribute: 0xFi64
    	NumberOfPages: 0x30B6i64
    	PhysicalStart: 0x200000i64
    	Type: "EfiLoaderData"
    	VirtualStart: 0x0i64
    IDC>map[27]
    object
    	Attribute: 0x800000000000000Fi64
    	NumberOfPages: 0x20i64
    	PhysicalStart: 0x7FF09000i64
    	Type: "EfiRuntimeServicesCode"
    	VirtualStart: 0x0i64
    	
    

    This function can be invoked at any point during firmware debugging.

    UEFI Debugging + DWARF

    If you build your own EFI apps or drivers on OSX, you can use IDA to debug the source code.

    In this example we will debug a sample EFI application. On OSX the convention is to build EFI apps in the Mach-O format, then convert the file to PE .efi with the mtoc utility. In this example, assume we have an EFI build on our OSX virtual machine that contains the following files in the ~/TestApp directory:

    • TestApp.efi - the EFI application that will be run
    • TestApp.dll - the original Mach-O binary
    • TestApp.dll.dSYM - DWARF info for the app
    • TestApp.c - source code for the app

    Here’s how we can debug this application in IDA:

    1. On your host machine, create a directory that will mirror the directory on the VM:

      mkdir ~/TestApp
      
    2. Copy the efi, macho, dSYM, and c files from your VM:

      scp -r vmuser@vm:TestApp/TestApp.* ~/TestApp
      
    3. Open the TestApp.efi binary in IDA, and wait for IDA to analyze it.

      Note that you can improve the disassembly by loading the DWARF file from TestApp.dll.dSYM. You can do this with Edit>Plugins>Load DWARF file, or you can load it programatically from IDAPython:

      path = "~/TestApp/TestApp.dll.dSYM/Contents/Resources/DWARF/TestApp.dll"
      node = idaapi.netnode()
      node.create("$ dwarf_params")
      node.supset(1, os.path.expanduser(path))
      idaapi.load_and_run_plugin("dwarf", 3)
      
    4. Select Remote XNU Debugger from the debugger menu, and set the following fields in Debugger>Process options:

    5. In Debugger>Debugger options, enable Suspend on library load/unload and set the Event condition field to:

      get_event_id() == LIB_LOADED && get_event_module_name() == "TestApp"
      
    6. In Debugger>Debugger options>Set specific options, set the following fields:

      Note that we must enable the Debug UEFI option, and set the UEFI symbols option so the debugger can find DWARF info for the EFI app at runtime.

    7. If the usernames on the host and VM are different, we will need a source path mapping:

      idaapi.add_path_mapping("/Users/vmuser/TestApp", "/Users/hostuser/TestApp")
      
    8. Reboot the VM and enter the EFI Shell

    9. Attach the debugger. After attaching IDA will detect the firmware images that have already been loaded:

    10. Resume the OS and launch TestApp from the EFI Shell prompt:

      Shell>fs1:\Users\vmuser\TestApp\TestApp.efi
      

      At this point IDA will detect that the target app has been loaded, and suspend the process just before the entry point of TestApp.efi (because of step 5).

    11. Now we can set a breakpoint somewhere in TestApp.efi and resume the OS. The debugger will be able to load source file and local variable information from TestApp.dll.dSYM:

      IMPORTANT NOTE: You must wait until TestApp has been loaded into memory before setting any breakpoints. If you add a breakpoint in the database before attaching the debugger, IDA might not set the breakpoint at the correct address. This is a limitation in IDA that we must work around for now.

    Debugging iOS with Corellium

    IDA can also debug the iOS kernel, provided you have access to a virtual iOS device from Corellium.

    To get started with debugging iOS, we will perform a simple experiment to patch kernel memory. The device used in this example is a virtual iPhone XS with iOS 12.1.4, but it should work with any model or iOS version that Corellium supports. Begin by powering on your device and allow it to boot up. In the Corellium UI, look for the line labeled SSH under Advanced options:

    Ensure you can connect to the device by running this command over ssh:

    $ ssh [email protected] uname -v
    Darwin Kernel Version 18.2.0 ... root:xnu-4903.242.2~1/RELEASE_ARM64_T8020
    

    We will use IDA to patch this version string.

    Now launch IDA, and when prompted with the window IDA: Quick start, choose Go to start with an empty database and open Debugger>Attach>Remote XNU Debugger. In the Corellium UI, find the hostname:port used by the kernel GDB stub. It should be specified in the line labeled kernel gdb:

    And set the Hostname and Port fields in IDA’s application setup window:

    Now click on Debug options>Set specific options, and for the Configuration dropdown menu, be sure to select Corellium-ARM64:

    You can ignore the other config options for now, and click OK.

    Click OK again, and wait for IDA to establish a connection to Corellium’s GDB stub (this may take a few seconds). Then select <attach to the process started on target> and wait for IDA to attach. This might take several seconds (we will address this later), but for now simply wait for IDA to perform the initial setup.

    If IDA could detect the kernel, it should appear in the Modules list:

    and the kernel version will be printed to the console:

    FFFFFFF007029FD7: detected Darwin Kernel Version 18.2.0 ...
    

    Navigate to this address and use IDAPython to overwrite the string:

    idaapi.dbg_write_memory(0xFFFFFFF007029FD7, "IDAPRO")
    

    Resume the OS, and try running the same command as before:

    $ ssh [email protected] uname -v
    IDAPRO Kernel Version 18.2.0 ... root:xnu-4903.242.2~1/RELEASE_ARM64_T8020
    

    If we could successfully write to kernel memory, IDAPRO should appear in the output.

    Creating a KDK for iOS

    Typically a Kernel Development Kit is not available for iOS devices, but we can still utilise the KDK_PATH option in IDA to achieve faster debugging. In the example above, the initial attach can be slow because IDA must parse the kernel image in memory (which can be especially slow if the kernel has a symbol table).

    Here’s how you can speed things up:

    1. create the KDK directory:

      $ mkdir ~/iPhoneKDK
      
    2. copy the kernelcache from the virtual device:

      $ scp root@ip:/System/Library/Caches/com.apple.kernelcaches/kernelcache /tmp
      
    3. uncompress the kernelcache with lzssdec:

      $ lzssdec -o OFF < /tmp/kernelcache > ~/iPhoneKDK/kernelcache
      
    4. set KDK_PATH in dbg_xnu.cfg:

      KDK_PATH = "~/iPhoneKDK";
      

    Now whenever the debugger must extract information from the kernel, it will parse the local file on disk. This should be noticeably faster, especially if the device is hosted by Corellium’s web service.

    Debugging the iOS Kernel Entry Point

    Corellium allows us to debug the first few instructions of kernel initialization. This can be very useful if we want to gain control of the OS as early as possible. In the Corellium UI, power on your device with the Start device paused option:

    Now start IDA with an empty database and attach to the suspended VM:

    From the XNU source, this is likely the _start symbol in osfmk/arm64/start.s, which simply branches to start_first_cpu. After stepping over this branch:

    Press shortcut P to analyze start_first_cpu. This is where the kernel performs its initial setup (note that the value in X0 is a pointer to the boot_args structure). This function is interesting because it is responsible for switching the kernel to 64-bit virtual addressing. Typically the switch happens when this function sets X30 to a virtual address, then performs a RET:

    Use F4 to run to this RET instruction. In this example X30 will now point to virtual address 0xFFFFFFF007B84474. After single stepping once more, we end up in arm_init in virtual memory:

    After this single step, IDA detected that execution reached the kernel’s virtual address space and automatically initialized the debugging environment. In this case a message will be printed to the console:

    FFFFFFF007004000: process kernel has started
    

    This signifies that IDA successfully detected the kernel base and created a new module in the Modules list. If the kernel has a symbol table, debug names will be available. Also note that PC now points inside the segment __TEXT_EXEC:__text instead of MEMORY, because the debugger parsed the kernel’s load commands to generate proper debug segments.

    Now that we know the address of arm_init, we can streamline this task:

    1. power on the device with Start device paused

    2. attach to the paused VM

    3. set a hardware breakpoint at arm_init:

      idaapi.add_bpt(0xFFFFFFF007B84474, 1, BPT_EXEC)
      
    4. resume, and wait for the breakpoint to be hit

    This gives us a quick way to break at the first instruction executed in virtual memory. You can continue debugging iOS as normal.

    Known Issues and Limitations

    Here is a list of known shortcomings in the XNU Debugger. Eventually we will address all of them, but it is unlikely we will resolve all of them by the next release. If any of the following topics are important to you, please let us know by sending an email to [email protected]. Issues with vocal support from our users are automatically prioritised.

    iBoot debugging

    Debugging the iOS firmware/bootloader is not yet supported. An On-Premise Corellium box is required for this functionality, so we will only implement it if there is significant demand.

    32-bit XNU

    The XNU Debugger does not support debugging 32-bit XNU. Since pure 32-bit OSes are quite outdated it is unlikely we will support them unless there is exceptional demand.

    KDP

    The XNU Debugger relies on the Remote GDB Protocol, and currently Apple’s Kernel Debugging Protocol (KDP) is not supported. It is possible to add KDP support to IDA in the future.

    Remote debugging with IDA Pro

    Remote debugging is the process of debugging code running on one networked computer from another networked computer:

    • The computer running the IDA Pro interface will be called the “debugger client”.
    • The computer running the application to debug will be called the “debugger server”.

    Remote debugging will be particularly useful in the following cases:

    • To debug virus/trojans/malwares : in this way, the debugger client will be as isolated as possible from the compromised computer.
    • To debug applications encountering a problem on one computer which is not duplicated on other computers.
    • To debug distributed applications.
    • To always debug from your main workstation, so you won’t have to duplicate IDA configuration, documentation and various debugging related resources everywhere.
    • In the future, to debug applications on more operating systems and architectures.

    This small tutorial will present how to setup and use remote debugging in practice.

    The remote IDA debugger server

    In order to allow the IDA client to communicate with the debugger server over the network, we must first start a small server which will handle all low-level execution and debugger operations.

    Debugger servers

    The IDA distribution ships with the following debugger servers:

    • For Windows: win32_remote32 (x86), win64_remote.exe (x64)
    • For Linux: linux_server32 (x86), linux_server (x64), armlinux_server32 (ARM), armlinux_server (ARM64)
    • For Android: android_x86_server, android_x64_server, android_server32 (ARM), android_server (ARM64)
    • For Mac: mac_server (x64), mac_server_arm (ARM64), mac_server_arme (ARM64e)

    With these, we can:

    • Locally debug applications and shared libraries from the IDA graphical and text versions.
    • Remotely debug applications and shared libraries from the IDA graphical and text versions.

    So let’s first copy the small x64 Windows debugger server file to our debugger server.

    This server accepts various command line arguments:

    C:\> win64_remote -?
    IDA Windows 64-bit remote debug server(MT) v9.0.30. Hex-Rays (c) 2004-2024
    Usage: win64_remote [options]
      -p ...  (--port-number ...) Port number
      -i ...  (--ip-address ...) IP address to bind to (default to any)
      -c ...  (--certchain-file ...) TLS certificate chain file
      -k ...  (--privkey-file ...) TLS private key file
      -v      (--verbose) Verbose mode
      -t      (--no-tls) Use plain, unencrypted TCP connections
      -P ...  (--password ...) Password
      -k      (--on-broken-connection-keep-session) Keep debugger session alive when connection breaks
      -K      (--on-stop-kill-process) Kill debuggee when closing session
    

    Let’s start it by specifying a password, to avoid unauthorized connections:

    C:\>win64_remote -Pmypassword
    IDA Windows 64-bit remote debug server(MT) v9.0.30. Hex-Rays (c) 2004-2024
    2024-11-04 03:20:51 Listening on 0.0.0.0:23946 (my ip 172.20.156.1)...
    

    Note that the remote debugger server can only handle one debugger session at a time. If you need to debug several applications simultaneously on the same host, launch several servers on different network ports by using the -p switch.

    Setting up the debugger client.

    First, we copy the executable we want to debug from the debugger server (Windows or Linux) to the debugger client (Windows or Linux). We can then load this file into IDA, as usual. To setup remote debugging, we select the ‘Process options…’ menu item in the Debugger menu:

    Specify the Application and Directory paths. Note that these file paths should be valid on the remote debugger server. Also do not forget to enter the host name or IP address of the debugger server: remote debugging will only be enabled if these settings are specified ! You also might have to open the TCP port in the remote machine firewall. Finally, we enter the password we chose for the remote IDA debugger server.

    Starting remote debugging.

    Both debugger server and debugger client are now ready to start a remote debugging session. In fact, you can now use all debugger related commands as you would with the local Windows PE debugger or local Linux debugger! For example,we can run the process until RIP reaches the application entry point, by jumping to this entry point then pressing the F4 key:

    If we now directly terminate the process (by pressing CTRL-F2) and look at win64_remote’s output (on the debugger server), we indeed properly observe it accepted then closed our network connection:

    C:\\> .\win64_remote.exe -Pmypassword
    IDA Windows 64-bit remote debug server(MT) v9.0.30. Hex-Rays (c) 2004-2024
    2024-11-04 03:20:51 Listening on 0.0.0.0:23946 (my ip 172.20.156.1)...
    2024-11-04 03:29:26 [1] Accepting connection from 172.20.144.1...
    2024-11-04 03:37:56 [1] Closing connection from 172.20.144.1...
    

    Attaching to a running process.

    Another interesting possibility is to attach to an already running process on the remote computer. If you click on the ‘Attach to process…’ command from the Debugger menu, IDA will display a listing of all remote running processes, you can then filter to choose the one you want to attach to (notepad.exe in this case):

    Double clicking on a process from the list will automatically suspend the process and attach to it, allowing you to debug it without starting it manually.

    Detaching from the debugged process.

    Finally, if the debugger server is running Windows XP, Windows Server 2003 or Linux, you can also detach from a process you were currently debugging, simply by using the ‘Detach from process’ command in the Debugger menu:

    On Windows, please note that IDA can also attach to Windows services running either locally or remotely. In particular, the ‘Detach from process’ command will be especially useful if you previously attached to a Windows service: it will allow you to stop the debugger without terminating a critical Windows service on the debugger server!

    IDA Scriptable Debugger: overview

    Debugging facilities in IDA 4.9 and 4.9 SP

    Since we enhanced the usability of IDA remote debugging options, many possibilities are now open. Explore the graph below to discover some of the possible connections.

    • instant debugging, no need to wait for the analysis to be complete to start a debug session.
    • easy connection to both local and remote processes.
    • support for 64 bits systems and new connection possibilities.
    • WindowCE remote debugging

    click on the links below to explore some of the remote debugging features.

    previewdebugger

    IDA Scriptable Debugger: scriptability

    Since 2003 IDA offers a debugger that complements the static analysis nicely. In many cases, one just can’t beat dynamic analysis. The IDA Debugger now supports 32-bit and 64-bit MS Windows executablesMS Windows, Linux, Mac OS X both locally and remotely. However, because the debugger API requires the mastery of our SDK and uses an event based model, it has proved quite difficult to use for some of our users.

    • because the API uses an event based model makes it hard to program a linear sequence of actions in a natural way. The user is forced to install an event handler and to implement a finite state machine that implements the core logic of his plugin. While this may, in many ways, be a more powerful approach, this is probably too complex for more mundane tasks.
    • because the API is only available at the plugin level, the simplest debugger actions requires writing a plugin which is a much bigger investment of time and efforts than writing a small IDC script.

    IDA 5.2 will address both issues. The old event based model will remain available, but a simpler linear model will become available thanks to the function get_debugger_event(). This function pauses the execution of the plugin (or the script) until a new debugger event happens. The user can specify if she is interested only in the events that suspend the process or in all events. A timeout can also be confifured, after which the execution will continue if no event arose.

    The new function allows us to drop the event based model (except in the cases when it is superior to linear logic) and write IDC scripts to control the debugger. For example, to launch the debugger, run to a specific location, print some data and single step twice, the following lines will suffice:

      AppBpt(some_address);
      StartDebugger("","","");         // start debugger with default params
      GetDebuggerEvent(WFNE_SUSP, -1); // ... and wait for bpt
      Message ("Stopped at %a, event code is %x\n", GetEventEA(), GetEventId());
      StepInto();                      // request a single step
      GetDebuggerEvent(WFNE_SUSP, -1); // ... and wait for app to execute
      StepInto();                      // request a single step
      GetDebuggerEvent(WFNE_SUSP, -1); // ... and wait for app to execute
    

    In IDA 5.1 this would have required a event handler and a small finite state automata, for a total more than 200 lines of code. Please note that, in the above example, the error handling code is omitted for clarity. In real life, you might want to check for unexpected conditions like an exception happening after StepInto().

    To illustrate how easier it is to write scripts with the new approach, we rewrote the core functionality of the UUNP unpacker plugin. The original program requires about 600 lines of code and has a rather complex logic. The new script only requires 100 lines of code (almost half of them being comments and empty lines). More importantly, the script is easy to understand and modify for your needs.

    This is a reimplementation of the uunp universal unpacker in IDC. It illustrates the use of the new debugger functions in IDA v5.2

    #include <idc.idc>
    
    //--------------------------------------------------------------------------
    static main()
    {
      auto ea, bptea, tea1, tea2, code, minea, maxea;
      auto r_esp, r_eip, caller, funcname;
    
      // Calculate the target IP range. It is the first segment.
      // As soon as the EIP register points to this range, we assume that
      // the unpacker has finished its work.
      tea1 = FirstSeg();
      tea2 = SegEnd(tea1);
    
      // Calculate the current module boundaries. Any calls to GetProcAddress
      // outside of these boundaries will be ignored.
      minea = MinEA();
      maxea = MaxEA();
    
      // Launch the debugger and run until the entry point
      if ( !RunTo(BeginEA()) )
        return Failed(-1);
    
      // Wait for the process to stop at the entry point
      code = GetDebuggerEvent(WFNE_SUSP, -1);
      if ( code <= 0 )
        return Failed(code);
    
      // Set a breakpoint at GetProcAddress
      bptea = LocByName("kernel32_GetProcAddress");
      if ( bptea == BADADDR )
        return Warning("Could not locate GetProcAddress");
      AddBpt(bptea);
    
      while ( 1 )
      {
        // resume the execution and wait until the unpacker calls GetProcAddress
        code = GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1);
        if ( code <= 0 )
          return Failed(code);
    
        // check the caller, it must be from our module
        r_esp = GetRegValue("ESP");
        caller = Dword(r_esp);
        if ( caller < minea || caller >= maxea )
          continue;
    
        // if the function name passed to GetProcAddress is not in the 
        // ignore-list, then switch to the trace mode
        funcname = GetString(Dword(r_esp+8), -1, ASCSTR_C);
        // ignore some api calls because they might be used by the unpacker
        if ( funcname == "VirtualAlloc" )
          continue;
        if ( funcname == "VirtualFree" )
          continue;
    
        // A call to GetProcAddress() probably means that the program has been
        // unpacked in the memory and now is setting up its import table
        break;
      }
    
      // trace the program in the single step mode until we jump to
      // the area with the original entry point.
      DelBpt(bptea);
      EnableTracing(TRACE_STEP, 1);
      for ( code = GetDebuggerEvent(WFNE_ANY|WFNE_CONT, -1); // resume
            code > 0;
            code = GetDebuggerEvent(WFNE_ANY, -1) )
      {
        r_eip = GetEventEa();
        if ( r_eip >= tea1 && r_eip < tea2 )
          break;
      }
      if ( code <= 0 )
        return Failed(code);
    
      // as soon as the current ip belongs OEP area, suspend the execution and
      // inform the user
      PauseProcess();
      code = GetDebuggerEvent(WFNE_SUSP, -1);
      if ( code <= 0 )
        return Failed(code);
    
      EnableTracing(TRACE_STEP, 0);
    
      // Clean up the disassembly so it looks nicer
      MakeUnknown(tea1, tea2-tea1, DOUNK_EXPAND|DOUNK_DELNAMES);
      MakeCode(r_eip);
      AutoMark2(tea1, tea2, AU_USED);
      AutoMark2(tea1, tea2, AU_FINAL);
      TakeMemorySnapshot(1);
      MakeName(r_eip, "real_start");
      Warning("Successfully traced to the completion of the unpacker code\n"
              "Please rebuild the import table using renimp.idc\n"
              "before stopping the debugger");
    }
    //--------------------------------------------------------------------------
    // Print an failure message
    static Failed(code)
    {
      Warning("Failed to unpack the file, sorry (code %d)", code);
      return 0;
    }
    

    Debugging code snippets with QEMU debugger (a la IDA Bochs debugger)

    Introduction

    IDA Pro 5.6 has a new feature: automatic running of the QEMU emulator. It can be used to debug small code snippets directly from the database. In this tutorial we will show how to dynamically run code that can be difficult to analyze statically.

    Target

    As an example we will use shellcode from the article “Alphanumeric RISC ARM Shellcode” in Phrack 66. It is self-modifying and because of alphanumeric limitation can be quite hard to undestand. So we will use the debugging feature to decode it.

    The sample code is at the bottom of the article but here it is repeated:

    80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR80AR
    80AR80AR80AR80AR80AR80AR80AR80AR80AR00OB00OR00SU00SE9PSB9PSR0pMB80SBcACP
    daDPqAGYyPDReaOPeaFPeaFPeaFPeaFPeaFPeaFPd0FU803R9pCRPP7R0P5BcPFE6PCBePFE
    BP3BlP5RYPFUVP3RAP5RWPFUXpFUx0GRcaFPaP7RAP5BIPFE8p4B0PMRGA5X9pWRAAAO8P4B
    gaOP000QxFd0i8QCa129ATQC61BTQC0119OBQCA169OCQCa02800271execme22727

    Copy this text to a new text file, remove all line breaks (i.e. make it a single long line) and save. Then load it into IDA.

    Loading binary files into IDA

    IDA displays the following dialog when it doesn’t recognize the file format (as in this case):

    Since we know that the code is for ARM processor, choose ARM in the “Processor type” dropdown and click Set. Then click OK. The following dialog appears:

    When you analyze a real firmware dumped from address 0, these settings are good. However, since our shellcode is not address-dependent, we can choose any address. For example, enter 0x10000 in “ROM start address” and “Loading address” fields.

    IDA doesn’t know anything about this file so it didn’t create any code. Press C to start disassembly.

    Configuring QEMU

    Before starting debug session, we need to set up automatic running of QEMU.

    1. Download a recent version of QEMU with ARM support (e.g. from http://homepage3.nifty.com/takeda-toshiya/qemu/index.html). If qemu-system-arm.exe is in a subdirectory, move it next to qemu.exe and all DLLs.
      Note: if you’re running Windows 7 or Vista, it’s recommended to use QEMU 0.11 or 0.10.50 (“Snapshot” on Takeda Toshiya’s page), as the older versions listen for GDB connections only over IPv6 and IDA can’t connect to it.
    2. Edit cfg/gdb_arch.cfg and change “set QEMUPATH” line to point to the directory where you unpacked QEMU. Change “set QEMUFLAGS” if you’re using an older version.
    3. In IDA, go to Debug-Debugger options…, Set specific options.
    4. Enable “Run a program before starting debugging”.
    5. Click “Choose a configuration”. Choose Versatile or Integrator board. The command line and Initial SP fields will be filled in.
    6. Memory map will be filled from the config file too. You can edit it by clicking the “Memory map” button, or from the Debugger-Manual memory regions menu item. See below for more details

    Now on every start of debugging session QEMU will be started automatically.

    Executing the code

    By default, initial execution point is the entry point of the database. If you want to execute some other part of it, there are two ways:

    1. Select the code range that you want to execute, or
    2. Rename starting point ENTRY and ending point EXIT (convention similar to Bochs debugger)

    In our case we do want to start at the entry point so we don’t need to do anything. If you press F9 now, IDA will write the database contents to an ELF file (database.elfimg) and start QEMU, passing the ELF file name as the “kernel” parameter. QEMU will load it, and stop at the initial point.

    Now you can step through the code and inspect what it does. Most of the instructions “just work”, however, there is a syscall at 0x0010118:

    ROM:00010118 SVCMI 0x414141

    Since the QEMU configuration we use is “bare metal”, without any operating system, this syscall won’t be handled. So we need to skip it.

    1. Navigate to 010118 and press F4 (Run to cursor). Notice that the code was changed (patched by preceding instructions):
    2. Right-click next line (0001011C) and choose Set IP.
    3. Press F7 three times. Once you’re on BXPL R6 line, IDA will detect the mode switch and add a change point to Thumb code:
    4. Go to 01012C and press U (Undefine).
    5. Press Alt-G (Change Segment Register Value) and set value of T to 1. The erroneous CODE32 will disappear.
    6. Go back to 00010128 and press C (Make code). Nice Thumb code will appear:
    7. In Thumb code, there is another syscall at 00010152. If you trace or run until it, you can see that R7 becomes 0xB (sys_execve) and R0 points to 00010156.

    Hint: if the code you’re investigating has many syscalls and you don’t want to handle them one by one, put a breakpoint at the address 0000000C (ARM’s vector for syscalls). Return address will be in LR.

    Saving results to database

    If you want to keep the modified code or data for later analysis, you’ll need to copy it to the database. For that:

    1. Edit segment attributes (Alt-S) and make sure that segments with the data you need have the “Loader segment” attribute set.
    2. Choose Debugger-Take memory snapshot and answer “Loader segments”.
    3. Now you can stop the debugging and inspect the new data.
      Note: this will update your database with the new data and discard the old. Repeated execution probably will not be correct.

    Happy debugging!
    Please send any comments or questions to [email protected]

    Trace Replayer and managing traces

    Using Trace Replayer Debugger and Managing Traces in IDA

    Copyright 2014 Hex-Rays SA

    Introduction

    Quick Overview

    The trace replayer is an IDA pseudo debugger plugin that appeared first in IDA 6.3. This plugin can replay execution traces recorded with any debugger backend in IDA, such as local Win32 or Linux debuggers, WinDbg, remote GDB debugger, etc…

    Following this tutorial

    This tutorial was created using the Linux version of IDA and a Linux binary as target. However, it can be followed on any supported platform (MS Windows, Mac OS X and Linux) by setting up remote debugging. Please refer to the debugger section of the docs for more information regarding remote debugging.

    Supplied files

    Among with the tutorial the following files are also provided at http://www.hex-rays.com/products/ida/support/tutorials/replayer/ida-replayer-tutorial.tar.gz

    File nameSHA1Description
    intoverflow.c6424d3100e3ab1dd3fceae53c7d925364cea75c5Program’s source code.
    intoverflow.elf69a0889b7c09ec5c293702b3b50f55995a1a2daaLinux ELF32 program.
    no_args.trc773837c2b212b4416c8ac0249859208fd30e2209IDA binary trace file version 1
    second_run.trc4e0a5effa34f805cc50fe40bc0e19b78ad1bb7c4IDA binary trace file version 1
    crash.trcf0ee851b298d7709e327d8eee81657cf0beae69bIDA binary trace file version 1

    Replaying and managing traces

    Recording traces

    Before using the trace replayer plugin we will need to record an execution trace of a program. We will use the following toy vulnerable program as an example:

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    
    int foo(char *arg, int size) 
    { 
        char *buf; 
    
        if ( strlen(arg) > size ) 
        { 
            printf("Too big!\n"); 
            return 1; 
        } 
    
        buf = malloc(size); 
        strcpy(buf, arg); 
        printf("Buffer is %s\n", buf); 
        free(buf); 
        return 0; 
    } 
    
    int main(int argc, char **argv) 
    { 
        if ( argc != 3 ) 
        { 
            printf("Invalid number of arguments!\n"); 
            return 2; 
        } 
    
        return foo(argv[1], atoi(argv[2])); 
    } 
    

    Please compile this sample program (in this example, we used GCC compiler for Linux) or use the supplied ELF binary, open the binary in IDA and wait until the initial analysis completes. When done, select a suitable debugger from the drop down list (“Local Linux debugger”, or “Remote Linux debugger” if you’re following this tutorial from another platform):

    We have two ways of telling IDA to record a trace:

    1. Break on process entry point and manually enable tracing at this point.
    2. Or put a trace breakpoint at the very first instruction of the program.

    In the case we prefer the first approach we will need to click on the menu “Debugger → Debugger Options” and then mark the check box “Stop on process entry point” as shown bellow:

    After checking this option press OK and run the program pressing F9. When the entry point is reached, we can select from the menu “Debugger → Tracing” one of the following three options:

    1. Instruction tracing: All instructions executed will be recorded.
    2. Function tracing: Only function calls and returns will be recorded.
    3. Basic block tracing: Similar to instruction tracing but, instead of single stepping instruction by instruction, IDA will set temporary breakpoints in the end of every known basic block, as well as on function calls.

    For this example we will select “Instruction tracing”. Check this option and let the program continue by pressing F9. The program will resume execution and finish quickly. Now, we have a recorded trace! To see it, select “Debugger → Tracing → Trace Window”. A new tab will open with a content similar to the following:

    As previously stated, there are two ways to record traces: enabling it manually, or using an “Enable tracing” breakpoint. To set such a breakpoint we will go to the program’s entry point (Ctrl+E) and put a breakpoint (F2) in the very first instruction. Then right click on the new breakpoint and select “Edit breakpoint”. In the dialog check the option “Enable tracing” and then select the desired “Tracing type” (for this example, we’ll use “Instructions”):

    Remove the “Stop on process entry point” option we set in the prior example and press F9 to run the program.

    This way is more convenient than the first because the tracing is turned on automatically and does not need manual intervention.

    Working with traces

    Now we have a new recorded trace, no matter which method we used. What can we do with it? First, we can check which instructions were executed, as they are highlighted in the disassembly, like in the screenshot bellow:

    (the highlight color can be changed in “Debugger → Tracing → Tracing Options”)

    Highlighting makes it clear which instructions have been executed.

    We can also check what functions have been executed (instead of instructions) by opening the “Trace Window” via “Debugger → Tracing → Trace Window”, right clicking on the list and then selecting “Show trace call graph”:

    Now let’s inspect the register values in order to understand why the check at 0x0848566 doesn’t pass. Please select “Debugger → Switch debugger” and in the dialog box click on the “Trace replayer” radio button:

    Click OK and press F4 in the first instruction of the “main” function.

    The trace replayer will suspend execution at the “main” function and display the register values that were recorded when the program was executed:

    We can single step by pressing F7, as usual. Let us keep pressing F7 until the “jz” instruction is reached:

    The comparison “cmp [ebp+arg_0], 3” was not successful (ZF=0) so the check does not pass. We need to give to the program two arguments to pass this check and record a new trace.

    Loading an overlay and viewing differences in flow

    Before doing another run, let’s save the first trace to a file. Select “Debugger → Tracing → Trace Window”, right click in the middle of the newly opened tab, and select “Save trace” from the popup menu:

    Then save the file:

    You will also be offered a chance to give the trace a description:

    Now let’s record a new trace but this time we will pass two command line arguments to the program. Select “Debugger → Process Options” and set “AAAA 4” as the arguments:

    Close the dialog, revert to the “Local Linux debugger”, and press F9. A new trace will be recorded. If we check the “main” function we will see that different instructions have been executed this time:

    Let’s check which instructions are different between the first and the second run.

    First, we will need to load the previous trace as “overlay”:

    Select the trace we saved:

    Note that we have now other options in the ‘Overlay’ submenu, now that there is an overlay present:

    Now go back to the disassembly view and check how the disassembly code is highlighted in three different colors:

    The code highlighted in yellow is the code executed in the current trace (the one listed in the “Trace Window”). The pink code was executed only in the overlay trace. And the code in purple is the code common to both traces. We can immediately see that there is some new code that have been executed, like the calls to atoi and foo.

    Let’s go to the “foo” function and see what happened here:

    The code in yellow tells us that the check for the size at 0x800484FC passed and the calls to malloc, strcpy and printf were executed. Let’s save this trace for later analysis and comparison with the future runs. As before, go to the trace window, right click on the list and select “Save trace”. Set the trace’s description to ‘Correct execution’.

    It’s time to record another trace with different arguments to see what happens. For this new execution, we will longer command line arguments (eight “A” characters instead of four). Let’s change the arguments in “Debugger → Process Options”, switch back to the “Local Linux debugger”, and run it. We have a new trace. Let’s compare it against the previously recorded one. As we did before, go to the “Trace Window”, right click on the list, select “Overlay”, then “Load overlay”, and select the trace with description “Correct execution”.

    As we see, the code that alerts us the about a too big string was executed (it’s highlighted in yellow). Let’s save this recorded trace with the “String too big” description. Now we will record one more trace but this time we will use the number “-1” as the second command line argument.

    Change the arguments in “Debugger → Process Options” as shown bellow:

    Then switch back again, to the “Local Linux debugger” (or to “Remote Linux debugger” if needed) and run it by pressing F9. The process will crash somewhere in the call to strcpy:

    Stop the debugger and save this trace (let’s call it “Crash”). Then diff this trace against the “Correct execution” trace.

    We will see the following in the disassembly view:

    As we see, pretty much the same code as in the previous run was executed until the call to strcpy. It’s time to replay this last execution and see what happened.

    Diffing traces

    When both a “main trace” and an “overlay trace” are present, the context menu item “Overlay → Subtract overlay” becomes available.

    This allows one to subtract the list of events (e.g., instructions) that are present in the overlay, from the main trace:

    Will give the following results:

    As you can see, many events that were present in both the overlay & the main trace have been removed. Only those that were only present in the main trace remain.

    Reverting the diff

    The diffing operation is reversible:

    This will restore the main trace as it were, before the contents of the overlay were removed from it.

    Replaying traces

    We know that the program is crashing somewhere in the call to strcpy but we don’t know why the check at 0x080484FC passes since -1 is smaller than the size of the string (8 bytes). Let’s put a breakpoint at the call to strlen at 0x080484F0, switch to the “Trace replayer” debugger, and “run” the program by pressing F9. Please note that we do not really run the program, we are merely replaying a previously recorded trace.

    The debugger will stop at the strlen call:

    In the trace replayer we can use all usual debugging commands like “run to cursor” (F4), “single step” (F7), or “step over” (F8). Let’s press F8 to step over the strlen call and check the result:

    It returns 8 as expected. Now move to the address 0x080484FC and press F4 or right click on this address, select “Set IP”, and press F7 (we need to inform the replayer plugin that we changed the current execution instruction in order to refresh all the register values). The difference between “Run to” (F4) and “Set IP” is that “Run to” will replay all events happened until that point but “Set IP” will directly move to the nearest trace event happened at this address (if it’s in the recorded trace, of course).

    Regardless of how we moved to this point IDA will display the following:

    As we see, the jump was taken because CF was set to 1 in the previous instruction (“cmp edx, eax”). Let’s step back to this instruction to see what values were compared. Select “Debugger → Step back” from the menu:

    The flags are reset to 0 and we can see that EAX (0xFFFFFFFF) and EDX (8) are compared. Press F7 to step one instruction again and you will notice CF changes to 1. The instruction JBE performs an unsigned comparison between 8 and 0xFFFFFFFF and, as 8 <= 0xFFFFFFFF, the check passes. We just discovered the cause of the bug.

    Let’s continue analyzing it a bit more. Scroll down until the call to malloc at 0x08048517, right click, choose “Set IP”, and press F7 (or simply press F4). As we see, the argument given to malloc is 0xFFFFFFFF (4 GB).

    Press F8 to step over the function call:

    Obviously, malloc can not allocate so much memory and returns NULL. However, the program does not check for this possibility and tries to copy the contents of the given buffer to the address 0, resulting in a crash.

    Summary

    In this tutorial we showed you the basics of trace management and the trace replayer module in IDA. We hope you enjoy this new feature. Happy debugging!

    Using IDA Pro’s tracing features

    Check the tutorial about tracing with IDA:

    {% file src=“tracing.pdf” %}

    Appcall

    IDA Pro - Appcall user guide

    Copyright 2023 Hex-Rays SA

    Introduction

    Appcall is a mechanism to call functions under a debugger session in the context of the debugged program using IDA’s CLI (Command Line Interpreter) or from a script.
    Such a mechanism can be used for seamless blackbox function calling and use, fuzzing, process instrumentation, DLL injection, testing or extending applications.

    Appcall mechanism highly depends on the type information of the called function. For that reason, it is necessary to have a correct function prototype before doing an Appcall, otherwise different or incorrect results may be returned.

    In a nutshell, Appcall works by first hijacking the current thread’s stack (please do switch threads explicitly if you want to Appcall in a different context), then pushing the arguments, and then temporarily adjusting the instruction pointer to the beginning of the called function. After the function returns (or an exception occurs), the original stack, instruction pointer, and other registers are restored, and the result is returned to the caller.

    Please note that while most of the examples in this document are illustrated using a Windows user mode application, Appcall is not limited to Windows and can be used with any platform supported by IDA debuggers.

    Quick start

    Let’s start explaining the basic concepts of Appcall using the IDC CLI. Let’s imagine we have the following printf() in the disassembly somewhere:

    .text:00000001400015C0 ; __int64 printf(const char *, ...)
    .text:00000001400015C0 _printf         proc near               
    .text:00000001400015C0                                         
    .text:00000001400015C0
    .text:00000001400015C0 arg_0           = qword ptr  8
    .text:00000001400015C0 arg_8           = qword ptr  10h
    .text:00000001400015C0 arg_10          = qword ptr  18h
    .text:00000001400015C0 arg_18          = qword ptr  20h
    .text:00000001400015C0
    .text:00000001400015C0                 mov     [rsp+arg_0], rcx
    .text:00000001400015C5                 mov     [rsp+arg_8], rdx
    .text:00000001400015CA                 mov     [rsp+arg_10], r8
    .text:00000001400015CF                 mov     [rsp+arg_18], r9
    ...
    

    It can be called by simply typing the following in the IDC CLI (press “.” to jump to the CLI):

    _printf("hello world\n");
    

    As you noticed, we invoked an Appcall by simply treating _printf as if it was a built-in IDC function. If the application had a console window, then you should see the message printed in it.

    If you have a function with a mangled name or with characters that cannot be used as an identifier name in the IDC language, such as “_my_func@8”, then you can use the LocByName function to get its address given its name, then using the address variable (which is callable) we issue the Appcall:

    auto myfunc = LocByName("_my_func@8");
    myfunc("hello", "world");
    

    Or simply directly as:

    LocByName("_my_func@8")("hello", "world");
    

    Using AppCall with IDC

    Apart from calling Appcall naturally as shown in the previous section, it is possible to call it explicitly using the dbg_appcall function:

    // Call application function
    //      ea - address to call
    //      type - type of the function to call. can be specified as:
    //              - declaration string. example: "int func(void);"
    //              - typeinfo object. example: get_tinfo(ea)
    //              - zero: the type will be retrieved from the idb
    //      ... - arguments of the function to call
    // Returns: the result of the function call
    // If the call fails because of an access violation or other exception,
    // a runtime error will be generated (it can be caught with try/catch)
    // In fact there is rarely any need to call this function explicitly.
    // IDC tries to resolve any unknown function name using the application labels
    // and in the case of success, will call the function. For example:
    //      _printf("hello\n")
    // will call the application function _printf provided that there is
    // no IDC function with the same name.
    
    anyvalue dbg_appcall(ea, type, ...);    
    

    The Appcall IDC function requires you to pass a function address, function type information (various forms are accepted) and the parameters (if any):

    auto msgbox;
    msgbox = LocByName("__imp_MessageBoxA");
    // Pass "0" for the type to deduce it from the database
    dbg_appcall(msgbox, 0, 0, "Hello world", "Info", 0);
    

    We’ve seen so far how to call a function if it already has type information, now suppose we have a function that does not:

    user32.dll:00007FFF3AD730F0 user32_FindWindowA proc near
    user32.dll:00007FFF3AD730F0      mov     r9, rdx
    user32.dll:00007FFF3AD730F3      mov     r8, rcx
    user32.dll:00007FFF3AD730F6      xor     edx, edx
    user32.dll:00007FFF3AD730F8      xor     ecx, ecx
    user32.dll:00007FFF3AD730FA      jmp     sub_7FFF3ADC326C
    user32.dll:00007FFF3AD730FA user32_FindWindowA endp  
    

    Before calling this function with dbg_appcall we have two options:

    1. Pass the prototype as a string
    2. Or, parse the prototype separately and pass the returned type info object.

    This is how we can do it using the first option:

    auto window_handle;
    window_handle = dbg_appcall(
        LocByName("user32_FindWindowA"),
        "long __stdcall FindWindow(const char *cls, const char *wndname)",
        0,
        "Calculator");
        
    msg("handle=%d\n", window_handle);
    

    As for the second option, we can use parse_decl() first, then proceed as usual:

    auto window_handle, tif;
    
    tif = parse_decl("long __stdcall FindWindow(const char *cls, const char *wndname)", 0);
    
    window_handle = dbg_appcall(
        LocByName("user32_FindWindowA"),
        tif,
        0,
        "Calculator");
        
    msg("handle=%d\n", window_handle);
      
    

    Note that we used parse_decl() function to construct a typeinfo object that we can pass to dbg_appcall.

    It is possible to permanently set the prototype of a function programmatically using apply_type():

    auto tif;
    tif = parse_decl("long __stdcall FindWindow(const char *cls, const char *wndname)", 0);
    apply_type(
        LocByName("user32_FindWindowA"),
        tif);
    

    In the following sections, we are going to cover different scenarios such as calling by reference, working with buffers and complex structures, etc.

    Passing arguments by reference

    To pass function arguments by reference, it suffices to use the & symbol as in the C language.

    • For example to call this function:
    void ref1(int *a)
    {
      if (a == NULL)
        return;
      int o = *a;
      int n = o + 1;
      *a = n;
      printf("called with %d and returning %d\n", o, n);
    }
    

    We can use this code from IDC:

    auto a = 5;
    msg("a=%d", a);
    ref1(&a);
    msg(", after the call=%d\n", a);
    
    • To call a C function that takes a string buffer and modifies it:
    /* C code */
    int ref2(char *buf)
    {
      if (buf == NULL)
        return -1;
    
      printf("called with: %s\n", buf);
      char *p = buf + strlen(buf);
      *p++ = '.';
      *p = '\0';
      printf("returned with: %s\n", buf);
      int n=0;
      for (;p!=buf;p--)
        n += *p;
      return n;
    }
    

    We need to create a buffer and pass it by reference to the function:

    auto s = strfill('\x00', 20); // create a buffer of 20 characters
    s[0:5] = "hello"; // initialize the buffer
    ref2(&s); // call the function and pass the string by reference
    
    // check if the string has a dot appended to it
    if (s[5] != ".")
    {
      msg("not dot\n");
    }  
    else
    {
      msg("dot\n");
    }
    

    __usercall calling convention

    It is possible to Appcall functions with non standard calling conventions, such as routines written in assembler that expect parameters in various registers and so on. One way is to use the __usercall calling convention.

    Consider this function:

    /* C code */
    // eax = esi - edi
    int __declspec(naked) asm1()
    {
      __asm
      {
        mov eax, esi
        sub eax, edi
        ret
      }
    }
    

    And from IDC:

    auto x = dbg_appcall(
      LocByName("asm1"),
      "int __usercall asm1@<eax>(int a@<edi>, int b@<esi>);",
      1,
      5);
    msg("result = %d\n", x);
    

    Variadic functions

    In C:

    int va_altsum(int n1, ...)
    {
      va_list va;
      va_start(va, n1);
    
      int r = n1;
      int alt = 1;
      while ( (n1 = va_arg(va, int)) != 0 )
      {
        r += n1*alt;
        alt *= -1;
      }
    
      va_end(va);
      return r;
    }
    

    And in IDC:

    auto result = va_altsum(5, 4, 2, 1, 6, 9, 0);
    

    Calling functions that might cause exceptions

    Exceptions may occur during an Appcall. To capture them, use the try/catch mechanism:

    auto e;
    try
    {
      dbg_appcall(some_func_addr, func_type, args...);
      // Or equally:
      // some_func_name(arg1, arg2, ...);
    }
    catch (e)
    {
      // Exception occured .....
    }
    

    The exception object “e” will be populated with the following fields:

    • description: description text generated by the debugger module while it was executing the Appcall
    • file: The name of the file where the exception happened.
    • func: The IDC function name where the exception happened.
    • line: The line number in the script
    • qerrno: The internal code of last error occurred

    For example, one could get something like this:

    description: "Appcall: The instruction at 0x401012 referenced memory at 0x0. The memory could not be written"
    file: ""
    func: "___idcexec0"
    line:           4.        4h           4o 
    qerrno:          92.       5Ch         134o 
    

    In some cases, the exception object will contain more information.

    Functions that accept or return structures

    Appcall mechanism also works with functions that accept or return structure types. Consider this C code:

    #pragma pack(push, 1)
    struct UserRecord 
    {
      int id;
      char name[50];
      struct UserRecord* next;
    };
    #pragma pack(pop)
    
    // Function to create a new record
    UserRecord *makeRecord(char name[], int id) 
    {
      UserRecord* newRecord = (UserRecord*)malloc(sizeof(UserRecord));
      strcpy(newRecord->name, name);
      newRecord->id = id;
      newRecord->next = NULL;
      return newRecord;
    }
    
    void printRecord(UserRecord* record) 
    {
      printf("Id: %d ; Name: %s\n", record->id, record->name);
    }
    
    // Function to list all student records in the linked list
    void listRecords(UserRecord* head) 
    {
      if (head == NULL) 
      {
          printf("No records found.\n");
          return;
      }
    
      printf("Records:\n"
             "--------\n");
      while (head != NULL) 
      {
          printRecord(head);
          head = head->next;
      }
    }
    

    We can create a couple of records and link them up together:

    auto rec1, rec2, rec3;
    // Create records
    rec1 = makeRecord("user1", 1);
    rec2 = makeRecord("user2", 2);
    rec3 = makeRecord("user3", 3);
    // Link them up
    rec1.next = rec2;
    rec2.next = rec3;
    // Display them
    listRecords(rec1);
    

    Because we issued an Appcall, when listRecords is called, we expect to see the following output in the console:

    Records:
    --------
    Id: 1 ; Name: user1
    Id: 2 ; Name: user2
    Id: 3 ; Name: user3
    

    We can then access the fields naturally (even the linked objects). We can verify that if we just dump the first record through the IDC CLI (or just by calling IDC’s print function):

    IDC>rec1
    object
      id:           1.        1h           1o
      name: "user1\x00"
      next: object
        id:           2.        2h           2o
        name: "user2\x00"
        next: object
          id:           3.        3h           3o 
          name: "user3\x00"
          next: 0x0i64
    

    Notice how when rec1 is dumped, its next field is automatically followed and properly displayed. The same happens for rec2 and rec3.

    We can also directly access the fields of the structure from IDC and have those changes reflected in the debugee’s memory:

    rec1.id = 11;
    rec1.name = "hey user1";
    rec1.next.name = "hey user2";
    rec1.next.id = 21;
    rec1.next.next.name = "hey user3";
    rec1.next.next.id = 31;
    // Display them
    listRecords(rec1);
    

    Notable observations:

    • Objects are always passed by reference (no need to use the &)
    • Objects are created on the stack
    • Objects are untyped
    • Missing object fields are automatically created by IDA and filled with zero

    Calling an API that receives a structure and its size

    Let us take another example where we call the GetVersionExA API function:

    kernel32.dll:00007FFF3A0F9240 kernel32_GetVersionExA proc near
    kernel32.dll:00007FFF3A0F9240                 jmp     cs:off_7FFF3A1645E0
    kernel32.dll:00007FFF3A0F9240 kernel32_GetVersionExA endp
    

    This API requires one of its input fields to be initialized to the size of the structure. Therefore, we need to initialize the structure correctly before passing it to the API to be further populated therein:

    // Create an empty object
    auto ver = object();
    // We need to initialize the size of the structure
    ver.dwOSVersionInfoSize = sizeof("OSVERSIONINFO");
    // This is the only field we need to have initialized, the other fields will be created by IDA and filled with zeroes
    // Now issue the Appcall:
    GetVersionExA(ver);
    
    msg("%d.%d (%d)\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber);
    

    Now if we dump the ver object contents we observe something like this:

      IDC>print(ver);
      object
        dwBuildNumber:        9200.     23F0h       21760o
        dwMajorVersion:           6.        6h           6o 
        dwMinorVersion:           2.        2h           2o
        dwOSVersionInfoSize:         148.       94h         224o
        dwPlatformId:           2.        2h           2o
        szCSDVersion: "\x00\x00\x00\x00\x00\x00...."  
    

    Working with opaque types

    Opaque types like FILE, HWND, HANDLE, HINSTANCE, HKEY, etc. are not meant to be used as structures by themselves but like pointers.

    Let us take for example the FILE structure that is used with fopen(); its underlying structure looks like this (implementation details might change):

    00000000 FILE struc ; (sizeof=0x18, standard type)
    00000000 curp dd ?
    00000004 buffer dd ?
    00000008 level dd ?
    0000000C bsize dd ?
    00000010 istemp dw ?
    00000012 flags dw ?
    00000014 hold dw ?
    00000016 fd db ?
    00000017 token db ?
    00000018 FILE ends
    

    And the fopen() function prototype is:

    msvcrt.dll:00007FFF39F1B7B0 ; FILE *__cdecl fopen(const char *FileName, const char *Mode)
    msvcrt.dll:00007FFF39F1B7B0 fopen           proc near
    msvcrt.dll:00007FFF39F1B7B0                 mov     r8d, 40h ; '@'
    msvcrt.dll:00007FFF39F1B7B6                 jmp     msvcrt__fsopen
    msvcrt.dll:00007FFF39F1B7B6 fopen           endp
    

    Let us see how we can get a “FILE *”“ and use it as an opaque type and issue an fclose() call properly:

    auto fp;
    fp = fopen("c:\\temp\\x.cpp", "r");
    print(fp);
    fclose(fp.__at__);
    

    Nothing special about the fopen/fclose Appcalls except that we see the __at__ attribute showing up although it does not belong to the FILE structure definition.
    This is a special attribute that IDA inserts into all objects, and it contains the memory address from which IDA retrieved the object attribute values. We can use the __at__ to retrieve the C pointer of a given IDC object.

    Previously, we omitted the __at__ field from displaying when we dumped objects output, but in reality this is what one expects to see as part of the objects attributes used in Appcalls. Let’s create a user record again:

    auto rec;
    rec1 = makeRecord("user1", 13);
    rec2 = makeRecord("user2", 14);
    rec1.next = rec2;
    print(rec1);
    

    ..and observe the output:

    object
      __at__:     5252736.   502680h    24023200o
      id:          13.        Dh          15o
      name: "user1\x00..."
      next: object
        __at__:     5252848.   5026F0h    24023360o 
        id:          14.        Eh          16o
        name: "user2\x00..."
        next: 0x0i64
    

    Please note that it is possible to pass as integer (which is a pointer) to a function that expects a pointer to a structure.

    FindFirst/FindNext APIs example

    In this example, we call the APIs directly without permanently setting their prototype first.

    static main()
    {
      auto fd, h, n, ok;
    
      fd = object(); // create an object
      h = dbg_appcall(
        LocByName("kernel32_FindFirstFileA"),
        "HANDLE __stdcall FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);",
        "c:\\windows\\*.exe", 
        fd);
      if (h == -1) // INVALID_HANDLE_VALUE
      {
        msg("No files found!\n");
        return -1;
      }
      for (n=1;;n++)
      {
        msg("Found: %s\n", fd.cFileName);
        ok = dbg_appcall(
              LocByName("kernel32_FindNextFileA"),
              "BOOL __stdcall FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData);",
              h,
              fd);
    
        if ( (n > 5) || (ok == 0) )
          break;
      }
      dbg_appcall(
        LocByName("kernel32_FindClose"),
        "BOOL __stdcall FindClose(HANDLE hFindFile);",
        h);
    
      return n;
    }  
    

    Using LoadLibrary/GetProcAddress

    In this example, we are going to initialize the APIs by setting up their prototypes correctly so we can use them later conveniently.

    extern getmodulehandle, getprocaddr, findwindow, loadlib;
    
    static init_api()
    {
      loadlib = LocByName("kernel32_LoadLibraryA");
      getmodulehandle = LocByName("kernel32_GetModuleHandleA");
      getprocaddr = LocByName("kernel32_GetProcAddress");
    
      if (loadlib == BADADDR || getmodulehandle == BADADDR || getprocaddr == BADADDR)
        return "Failed to locate required APIs";
    
      // Let us permanently set the prototypes of these functions
      apply_type(loadlib, "HMODULE __stdcall loadlib(LPCSTR lpModuleName);");
      apply_type(getmodulehandle, "HMODULE __stdcall gmh(LPCSTR lpModuleName);");
      apply_type(getprocaddr, "FARPROC __stdcall gpa(HMODULE hModule, LPCSTR lpProcName);");
    
      // Resolve address of FindWindow api
      auto t = getmodulehandle("user32.dll");
      if (t == 0)
      {
        t = loadlib("user32.dll");
        if (t == 0)
            return "User32 is not loaded!";
      }
      findwindow = getprocaddr(t, "FindWindowA");
      if (findwindow == 0)
        return "FindWindowA API not found!";
    
      // Set type
      apply_type(findwindow, "HWND __stdcall FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);");
    
      return "ok";
    }
    
    static main()
    {
      auto ok = init_api();
      if (ok != "ok")
      {
        msg("Failed to initialize: %s", ok);
        return -1;
      }
      auto hwnd = dbg_appcall(findwindow, 0, 0, "Calculator");
      if (hwnd == 0)
      {
        msg("Failed to locate the Calculator window!\n");
        return -1;
      }
      msg("Calculator hwnd=%x\n", hwnd);
      return 0;
    }
    

    Retrieving application’s command line

    extern getcommandline;
    
    static main()
    {
      getcommandline = LocByName("kernel32_GetCommandLineA");
      if (getcommandline == BADADDR)
      {
        msg("Failed to resolve GetCommandLineA API address!\n");
        return -1;
      }
      apply_type(getcommandline, "const char *__stdcall GetCommandLineA();");
    
      msg("This application's command line:<\n%s\n>\n", getcommandline());
      return 0;
    }
    

    Specifying Appcall options

    Appcall can be configured with set_appcall_options() and passing one or more options:

    • APPCALL_MANUAL: Only set up the appcall, do not run it (you should call cleanup_appcall() when finished). Please Refer to the “Manual Appcall” section for more information.
    • APPCALL_DEBEV: If this bit is set, exceptions during appcall will generate IDC exceptions with full information about the exception. Please refer to the “Capturing exception debug events” section for more information.

    It is possible to retrieve the Appcall options, change them and then restore them back. To retrieve the options use the get_appcall_options().

    Please note that the Appcall options are saved in the database so if you set it once it will retain its value as you save and load the database.

    Manual Appcall

    So far, we’ve seen how to issue an Appcall and capture the result from the script, but what if we only want to setup the environment and manually step through a function?

    This can be achieved with manual Appcall. The manual Appcall mechanism can be used to save the current execution context, execute another function in another context and then pop back the previous context and continue debugging from that point.

    Let us directly illustrate manual Appcall with a real life scenario:

    1. You are debugging your application
    2. You discover a buggy function (foo()) that misbehaves when called with certain arguments: foo(0xdeadbeef)
    3. Instead of waiting until the application calls foo() with the desired arguments that can cause foo() to misbehave, you can manually call foo() with the desired arguments and then trace the function from its beginning.
    4. Finally, one calls cleanup_appcall() to restore the execution context

    To illustrate, let us take the ref1 function (from the previous example above) and call it with an invalid pointer:

    1. Set manual Appcall mode:

      set_appcall_options(APPCALL_MANUAL);
      
    2. Call the function with an invalid pointer:

      ref1(6);
      

    Directly after doing that, IDA will switch to the function and from that point on we can debug:

    .text:0000000140001050 ; void __stdcall ref1(int *a)
    .text:0000000140001050 ref1            proc near
    .text:0000000140001050                 test    rcx, rcx  ; << RIP starts here 
    .text:0000000140001053                 jz      short locret_14000106A
    .text:0000000140001055                 mov     edx, [rcx]
    .text:0000000140001057                 lea     r8d, [rdx+1]
    .text:000000014000105B                 mov     [rcx], r8d
    .text:000000014000105E                 lea     rcx, aCalledWithDAnd ; "called with %d and returning %d\n"
    .text:0000000140001065                 jmp     _printf
    .text:000000014000106A locret_14000106A:      
    .text:000000014000106A                 retn
    .text:000000014000106A ref1            endp  
    

    Now you are ready to single step that function with all its arguments properly set up for you. When you are done, you can return to the previous context by calling cleanup_appcall().

    Initiating multiple manual Appcalls

    It is possible to initiate multiple manual Appcalls. If manual Appcall is enabled, then issuing an Appcall from an another Appcall will push the current context and switch to the new Appcall context. cleanup_appcall() will pop the contexts one by one (LIFO style).

    Such technique is useful if you happen to be tracing a function then you want to debug another function and then resume back from where you were!

    Manual Appcalls are not designed to be called from a script (because they don’t finish), nonetheless if you use them from a script:

    auto i;
    printf("Loop started\n"); // appcall 1
    for (i=0;i<10;i++)
    {
      msg("i=%d\n", i);
    }
    printf("Loop finished\n"); // appcall 2
    

    We observe the following:

    1. First Appcall will be initiated
    2. The script will loop and display the values of i in IDA’s output window
    3. Another Appcall will be initiated
    4. The script finishes. None of the two Appcalls actually took place
    5. The execution context will be setup for tracing the last issued Appcall
    6. After this Appcall is finished, we observe “Loop finished”
    7. We issue cleanup_appcall and notice that the execution context is back to printf but this time it will print “Loop started”
    8. Finally when we call again cleanup_appcall we resume our initial execution context

    Capturing exception debug events

    We previously illustrated that we can capture exceptions that occur during an Appcall, but that is not enough if we want to learn more about the nature of the exception from the operating system point of view.

    It would be better if we could somehow get the last debug_event_t that occured inside the debugger module. This is possible if we use the APPCALL_DEBEV option. Let us repeat the previous example but with the APPCALL_DEBEV option enabled:

    auto e;
    try
    {
      set_appcall_options(APPCALL_DEBEV); // Enable debug event capturing
      ref1(6);
    }
    catch (e)
    {
      // Exception occured ..... this time "e" is populated with debug_event_t fields (check idd.hpp)
    }
    

    And in this case, if we dump the exception object’s contents, we get these attributes:

    Unhandled exception: object
      can_cont:           1.        1h           1o
      code:  3221225477. C0000005h 30000000005o
      ea:     4198442.   40102Ah    20010052o
      eid:          64.       40h         100o
      file: ""
      func: "___idcexec0"
      handled:           1.        1h           1o
      info: "The instruction at 0x40102A referenced memory at 0x6. The memory could not be read"
      line:           2.        2h           2o
      pc:          11.        Bh          13o
      pid:       40128.     9CC0h      116300o
      ref:           6.        6h           6o
      tid:       36044.     8CCCh      106314o
    

    There are some functions that can be used while working with Appcalls.

    parse_decl/get_tinfo/sizeof

    The get_tinfo() function is used to retrieve the typeinfo string associated with a given address.

    /// Get type information of function/variable as 'typeinfo' object
    ///      ea - the address of the object
    ///      type_name - name of a named type
    /// returns: typeinfo object, 0 - failed
    /// The typeinfo object has one mandatory attribute: typid
    
    typeinfo get_tinfo(long ea);
    typeinfo get_tinfo(string type_name);  
    

    The parse_decl() function is used to construct a typeinfo string from a type string. We already used it to construct a typeinfo string and passed it to dbg_appcall().

    /// Parse one type declaration
    ///      input -  a C declaration
    ///      flags -  combination of PT_... constants or 0
    ///               PT_FILE should not be specified in flags (it is ignored)
    /// returns: typeinfo object or num 0
    
    typeinfo parse_decl(string input, long flags);
    

    And finally, given a typeinfo string, one can use the sizeof() function to calculate the size of a type:

    /// Calculate the size of a type
    ///      type - type to calculate the size of
    ///             can be specified as a typeinfo object (e.g. the result of get_tinfo())
    ///             or a string with C declaration (e.g. "int")
    /// returns: size of the type or -1 if error
    
    long sizeof(typeinfo type);  
    

    Accessing enum members as constants

    In IDC, it is possible to access all the defined enumerations as if they were IDC constants:

    00000001 ; enum MACRO_PAGE (standard) (bitfield)
    00000001 PAGE_NOACCESS  = 1
    00000002 PAGE_READONLY  = 2
    00000004 PAGE_READWRITE  = 4
    00000008 PAGE_WRITECOPY  = 8
    00000010 PAGE_EXECUTE  = 10h
    00000020 PAGE_EXECUTE_READ  = 20h
    00000040 PAGE_EXECUTE_READWRITE  = 40h
    

    Then one can type:

    msg("PAGE_EXECUTE_READWRITE=%x\n", PAGE_EXECUTE_READWRITE);
    

    This syntax makes it even more convenient to use enumerations when calling APIs via Appcall.

    Storing/Retrieving typed elements

    It is possible to store/retrieve (aka serialize/deserialize) objects to/from the database (or the debugee’s memory). To illustrate, let us consider the following memory contents:

    0001000C dd 1003219h
    00010010 dw 0FFEEh
    00010012 dw 0FFEEh
    00010014 dd 1
    

    And we know that this maps to a given type:

    struct X
    {
      unsigned long a;
      unsigned short b, c;
      unsigned long d;
    };
    

    To retrieve (deserialize) the memory contents into a nice IDC object, we can use the object.retrieve() function:

    /// Retrieve a C structure from the idb or a buffer and convert it into an object
    ///  typeinfo - description of the C structure. Can be specified
    ///             as a declaration string or result of \ref get_tinfo() or
    ///             similar functions
    ///  src      - address (ea) to retrieve the C structure from
    ///             OR a string buffer previously packed with the store method
    ///  flags    - combination of \ref object_store[PIO_...] bits
    
    void object.retrieve(typeinfo, src, flags);
    

    Here is an example:

    // Create the typeinfo string
    auto t = parse_decl("struct X { unsigned long a; unsigned short b, c; unsigned long d;};", 0);
    // Create a dummy object
    auto o = object();
    // Retrieve the contents into the object:
    o.retrieve(t, 0x1000C, 0);
    

    And now if we dump the contents of o:

    IDC>print(o);
    object
      __at__:       65548.    1000Ch      200014o 00000000000000010000000000001100b
      a:    16790041.  1003219h   100031031o 00000001000000000011001000011001b
      b:       65518.     FFEEh      177756o 00000000000000001111111111101110b
      c:       65518.     FFEEh      177756o 00000000000000001111111111101110b
      d:           1.        1h           1o 00000000000000000000000000000001b
    

    and again we notice the __at__ which holds the address of the retrieved object.

    To store (serialize) the object back into memory, we can use the object.store() function:

    /// Convert the object into a C structure and store it into the idb or a buffer
      ///  typeinfo - description of the C structure. Can be specified
      ///             as a declaration string or result of \ref get_tinfo() or
      ///             similar functions
      ///  dest     - address (ea) to store the C structure
      ///             OR a reference to a destination string
      ///  flags    - combination of PIO_.. bits
      
      void object.store(typeinfo, dest, flags);
    

    Here’s an example continuing from the previous one:

    o.a++; // modify the field
    o.d = 6; // modify another field
    o.store(t, o.__at__, 0);
    

    And finally to verify, we go to the memory address:

    0001000C dd 100321Ah
    00010010 dw 0FFEEh
    00010012 dw 0FFEEh
    00010014 dd 6
    

    Using Appcall with IDAPython

    The Appcall concept remains the same between IDC and Python, nonetheless Appcall/Python has a different syntax (using references, unicode strings, etc.)

    The Appcall mechanism is provided by ida_idd module (also via idaapi) through the Appcall variable. To issue an Appcall using Python:

    from idaapi import Appcall
    Appcall.printf("Hello world!\n");
    

    One can take a reference to an Appcall:

    printf = Appcall.printf
    # ...later...
    printf("Hello world!\n");
    
    • In case you have a function with a mangled name or with characters that cannot be used as an identifier name in the Python language, then use the following syntax:
    findclose     = Appcall["__imp__FindClose@4"]
    getlasterror  = Appcall["__imp__GetLastError@0"]
    setcurdir     = Appcall["__imp__SetCurrentDirectoryA@4"]
    
    • In case you want to redefine the prototype of a given function, then use the Appcall.proto(func_name or func_ea, prototype_string) syntax as such:
    # pass an address or name and Appcall.proto() will resolve it
    loadlib = Appcall.proto("__imp__LoadLibraryA@4", "int (__stdcall *LoadLibraryA)(const char *lpLibFileName);")
    # Pass an EA instead of a name
    freelib = Appcall.proto(LocByName("__imp__FreeLibrary@4"), "int (__stdcall *FreeLibrary)(int hLibModule);")
    
    • To pass unicode strings you need to use the Appcall.unicode() function:
    getmodulehandlew = Appcall.proto("__imp__GetModuleHandleW@4", "int (__stdcall *GetModuleHandleW)(LPCWSTR lpModuleName);")
    hmod = getmodulehandlew(Appcall.unicode("kernel32.dll"))
    
    • To pass int64 values to a function you need to use the Appcall.int64() function:
    /* C code */
    int64 op_two64(int64 a, int64 b, int op)
    {
      if (op == 1)
        return a + b;
      else if (op == 2)
        return a - b;
      else if (op == 3)
        return a * b;
      else if (op == 4)
        return a / b;
      else
        return -1;
    }
    

    Python Appcall code:

    r = Appcall.op_two64(Appcall.int64(1), Appcall.int64(2), 1)
    print("result=", r.value)
    

    If the returned value is also an int64, then you can use the int64.value to unwrap and retrieve the value.

    • To define a prototype and then later assign an address so you can issue an Appcall:
    # Create a typed object (no address is associated yet)
    virtualalloc = Appcall.typedobj("int __stdcall VirtualAlloc(int lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);")
    # Later we have an address, so we pass it:
    virtualalloc.ea = idc.get_name_ea(0, "kernel32_VirtualAlloc")
    # Now we can Appcall:
    ptr = virtualalloc(0, Appcall.Consts.MEM_COMMIT, 0x1000, Appcall.Consts.PAGE_EXECUTE_READWRITE)
    print("ptr=%x" % ptr)
    

    Things to note:

    • We used the Appcall.Consts syntax to access enumerations (similar to what we did in IDC)
    • If you replicate this specific example, a new memory page will be allocated. You need to refresh the debugger memory layout (with idaapi.refresh_debugger_memory()) to access it

    Passing arguments by reference

    • To pass function arguments by reference, one has to use the Appcall.byref():
    # Create a byref object holding the number 5
    i = Appcall.byref(5)
    # Call the function
    Appcall.ref1(i)
    # Retrieve the value
    print("Called the function:", i.value)
    
    • To call a C function that takes a string buffer and modifies it, we need to use the Appcall.buffer(initial_value, [size]) function to create a buffer:
    buf = Appcall.buffer("test", 100)
    Appcall.ref2(buf)
    print(buf.cstr())
    
    • Another real life example is when we want to call the GetCurrentDirectory() API:
    # Take a reference
    getcurdir = Appcall.proto("kernel32_GetCurrentDirectoryA", "DWORD __stdcall GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer);")
    # make a buffer
    buf = Appcall.byref("\x00" * 260)
    # get current directory
    n = getcurdir(260, buf)
    print("curdir=%s" % buf.cstr())
    
    • To pass int64 values by reference:
    int64_t ref4(int64_t *a)
    {
      if (a == NULL)
      {
        printf("No number passed!");
        return -1;
      }
      int64_t old = *a;
      printf("Entered with %" PRId64 "\n", *a);
      (*a)++;
      return old;
    }
    

    We use the following Python code:

    # Create an int64 value
    i = Appcall.int64(5)
    # create a reference to it
    v = Appcall.byref(i)
    # appcall
    old_val = Appcall.ref4(v)
    print(f"Called with {old_val.value}, computed {i.value}")
    
    • To call a C function that takes an array of integers or an array of a given type:
    /* C code */
    int ref3(int *arr, int sz)
    {
      if (arr == NULL)
        return 0;
      int sum = 0;
      for (int i=0;i<sz;i++)
        sum += arr[i];
      return sum;
    }
    

    First we need to use the Appcall.array() function to create an array type, then we use the array_object.pack() function to encode the Python values into a buffer:

    # create an array type
    arr = Appcall.array("int")
    # Create a test list
    L = [x for x in range(1, 10)]
    # Pack the list
    p_list = arr.pack(L)
    
    # appcall to compute the total
    c_total = Appcall.ref3(p_list, len(L))
    # internally compute the total
    total = sum(L)
    if total != c_total:
        print("Appcall failed!")
    else:
        print(f"Total computed using Appcall is {total}")
    

    Functions that accept or return structures

    Like in IDC, we can create objects and pass them with at least two methods.

    The first method involves using the Appcall.obj() function that takes an arbitrary number of keyword args that will be used to create an object with the arguments as attributes. The second method is by using a dictionary.

    # Via dictionary
    rec1 = {"id": 1, "name": "user1"}
    
    # Via Appcall.obj
    rec2 = Appcall.obj(id=2, name="user2")
    
    Appcall.printRecord(rec1)
    Appcall.printRecord(rec2)  
    

    And finally, if you happen to have your own object instance then just pass your object. The IDAPython object to IDC object conversion routine will skip attributes starting and ending with “__”.

    FindFirst/FindNext example

    # For simplicity, let's alias the Appcall
    a = idaapi.Appcall
    getcurdir = a.proto(
        "kernel32_GetCurrentDirectoryA", 
        "DWORD __stdcall GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer);")
        
    getwindir = a.proto(
        "kernel32_GetWindowsDirectoryA",
        "UINT __stdcall GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize);")
        
    setcurdir = a.proto(
        "kernel32_SetCurrentDirectoryA",
        "BOOL __stdcall SetCurrentDirectoryA(LPCSTR lpPathName);")
        
    findfirst = a.proto(
        "kernel32_FindFirstFileA",
        "HANDLE __stdcall FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);")
        
    findnext = a.proto(
        "kernel32_FindNextFileA",
        "BOOL __stdcall FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData);")
        
    findclose = a.proto(
        "kernel32_FindClose",
        "BOOL __stdcall FindClose(HANDLE hFindFile);")
    
    def test():
        # create a buffer
        savedpath = a.byref("\x00" * 260)
        # get current directory
        n = getcurdir(250, savedpath)
        out = []
        out.append("curdir=%s" % savedpath.value[0:n])
    
        # get windir
        windir = a.buffer(size=260) # create a buffer using helper function
        n = getwindir(windir, windir.size)
        if n == 0:
            print("could not get current directory")
            return False
    
        windir = windir.value[:n]
        out.append("windir=%s" % windir)
    
        # change to windows folder
        setcurdir(windir)
    
        # initiate find
        fd = a.obj()
        h = findfirst("*.exe", fd)
        if h == -1:
            print("no *.exe files found!")
            return False
    
        found = False
        while True:
            fn = a.cstr(fd.cFileName)
            if "regedit" in fn:
                found = True
            out.append("fn=%s<" % fn)
            fd = a.obj() # reset the FD object
            ok = findnext(h, fd)
            if not ok:
                break
        #
        findclose(h)
    
        # restore cur dir
        setcurdir(savedpath.value)
    
        # verify
        t = a.buffer(size=260)
        n = getcurdir(t.size, t)
        if t.cstr() != savedpath.cstr():
            print("could not restore cur dir")
            return False
    
        out.append("curdir=%s<" % t.cstr())
        print("all done!")
        for l in out:
            print(l)
    
        if found:
            print("regedit was found!")
        else:
            print("regedit was not found!")
            
        return found
        
        
    test()    
    

    Using GetProcAddress

    a = idaapi.Appcall
    loadlib  = a.proto("kernel32_LoadLibraryA", "HMODULE __stdcall LoadLibraryA(const char *lpLibFileName);")
    getprocaddr = a.proto("kernel32_GetProcAddress", "FARPROC __stdcall GetProcAddress(HMODULE hModule, LPCSTR lpProcName);")
    freelib = a.proto("kernel32_FreeLibrary", "BOOL __stdcall FreeLibrary(HMODULE hLibModule);")
    
    def test_gpa():
        h = loadlib("user32.dll")
        if idaapi.inf_is_64bit():
            h = h.value
        if h == 0:
            print("failed to load library!")
            return False
            
        p = getprocaddr(h, "FindWindowA")
        if idaapi.inf_is_64bit():
            p = p.value
        if p == 0:
            print("failed to gpa!")
            return -2
        findwin = a.proto(p, "HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName);")
        hwnd = findwin(0, "Calculator")
        freelib(h)
        if idaapi.inf_is_64bit():
            hwnd = hwnd.value
            
        print("%x: ok!->hwnd=%x" % (p, hwnd))
    
        return 1
        
    test_gpa()
    

    Please note that we used the idaapi.inf_is_64bit() method to properly unwrap integer values that depends on the bitness of the binary.

    Setting the Appcall options

    In Python, the Appcall options can be set global or locally per Appcall.

    • To set the global Appcall setting:
    old_options = Appcall.set_appcall_options(Appcall.APPCALL_MANUAL)
    
    • To set the Appcall setting per Appcall:
    # take a reference to printf
    printf = Appcall._printf
    # change the setting for this Appcall
    printf.options = Appcall.APPCALL_DEBEV
    printf("Hello world!\n")
    

    Similarly, retrieving the Appcall options is done by either calling Appcall.get_appcall_options() or by reading the options attribute (for example: printf.options)

    To cleanup after a manual Appcall use Appcall.cleanup_appcall().

    Calling functions that can cause exceptions

    An Appcall that generates an exception while executing in the current thread will throw a Python Exception object. This is inline with the IDC behavior we described above.

    • Let us try when the Appcall options does not include the APPCALL_DEBEV flag:
    try:
      idaapi.Appcall.cause_crash()
    except Exception as e:
      print("Got an exception!")
    

    This approach is useful if you want to know whether the Appcall passes or crashes.

    Now if we want more details about the exception, then we use the APPCALL_DEBEV flag, which will cause an OSError exception to be raised and have its args[0] populated with the last debug_event_t:

    cause_crash = idaapi.Appcall.cause_crash
    cause_crash.options = idaapi.APPCALL_DEBEV
    try:
      cause_crash()
    except OSError as e:
      debug_event = e.args[0]
      print(f"Exception: tid={debug_event.tid} ea={debug_event.ea:x}")
    except Exception as e:
      print("Unknown exception!")
    

    If the Appcall caused a crash, then the debug_event variable will be populated with the last debug_event_t structure inside the OSError exception handler.

    Storing/Retrieving objects

    Storing/Retrieving objects is also supported in Python:

    1. Using the IDA SDK (through the idaapi Python module)
    2. Using Appcall helper functions

    In this example we show how to:

    1. Unpack the DOS header at address 0x140000000 and verify the fields
    2. Unpack a string and see if it is unpacked correctly

    Let’s start with the IDA SDK helper functions first:

    # Struct unpacking
    def test_unpack_struct():
      name, tp, flds = idc.parse_decl("IMAGE_DOS_HEADER;", 0)
      ok, obj = idaapi.unpack_object_from_idb(idaapi.get_idati(), tp, flds, 0x140000000, 0)
      return obj.e_magic == 23117 and obj.e_cblp == 144
    
    # Raw unpacking
    def test_unpack_raw():
      # Parse the type into a type name, typestring and fields
      name, tp, flds = idc.parse_decl("struct abc_t { int a, b;};", 0)
      # Unpack from a byte vector (bv) (aka string)
      ok, obj = idaapi.unpack_object_from_bv(
                  idaapi.get_idati(), 
                  tp, 
                  flds, 
                  b"\x01\x00\x00\x00\x02\x00\x00\x00", 
                  0)
      return obj.a == 1 and obj.b == 2
    
    print("test_unpack_struct() passed:", test_unpack_struct())
    print("test_unpack_raw() passed:", test_unpack_raw())
    

    Now to accomplish similar result using Appcall helper functions:

    # Struct unpacking with Appcall
      def test_unpack_struct():
      tp = idaapi.Appcall.typedobj("IMAGE_DOS_HEADER;")
      ok, obj = tp.retrieve(0x140000000)
      return ok and obj.e_magic == 23117 and obj.e_cblp == 144
    
    # Raw unpacking with Appcall
    def test_unpack_raw():
      global tp
      # Parse the type into a type name, typestring and fields
      tp = idaapi.Appcall.typedobj("struct abc_t { int a, b;};")
      ok, obj = tp.retrieve(b"\x01\x00\x00\x00\x02\x00\x00\x00")
      return obj.a == 1 and obj.b == 2
    
    print("test_unpack_struct() passed:", test_unpack_struct())
    print("test_unpack_raw() passed:", test_unpack_raw())
    

    When it comes to storing, instead of using the Appcall’s typedobj.retrieve(), we can use the typedobj.store() function:

    # Packs/Unpacks a structure to the database using appcall facilities
    def test_pack_idb(ea):
      print("%x: ..." % ea)
      tp = a.typedobj("struct { int a, b; char x[4];};")
      o = a.obj(a=16, b=17,x="abcd")
      return tp.store(o, ea) == 0
    
    ea = idc.here() # some writable area    
    if test_pack_idb(ea):
      print("cool!")
      idaapi.refresh_debugger_memory()
    

    Accessing enum members as constants

    Like in IDC, to access the enums, one can use the Appcall.Consts object:

    print("PAGE_EXECUTE_READWRITE=%x" % Appcall.Consts.PAGE_EXECUTE_READWRITE)
    

    If the constant was not defined then an attribute error exception will be thrown. To prevent that, use the Appcall.valueof() method instead, which lets you provide a default value in case a constant was absent:

    print("PAGE_EXECUTE_READWRITE=%x" % Appcall.valueof("PAGE_EXECUTE_READWRITE", 0x40))
    

    Please send your comments or questions to [email protected]

    Creating Signatures

    FLIRT
    Makesig

    FLIRT

    FLIRT stands for Fast Library Identification and Recognition Technology. This technology allows IDA to recognize standard library functions generated by supported compilers and greatly improves the usability and readability of generated disassemblies. Of course, FLIRT can be combined with IDA’s usual interactivity to further improve the analysis. See this Pascal and this Delphi example as well.

    Automatic Unretouched Disassembly

    Automatic Disassembly

    With signatures applied (Borland Visual Component Library)

    IDA F.L.I.R.T. Technology: In-Depth

    The Goal

    One major stumbling block in the disassembly of programs written in modern high level languages is the time required to isolate library functions. This time may be considered lost because it does not bring us new knowledge : it is only a mandatory step that allows further analysis of the program and its meaningful algorithms. Unfortunately, this process has to be repeated for each and every new disassembly.

    Sometimes, the knowledge of the class of a library function can considerably ease the analysis of a program. This knowledge might be extremely helpful in discarding useless information. For example, a C++ function that works with streams usually has nothing to do with the main algorithm of a program.

    It is interesting to note that every high level language program uses a great number of standard library functions, sometimes even up to 95% of all the functions called are standard functions. For one well known compiler, the “Hello, world!” program contains:

            library functions       -       58
            function main()         -       1
    

    Of course, this is an artificial example but our analysis has shown that real life programs contain, on average, 50% of library functions. This is why the user of a disassembler is forced to waste more than half of his time isolating those library functions. The analysis of an unknown program resembles the resolution of a gigantic crossword puzzle : the more letters we know, the easier it is to guess the next word. During a disassembly, more comments and meaningful names in a function means a faster understanding of its purpose. Widespread use of standard libraries such as OWL, MFC and others increase even more the contribution of the standard functions in the target program.

    A middle sized program for Win32, written in C++, using modern technologies (e.g., AppExpert or a similar wizard) calls anything from 1000 to 2500 library functions.

    To assist IDA users we attempted to create an algorithm to recognize the standard library functions. We wanted to achieve a practical, usable result and therefore accepted some limitations

    • we only consider programs written in C/C++

    • we do not attempt to achieve perfect function recognition : this is theoretically impossible. Moreover the recognition of some functions may lead to undesirable consequences. For example, the recognition of the following function

                      push    bp
                      mov     bp, sp
                      xor     ax, ax
                      pop     bp
                      ret
            
      

      would lead to many misidentifications. It is worth noting that in modern C++ libraries one can find a lot of functions that are absolutely identical byte-to-byte but have different names.

    • we only recognize and identify functions located in the code segment, we ignore the data segment.

    • when a function has been sucessfully identified, we assign it a name and an eventual comment. We do not aim to provide information about the function arguments or about the behaviour of the function.

    and we imposed the following constraints upon ourselves

    • we try to avoid false positives completely. We consider that a false positive (a function wrongly identified) is worse than a false negative (a function not identified). Ideally, there should be no false positive at all.
    • the recognition of the functions must require a minimum of processor and memory resources.
    • because of the polyvalent architecture of IDA – it supports tens of very different processors – the identification algorithm must be platform-independent, i.e. it must work with the programs compiled for any processor.
    • the main() function should be identified and properly labelled as the library’ startup-code is of no interest.

    The Difficulties

    Memory usage

    The main obstacle to recognition and identification is the sheer quantity of functions and the size of the memory they occupy. If we evaluate the size of the memory occupied by all _versions_ of all libraries produced by all compiler _vendors_ for memory _models_, we easily fall into the tens of gigabytes range.

    Matters get even worse if we try to take OWL, MFC, MFC and similar libraries into account. The storage needed is huge. At this time, personal computers’ users can’t afford to set aside hundreds of Megabytes of disk space for a simple utility disassembler. Therefore, we had to find an algorithm that diminishes the size of the information needed to recognize standard library functions. Of course, the number of functions that should be recognized dictates the need for an efficient recognition algorithm : a simple brute force search is not an option.

    Variability

    An additional difficulty arises from the presence of _variant_ bytes in the program. Some bytes are corrected (fixed up) at load time, others become constants at link time, but most of the variant bytes originate from references to external names. In that case the compiler does not know the addresses of the called functions and leaves these bytes equal to zeroes. This so called “fixup information” is usually written to a table in the output file (sometimes called “relocation table” or “relocation information”). The example below

    B8 0000s                             mov     ax, seg _OVRGROUP_
    9A 00000000se                        call    _farmalloc
    26: 3B 1E 0000e                      cmp     bx, word ptr es:__ovrbuffer
      
    

    contains variant bytes. The linker will try to resolve external references, replacing zeroes with the addresses of called functions, but some bytes will stay untouched : references to dynamic libraries or bytes containing absolute address in the program. These references can be resolved only at load time by the system loader. It will try to resolve all external references and replace zeroes with absolute addresses. When the system loader cannot resolve an external referenceI, as it is the case when the program refers to an unknown DLL, the program will simply not run.

    Optimizations introduced by some linkers will also complicate the matter because constant bytes will sometim es be changed. For example:

                   0000: 9A........        call    far ptr xxx
    
                 is replaced by
    
                   0000: 90                nop
                   0001: 0E                push    cs
                   0002: E8....            call    near ptr xxx
    
      
    

    The program will execute as usual, but the replacement introduced by the linker effectively prohibits byte-to-byte comparison with a function template. The presence of variant bytes in a program makes the use of simple checksums for recognition impossible. If functions did not contain variant bytes, the CRC of the first N Bytes would be enough to identify and select a group of functions in a hash table. The use of such tables would greatly decrease the size of the information required for identification : the name of a function, its length and checksum would suffice.

    We have already mentionned the fact that the recognition of all standard library functions was not possible or even desirable. One additional proof is the fact that some identical functions do exactly the same thing but are called in a different manner. For example, the functions strcmp() and fstrcmp() are identical in large memory models.

    We face a dilemna here : we do not want to discard these functions from the recgnition process since they are not trivial and their labelling would help the user but, we are unable to distinguish them.

    And there is more : consider this

                    call    xxx
                    ret
            or
                    jmp     xxx
      
    

    At first sight, these pieces of code are not interesting. The problem is that they are present, sometimes in significant number, in standard libraries. The libraries for the Borland C++ v1.5 OS/2 compiler contains 20 calls of this type, in important functions such as read(), write(), etc.

    Plain comparison of these functions yields nothing. The only way to distinguish those functions is to discover what other function they call. Generally, all short functions (consisting merely of 2-3 instructions) are difficult to recognize and the probability of wrong recognition is very high. However not recognizing them is undesirable, as it can lead to cascade failures : if we do not recognize the function tolower(), we may fail to recognize strlwr() which refers to tolower().

    Finally, there is an obvious copyright problem: standard libraries may simply not be distributed with a disassembler.

    The idea

    To address those issues, we created a database of all the functions from all libraries we wanted to recognize. IDA now checks, at each byte of the program being disassembled, whether this byte can mark the start of a standard library function.

    The information required by the recognition algorithm is kept in a signature file. Each function is represented by a pattern. Patterns are first 32 bytes of a function where all variant bytes are marked.

    For example:

    558BEC0EFF7604..........59595DC3558BEC0EFF7604..........59595DC3 _registerbgidriver
    558BEC1E078A66048A460E8B5E108B4E0AD1E9D1E980E1C0024E0C8A6E0A8A76 _biosdisk
    558BEC1EB41AC55604CD211F5DC3.................................... _setdta
    558BEC1EB42FCD210653B41A8B5606CD21B44E8B4E088B5604CD219C5993B41A _findfirst
      
    

    where variant bytes are displayed as “..” Several functions start with the same byte sequence. Therefore a tree structure seems particularly well suited to the storage of those functions :

    558BEC
          0EFF7604..........59595DC3558BEC0EFF7604..........59595DC3 _registerbgidriver
          1E
            078A66048A460E8B5E108B4E0AD1E9D1E980E1C0024E0C8A6E0A8A76 _biosdisk
            B4
              1AC55604CD211F5DC3                                       _setdta
              2FCD210653B41A8B5606CD21B44E8B4E088B5604CD219C5993B41A   _findfirst
    

    Sequences of bytes are kept in the nodes of the tree. In this example, the root of the tree contains the sequence “558BEC”, three subtrees stem from the root, respectively starting with bytes 0E, 1E, B4. The subtree starting with B4 gives birth to two subtrees. Each subtree ends with leaves . The information about the function is kept in that (only the name is visible in the above example).

    The tree data structure simultaneously achieves two goals :

    • Memory requirements are decreased since we store bytes common to several functions in tree nodes. This saving is, of course, proportional to the number of functions starting with the same bytes.
    • It is well suited to fast fast pattern matching. The number of comparisons required to match a specific location within a program to all functions in a signature file grows logarithmically with the number of functions.

    It would not be very wise to take a decision based on the first 32 bytes of a function alone. As already suggested, modern real-world libraries contain several functions starting with the same bytes:

    558BEC
          56
            1E
              B8....8ED8
                       33C050FF7608FF7606..........83C406
                                                          8BF083FEFF
                        0. _chmod   (20 5F33)
                        1. _access  (18 9A62)
      
    

    When two functions have the same first 32 bytes, they are stored in the same leaf of the tree. To resolve that situation, we calculate the CRC16 of the bytes starting from position 33 until till the first variant byte. The CRC is stored in the signature file. The number of bytes used to calculate that CRC also needs to be saved, as it differs from function to function. In the above example, the CRC16 is calculated on 20 bytes for the _chmod (bytes 33..52) function and 18 _access function.

    There is, of course, a possibility that the first variant byte will be at the 33d position. The length of the sequence of bytes used to calculate the CRC16 is then equal to zero. In practice, this happens rarely and this algorithm gives very low number of false recognitions.

    Sometimes functions have the same initial 32-byte pattern and the same CRC16, as in the example below

    05B8FFFFEB278A4606B4008BD8B8....8EC0
              0. _tolower (03 41CB) (000C:00)
              1. _toupper (03 41CB) (000C:FF)
      
    

    We are unlucky: only 3 bytes were used to calculate the CRC16 and they were the same for both functions. In this case we will try to find a position at which all functions in a leaf have different bytes. (in our example this position is 32+3+000C)

    But even this method does not allow to recognize all functions. Here is another example:

    ... (partial tree is shown here)
                    0D8A049850E8....83C402880446803C0075EE8BC7:
                      0. _strupr (04 D19F) (REF 0011: _toupper)
                      1. _strlwr (04 D19F) (REF 0011: _tolower)
      
    

    These functions are identical at non-variant bytes and differ only by the functions they call. In this example the only way to distinguish functions is to examine the name referenced from the instruction at offset 11.

    The last method has a disadvantage: proper recognition of functions _strupr() and _strlwr() depends on the recognition of functions _toupper() and _tolower(). It means that in the case of failure because of the absence of reference to _toupper() or _tolower() we should defer recognition and repeat it later, after finding _tolower() or _toupper(). This has an impact on the general design of the algorithm : we need a second pass to resolve those deferred recognitions. Luckily, subsequent passes are only applied to a few locations in the program.

    Finally, one can find functions that are identical in non-variant bytes, refer to the same names but are called differently. Those functions have the same implementation but different names. Surprisingly, this is a frequent situation in standard libraries, especially in C++ libraries.

    We call this situation a _collision_ which occurs when functions attached to a leaf cannot be distinguished from each other by using the described methods. A classical example is:

    558BEC1EB441C55606CD211F720433C0EB0450E8....5DCB................
       0. _remove (00 0000)
       1. _unlink (00 0000)
    
       or
    8BDC36834702FAE9....8BDC36834702F6E9............................
       0. @iostream@$vsn            (00 0000)
       1. @iostream_withassign@$vsn (00 0000)
      
    

    Artificial Intelligence is the only way to resolve those cases. Since our goal was efficiency and speed, we decided to leave artificial intelligence for the future developments of the algorithm.

    The Implementation

    In IDA version 3.6, the practical implementation of the algorithm matches the above description almost perfectly. We have limited ourselves to the C and C++ language but it will be, without doubt, possible to write pre-processors for other libraries in the future.

    A separate signature file is provided for each compiler. This segregation decreases the probability of cross-compiler identification collisions. A special signature file, called startup signature file is applied to the entry point of the disassembled program to determine the generating compiler. Once it has been identified, we know which signature file should be used for the rest of the disassembly. Our algorithm successfully discerns the startup modules of most popular compilers on the market.

    Since we store all functions’ signatures for one compiler in one signature file, it is not necessary to discriminate the memory models (small,compact, medium, large, huge) of the libraries and/or versions of the compilers.

    We use special startup-signatures for every format of disassembled file. The signature exe.sig is used for programs running under MS DOS, lx.sig or ne.sig – for OS/2, etc.

    To decrease a probability of false recognition of short functions, we must absolutely remember any reference to an external name if such a reference exists. It may decrease, to some degree, the probability of the recognition of the function in general but we believe that such an approach is justified. It is better not to recognize than to recognize wrongly. Short functions (shorter than 4 bytes) that do no contain references to external names are not used in the creation of a signature file and no attempt is made to recognize such functions.

    The functions from <ctype.h> are short and refer to the array of types of the symbols, therefore we decided to consider the references to this array as an exception : we calculate the CRC16 of the array of the types of the symbols and store it in the signature file.

    Without artificial intelligence, the collisions are solved by natural intelligence. The human creator of a signature file chooses the functions to include and to discard from the signature file. This choice is very easy and is practically implemented by the edition of a text file.

    The patterns of the functions are not stored in a signature file under their original form (i.e., they do not look like the example figures). In place of the patterns, we store the arrays of bits determining the changing bytes and the values of the individual bytes are stored. Therefore the signature file contains no byte from the original libraries, except for the names of the functions. The creation of a signature file involves in 2 stages: the preprocessing of the libraries and the creation of a signature file. In the first stage the program ‘parselib’ is used. It preprocesses *.obj and *.lib files to produce a pattern-file. The pattern-file contains the patterns of the functions, their names, their CRC16 and all other information necessary to create the signature file. At the second stage the ‘sigmake’ program builds the signature file from the pattern-file.

    This division into 2 stages allows sigmake utility to be independent of the format of the input file. Therefore it will be possible to write other preprocessors for files differing from *.obj and *.lib in future.

    We decided to compress (using the InfoZip algorithm) the created signature files to decrease the disk space necessary for their storage.

    For the sake of user’s convenience we attempted to recognize the main() function as often as it was possible. The algorithm for identifying this function differs from compiler to compiler and from program to program. (DOS/OS2/Windows/GUI/Console…).

    This algorithm is written, as a text string, in a signature file. Unfortunately we have not yet been able to automate the creation of this algorithm.

    The Results

    As it turns out the signature files compress well; they may be compressed by a factor bigger than 2. The reason of this compressibility is that about 95% of a signature file are function names. (Example: the signature file for MFC 2.x was 2.5MB before compression, 700Kb after. It contains 33634 function names; an average of 21 bytes is stored per function. Generally, the ratio of the size of a library size to the size of a signature file varies from 100 to 500.

    The percentage of properly recognized functions is very high. Our algorithm recognized all but one function of the “Hello World” program. The unrecognized function consists of only one instruction:

            jmp     off_1234
      
    

    We were especially pleased with the fact that there was no false recognition. However it does not mean that they will not occur in the future. It should be noted that the algorithm only works with functions.

    Data is sometimes located in the code segment and therefore we need to mark some names as “data names”, not as “function names”. It is not easy to examine all names in a modern large library and mark all data names.

    The implementation of these data names is planned, some time in the future.

    Generate FLIRT signature file

     Action    name: makesig:create_signature
     
    

    This command generate a FLIRT signature file. A function is eligible when then name don’t start with “sub_”.

     File: Pathname for the signature file
     Library name: identifier, shown in the description of Signature
    
     Collect functions
      - All: Generate signature for all functions in the idb that are eligible
      - Selected: Generate a signature only for the selection in Functions
    
     Collisions
      - Ignore: don't add collision FLIRT signature
                will delete the Exclusion file if it exists
      - Deal with manually: if there is collisions, a window will open to manage
                            the collisions
    

    Two or three files are generated:

     - Signature file: The output file
     - Pattern file:   Filename is Signature filename with extension replaced
                       with "pat"
     - Exclusion File: Filename with extension replaced by "exc"
                       Only present if you want to deal with collision and there
                       is any.
    

    The last two files can be deleted once the signature file is generated.

    Supported Compilers

    Supported C Compilers

    • Aztec C v3.20d
    • Borland C++ for OS/2 v1.0, v1.5, v2.0
    • Borland Turbo C v2.0, v2.01
    • Borland Turbo C++ v1.01
    • Borland C++ v2.0, v3.1, v4.0, v4.5, v5.0, v5.01
    • Borland C++ Builder v1.0
    • Borland C++ Builder v3.0
    • EMX (GCC) for OS/2 v0.9b
    • IBM C Set v2.00, v2.10
    • IBM Visual Age C++ v3.0 OS/2
    • Lattice C v3.30
    • Metaware High C for OS/2
    • Microsoft C v5.0, v6.0, v7.0 Microsoft Quick C v1.0, v2.01
    • Microsoft Visual C++ v1.0, v1.5, v2.0, v4.0, v4.1, v5 and v6
    • NDP C v4.2
    • Optima v1.0
    • Symantec C++ v6.0, 6.1, 7.2
    • Texas Instruments C Compiler for TMS320C6
    • Visual Age C++ v3.0
    • Visual Age C++ v3.5
    • Watcom C++ v9.01d, v9.5, v10.0,
    • v10.0b, v10.5, v10.6
    • Watcom for QNX
    • Zortech C v1.0, v3.1
    • Microsoft Visual C++ v7, 8 (Microsoft.NET)
    • Microsoft 64-bit Visual C++ AMD64
    • Microsoft Visual C++ for Windows CE v3-4.2 on ARM
    • Borland C++ Build v1-6
    • GNU C compilers on various platforms

    Supported Pascal Compilers

    • Borland Turbo Pascal 5, 5.5, 6, 7, Borland Turbo Pascal for Windows
    • Borland Delphi 1, Delphi 2, Delphi 3, Delphi 4, Delphi 5

    Supported Fortran Compilers

    • MS Fortran PowerStation 4.0

    Supported Libraries

    • Microsoft Foundation Classes
    • Borland 5.0x MFC adaptation, Borland Visual Component Library
    • CTask
    • SDK CAB Library
    • Vireo Libraries Borland Edition and MicroSoft Edition
    • Object Toolkit Pro
    • Windows CE libraries
    • Keil runtime libraries for C166
    • C runtime library for I960
    • C runtime for TMS320C6
    • Borland 6.0x Visual Component Library

    How does it work ?

    Have a look at the Flirt technical paper!

    Turbo Pascal

    (FLIRT libraries thanks to Nick Pisanov)

    Turbo Pascal Program

    Turbo Pascal Program

    FLIRT-Enhanced Disassembly

    Note: this result is totally automatic, including the comments.

    FLIRT-Enhanced Disassembly

    Delphi

    Thanks to Peter Sawatzki who kindly generated the FLIRT sig files. He also donated Delphi 4/5 files.

    Delphi 3 Program

    Delphi 3 Program

    FLIRT-Enhanced Disassembly

    Note : this result is totally automatic, including the comments.

    FLIRT-Enhanced Disassembly

    Makesig

    Built-in Makesig plugin is a tool for generating FLIRT signatures from a current database.

    {% hint style=“info” %} The content here was a part of the blog article {% endhint %}

    How to make signatures from working database?

    1. Export the patterns from the database into a .sig file;
    2. Re-import the .sig into the target database.

    Example

    Let’s see how that would work in a real scenario. Imagine working on a long-term reversing project with frequent new versions. With the makesig plugin, we can migrate the carefully curated list of functions that we already reverse-engineered and exported as a signature file, into the current binary (given that compiler flags didn’t change too much between releases). Let’s say we identified an interesting function In the older release (source) binary and wanted to port that information to the newer binary:

    We can export a signature file for this function via menu item File -> Produce File -> Create SIG file…

    Create .sig file dialog

    Then, in the new binary file, we can import this signature file in the Signatures window:

    Import signature

    As we can see, IDA applies the signature and reports that it found a match in the new database! And indeed, we can find the function, labeled as a library function, because its function name came from the signature file:

    Applied signature

    Working with Types

    IDA type system fundamentals

    The IDA type system is based on C-like constructs such as:

    • Structures: Aggregate data types that group multiple members.
    • Unions: Allow overlapping the same memory with different data types.
    • Enums: Provide named integer constants.

    IDA ships with type libraries out-of-the-box, but you can define custom types in the Local Types window.

    Type definitions sources

    • Built-in or custom type libraries(.til files)
    • Custom types
    • Debug information (e.g., PDB or DWARF)

    Type libraries

    IDA ships with type libraries for popular platforms and operating systems. They provide predefined data types that can be used in your analysis. You can view a list of currently loaded type libraries in the Type Libraries window (View → Open subviews → Type Libraries, or Shift+F11)

    Load additional type libraries

    1. Go to the Type Libraries window. Right-click on the libraries list and select Load type library…, or press the Ins key.

    Load type library

    1. Select the type library from the list and click OK.

    Once loaded, type library definitions are accessible throughout IDA, including the Local Types window.

    {% hint style=“info” %} Relation between Local Types and Type Libraries: In IDA, Local Types are custom or imported type definitions specific to your current project, while Type Libraries provide pre-defined types for common platforms and architectures. Types in the Type Libraries, once referenced, are copied into the IDB and appear under the Local Types window. {% endhint %}

    See also:

    Type management essentials: Local Types view

    The Local Types view provides a centralized hub for managing and customizing type definitions directly within the IDA UI. To access this view, navigate to View → Open subviews → Local Types or press Shift+F1 keys.

    Local Types window

    In the Local Types window, you can:

    Add new types

    In the Add type dialog, you can create a custom structure, union, and enumeration, or import them from loaded libraries. To add a new type:

    • press the Ins key
    • right-click on the types list and select Add type… from the context menu
    • go to Edit → Add type….

    Create a structure (struct)

    1. Open the Add type dialog and in the Struct tab configure the structure settings: Add struct

    Understanding structure options:

    • Name: the unique name of your struct.

    • Fixed layout (default: enabled) When checked:

      • It locks the struct size and members. It prevents accidentally changing the struct size, for example, if the user moves members around while modifying another type. Fixed layout ensures the structure layout remains stable unless explicitly modified. Note: You can still add a field to a fixed structure.
      • You need to specify the Structure size in bytes.
    • Make type choosable (default: enabled) When checked:

      • It includes this struct in the type listing.
    • Pack fields (default: disabled) When checked:

      • It packs the fields of the struct (removes padding) and saves memory.
    • Tuple (default: disabled) When checked:

      • Creates tuple, a special kind of struct.
    • Create union (Leave unchecked for structures)

      • Only check it when creating a union instead of a struct.
    1. Click OK.

    As an alternative, you can create or edit structures via free-text editor.

    Create a tuple

    {% hint style=“info” %} Tuples are dedicated for Golang functions that return multiple values. Unlike a function with single return value (e.g., a struct), which is returned entirely in registers or entirely on the stack, tuple fields are handled separately: some may be returned in registers, others on the stack. {% endhint %}

    1. Open the Add type dialog and in the Struct tab configure the tuple settings:
      • specify the unique name of your tuple, and
      • check the Tuple checkbox.
    Add tuple
    1. Click OK.

    {% hint style=“info” %} Two tuples with the same field types are considered equal, regardless of the field names. {% endhint %}

    Create a union

    {% hint style=“info” %} A union is de facto a type of a struct. Creating and editing unions follow the same principles as working with structs. {% endhint %}

    1. Open the Add type dialog and in the Struct tab configure the union settings:
      • specify the unique name of your union, and
      • check the Create union checkbox.
    Add union

    {% hint style=“info” %} When you choose to create a union, the fixed layout option will no longer be available. If you would like to turn a union to a fixed layout structure, first change “union” to “struct” in the C syntax tab, and then edit the struct. {% endhint %}

    1. Click OK.

    Create an enumeration (enum)

    1. Open the Add type dialog and in the Enum tab configure the enum settings: Add enum

    Understanding enum options:

    • Name: specify the unique name of your enum

    • Size: (default: auto)

      • It determines how much memory the enum values will occupy
      • You can select from dropdown the number of bytes (1, 2, 4, or 8 bytes)
      • The auto option lets the compiler decide based on values
    • Number representation: defines how enum values are displayed in IDA

      • Select the format for enum members from the available options: Hexadecimal, Decimal, Octal, Binary or Character (ASCII/Unicode)
    • Signed: (default: disabled)

      • It determines if enum values can be negative
    • Bitmask: (default: disabled) When checked:

      • It makes the enum a bitfield, and allows the representation of multiple flags in a single value using bitwise operations (e.g., OR, AND)
    1. Click OK.

    As an alternative, you can create or edit enums via free-text editor.

    Modify existing types

    To modify an existing type:

    • press Ctrl+E or
    • right-click on the list of existing types and select Edit type… from the context menu.

    Managing structure fields

    Basic operations for managing struct fields are available in the context menu (from Local Types view) or via Edit menu:

    CommandHotkeyDescription
    RenameNRename field
    Insert gap…-Expand the current structure by inserting undefined bytes at the cursor location. Note: the cursor must not be at the end. To define a member at the end of the structure, just use data definition commands.
    Remove gap…-Shrink the current structure by deleting undefined bytes at the cursor location. The cursor must be positioned on an undefined byte. IDA will prompt the dialog to specify the number of bytes to delete.
    Duplicate a structure type-Create a copy of the structure

    Commands for converting structure fields to different data types:

    CommandHotkeyDescription
    DataDConvert to basic data type
    StringAConvert to string literal
    Array*Convert to array

    Managing enum members

    Basic operations for managing enum members are available in the context menu (from Local Types view) or via Edit menu:

    CommandHotkeyDescription
    Add enum member…DCreate a new symbolic constant in the enum. You have to specify its name and value in the new dialog. You cannot define more than 256 constants with the same value in an enum. If the current enum is a bitfield, you need to specify the bitmask. To learn about bitmasks, read about bitfields.
    Edit enum member…Ctrl + NModify existing enum member name or value. To rename an enum type name, you can also use the Rename option from the context menu.
    Delete member “member_name”URemove enum member and all associated data, including comments.

    Modifying field types

    • In the Local Types view: right-click on a field and use the Field type submenu to modify member types
    • In the Disassembly/IDA View: use commands from the Edit|Operand types… submenu

    Delete existing types

    To delete an existing type:

    • press Del or
    • right-click on the list of existing types and select Delete type… from the context menu.

    {% hint style=“info” %} Deleting a type will remove all references to it from the database. If you recreate the type later, references will not be restored automatically and must be manually reassigned. {% endhint %}

    Copy full type(s) definition to clipboard

    To copy the entire C-style definition of the type:

    1. In the Local Types view, right-click on the type you want to copy and select Copy full type(s) from the context menu
    2. The complete definition, including all nested types and dependencies, will be copied to your clipboard.

    Adding and editing types via free-text editor

    The Struct/Enum tabs are perfect for learning IDA type system and creating simple, single types. However, for more complex tasks—such as copying types from existing source code or defining multiple related types simultaneously—the text editor offers greater efficiency and flexibility.

    Add a type using C syntax tab

    1. In the Local Types view, open the Add type dialog.
    2. Go to the C syntax tab and enter a new type declaration.
    C syntax tab

    Edit a type using C syntax tab

    1. In the Local Types view, right-click on the existing type and select Edit type… from the context menu.
    2. Go to the C syntax tab and modify the type.
    C syntax tab

    Create multiple type definitions at once

    The Parse declarations… option allows you to input and process many type definitions at once, enabling batch creation of multiple types.

    1. Right-click on the types list in the Local Types view and select Parse declarations… from the context menu.
    2. In the Parse declarations… dialog, enter the type definitions using C syntax and click OK to add them to the Local Types.
    Parse definitions tab

    Importing types

    Import types from loaded type libraries

    Before you start importing types from type libraries, ensure that your desired library is already loaded in the Type Libraries window.

    Import standard structures

    If you want to import an existing standard structure:

    1. Open the Add type dialog and in the Struct tab, click Import standard structure. Import struct

    2. In the new dialog, browse and select the structure from the list of all corresponding types in the loaded libraries, then click OK to import it.

    Import standard enums

    If you want to import an existing standard enum from the type library:

    1. Open the Add type dialog and in the Enum tab, click:
    • Import standard enum by enum name (1), or
    • Import standard enum by symbol name (2) (useful when you know the member names but not the enum name).
    Import enum
    1. In the new dialog, browse and select the enum from the list of all corresponding types in the loaded libraries, then click OK to import it.

    Import type definitions from C/C++ header files

    Header files can be parsed by three different parsers:

    • legacy parser, that supports basic C,
    • old_clang, which deals with complex C/C++/Objective-C source code (previous parser based on clang),
    • clang - new parser introduced in IDA 9.2 (based on LLVM), supporting C/C++

    You can select source parser in Options → Compiler…:

    Parser settings in the Compiler options

    To import type definitions from header files:

    1. Navigate to Files → Load file → Parse C header file…
    2. Select your header file and click OK to import it. You should see a notification about a successful compilation. When you import a header file, all the type definitions from that file are added to your Local Types.

    How can I download IDACLang? IDAClang is a standalone command line tool to produce type libraries, that you can get from My Hex-Rays download center.
    Note that we plan to drop support for IDAClang in future versions.

    See also:

    Import debug information

    IDA supports debugging information formats such as PDB and DWARF. If your input file includes debugging information with types data, IDA will automatically import the types while loading the file.

    DWARF info

    The imported types will be displayed in the Local Types window, organized under the corresponding folder (either dwarf or pdb).

    Types imported with debug info

    Working with types programmatically

    In addition to the manual approach through IDA’s graphical interface, types can be created, modified, and managed programmatically using our APIs. This, among others, allows for the automation of type-related tasks or the creation of complex data structures, making it particularly useful for handling large sets of types or performing repetitive operations.

    See also:

    Creating Type Libraries

    Using the IDAClang plugin for IDA Pro

    Overview

    The IDAClang plugin integrates the clang compiler frontend into IDA itself. This allows IDA to parse type information from complex C/C++/Objective-C source code and import it directly into an IDA database.

    Libclang

    IDAClang utilizes a specialized build of libclang - the opensource C API for the clang compiler. This custom library is also shipped with IDA alongside the plugin itself, so you do not need to worry about it. The plugin will find and load libclang automatically.

    Our build of libclang is from Clang v13.0, so it can handle any Objective-C syntax and anything from C++20 and earlier.

    Motivation

    IDAClang was introduced as a more robust alternative to IDA’s built-in source code parser. The built-in parser can handle simple C source code, but naturally it struggles to handle complex C++ and Objective-C syntax. IDAClang solves this problem by outsourcing all the heavy lifting to a third-party library that can handle the ugly parsing operations. The plugin needs only to parse the abstract syntax tree generated by clang.

    As a result, IDAClang should be much more flexible. You can even feed it complete .cpp source files. The plugin will extract whatever useful type information it can find, and ignore the rest.

    VTables

    One big advantage of using libclang is that we can take advantage of clang’s internal C++ VTable management. For example, when IDAClang parses a C++ class that looks like this:

    class C
    {
      virtual void func(void);
    };
    

    The following types will be generated in the database:

    struct __cppobj C
    {
      C_vtbl *__vftable /*VFT*/;
    };
    
    struct /*VFT*/ C_vtbl
    {
      void (__cdecl *func)(C *this);
    };
    

    To create the C_vtbl type, IDAClang traverses clang’s internal VTableLayout data structure. This data structure is the same mechanism that the clang compiler uses during the actual code generation. Thus, we can be very confident that IDAClang is producing correct vtable types - even in much more complex situations. After all, clang knows what it’s doing in this regard.

    Moreover, when using IDAClang to generate a type library (see Building Type Libraries with IDAClang below), the plugin will take advantage of clang’s name mangling to populate the symbol table:

    SYMBOLS
    FFFFFFFF 00000000 void __cdecl _ZN1C4funcEv(C *this);
    00000018 00000000 C_vtbl_layout _ZTV1C;
    
    TYPES
    struct C_vtbl_layout
    {
      __int64 thisOffset;
      void *rtti;
      void (__cdecl *func)(C *this);
    };
    

    Here IDAClang created symbols for the C::func member function, as well as the mangled VTable symbol for the C class.

    Templates

    Another notable advantage of using libclang is it allows us to gracefully handle C++ templates.

    For example, consider the following template declarations:

    template <typename T, typename V> struct S
    {
      T x;
      V y;
    };
    
    typedef S<int, void *> instance_t;
    

    When clang parses the instance_t declaration, internally it will generate a structure that represents the specialized template S<int, void *>. The IDAClang plugin will then use this internal representation to generate a valid type for S<int, void *> in IDA’s type system:

    struct S<int, void *>
    {
      int x;
      void *y;
    };
    
    typedef S<int, void *> instance_t;
    

    The type with name S<int, void *> represents the fully resolved structure, with all template arguments replaced. This all happens automatically, and it is especially useful in more complex situations - such as template classes containing virtual methods that depend on template parameters, resulting in specialized VTables.

    The IDAClang UI

    Enabling the IDAClang Parser

    To provide support for third-party parsers, IDA now has a new Source parser field in the Options>Compiler dialog:

    compiler options1

    To enable the IDAClang parser, select the clang parser from the dropdown menu:

    compiler options2

    As a quick sanity check, try saving the following declaration in a file called test.h:

    typedef int myint_t;
    

    Parse the file using menu File>Load file>Parse C header file. IDA should print this to the output window:

    /private/tmp/test.h: successfully compiled
    

    The type should now be present in the Local Types view:

    local types1

    Configuring IDAClang

    Of course, IDAClang is capable of parsing source code that is much more complex. Often times this requires more detailed configuration of the parser invocations.

    To support this, the Compiler>Options dialog provides the Arguments field:

    compiler options3

    In this field you can provide any argument you would typically provide to the clang compiler when invoking it from the command line. For example:

    compiler options4

    One of the more important clang arguments is the -target option, which specifies the target architecture and platform. This allows clang to properly configure itself to parse macOS/Windows/Linux system headers. Clang calls this the target “triple” because it is often given in the form of:

    -target <arch>-<vendor>-<platform>
    

    Some examples:

    -target arm64-apple-darwin
    -target x86_64-pc-win32
    -target i386-pc-linux
    

    The various combinations of supported targets is documented in more detail here.

    Note that in the simple test.h example above, we did not specify a target platform. In this case clang will assume that the target platform is the same as the host machine IDA is currently running on. You can print the exact target used by clang by opening Options>Compiler>Parser specific options and enable the following option:

    clang options1

    Now when we use IDAClang to parse the test.h file, it will print a message:

    IDACLANG: triple: x86_64-apple-macosx10.15.0
    

    Which would be the typical output when IDA is running on macOS. On Windows the default will look something like:

    IDACLANG: triple: x86_64-pc-windows-msvc19.29.30137
    

    And on Linux:

    IDACLANG: triple: x86_64-unknown-linux-gnu
    

    Such is the default behavior within libclang, but clang supports a wide variety of platforms and architectures. You can almost always specify a target that will match the input binary in the current database.

    Example Files Package

    You can download all the examples referenced in this tutorial from here:

    {% file src=“assets/examples.zip” %}

    STL Example

    Now let’s try invoking IDAClang on some more real-world source code.

    In this example, assume we are analyzing an x64 binary that makes heavy use of the C++ Standard Template Library. Then assume that at some point we want to create a structure that looks like this:

    #include <string>
    #include <vector>
    #include <map>
    #include <set>
    
    struct stl_example_t
    {
      std::string str;
      std::vector<int> vec;
      std::map<std::string, int> map;
      std::set<char> set;
    };
    

    This is the contents of stl/stl_example.h from examples.zip. IDA’s default parser cannot handle such complex C++ syntax, so IDAClang is our only hope of importing this type. The precise configuration of IDAClang will vary between platforms, so we’ll demonstrate them all separately.

    To parse stl_example.h on macOS, we’ll have to point IDAClang to the macOS SDK as well as the STL system headers:

    -target x86_64-apple-darwin
    -x c++
    -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
    -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1
    -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/11.0.3/include
    

    Copy the text above into the Options>Compiler>Arguments field.

    Note that we point IDAClang to the macOS SDK with the -isysroot option and use the -I option to allow IDAClang to find the proper system headers in the Xcode toolchain. Be wary of the last option (ending with usr/lib/clang/11.0.3/include). This path contains the clang version number, so it might be different on your machine. Also make special note of the -x c++ option. This is used to inform libclang that the input source will not be plain C, which is the default syntax for .h files in libclang.

    Now we can use File>Load file>Parse C header file to parse stl_example.h. This will generate a useful type for stl_example_t in our database:

    stl example macos

    On Windows the configuration is a bit different. If you’re using Visual Studio, libclang is normally able to detect common header paths automatically.

    Thus you will likely only need to specify the following arguments in Options>Compiler>Arguments:

    -target x86_64-pc-win32 -x c++
    

    Ideally this will be enough to parse stl_example.h and generate some useful type info:

    stl example windows

    If for whatever reason the heuristics within libclang fail to find the headers on your system, it is very easy to specify the header paths manually. Simply open a Visual Studio x64 Command Prompt and run the following command:

    echo %INCLUDE%
    

    This will print a semicolon-separated list of the header paths used on your system:

    vs prompt

    This list can be copied directly into the Options>Compiler>Include directories field in IDA. IDAClang will automatically process this list and pass the header paths to clang upon invocation of the parser. This is likely enough to handle most Windows-based source code.

    On Linux you can determine the header paths used your system by running the following command:

    cpp -v
    

    This will print something like:

    #include <...> search starts here:
     /usr/lib/gcc/x86_64-linux-gnu/6/include
     /usr/local/include
     /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed
     /usr/include/x86_64-linux-gnu
     /usr/include
    

    You can then use these arguments in the Options>Compiler>Arguments field in IDA:

    -target x86_64-pc-linux-gnu
    -x c++
    -I/usr/lib/gcc/x86_64-linux-gnu/6/include
    -I/usr/local/include
    -I/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed
    -I/usr/include/x86_64-linux-gnu
    -I/usr/include
    

    Then use File>Load file>Parse C header file to parse stl_example.h.

    Invoking IDAClang from IDAPython

    Like any good IDA feature, IDAClang can also be invoked from an IDAPython script.

    IDA 7.7 introduced the ida_srclang module to provide simple support for invoking third-party parsers from IDAPython. Use the following IDAPython commands for an overview of this new module:

    import ida_srclang
    ? ida_srclang
    ? ida_srclang.parse_decls_with_parser
    ? ida_srclang.set_parser_argv
    

    The function ida_srclang.parse_decls_with_parser can notably be used to parse source code snippets:

    Python>? ida_srclang.parse_decls_with_parser
    Help on function parse_decls_with_parser in module ida_srclang:
    parse_decls_with_parser(*args) -> 'int'
        Parse type declarations using the parser with the specified name
        @param parser_name: (C++: const char *) name of the target parser
        @param til: (C++: til_t *) type library to store the types
        @param input: (C++: const char *) input source. can be a file path or decl string
        @param is_path: (C++: bool) true if input parameter is a path to a source file, false if the
                        input is an in-memory source snippet
        @retval -1: no parser was found with the given name
        @retval else: the number of errors encountered in the input source
    

    If the is_path argument is False, this function will assume the input argument is a string that represents a source code snippet. Otherwise it will be considered a path to a source file on disk. Also note the til parameter, which will often times be None. This ensures the parsed types are imported directly into the current database.

    Examples

    IMPORANT NOTE: when libclang parses in-memory strings, it makes no assumptions about the expected syntax. Thus, you must specify the -x option to tell clang which syntax to expect before invoking the parser. Here are the the known syntax directives:

    -x c
    -x c++
    -x objective-c
    -x objective-c++
    

    For example, this is how you would use ida_srclang to parse a simple C source string with IDAClang:

    import ida_srclang
    # tell clang the expected syntax
    ida_srclang.set_parser_argv("clang", "-x c")
    # parse a type string
    ida_srclang.parse_decls_with_parser("clang", None, "typedef int myint_t;", False)
    

    STL Example Revisited

    We can also handle the same STL example discussed previously, but this time parse stl_example_t as a source snippet:

    import ida_srclang
    
    clang_argv = [
      "-target x86_64-apple-darwin",
      "-x c++",
      "-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk",
      "-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
      "-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/11.0.3/include",
      ]
    ida_srclang.set_parser_argv("clang", " ".join(clang_argv))
    
    decl = """
    #include <string>
    #include <vector>
    #include <map>
    #include <set>
    
    struct stl_example_t
    {
      std::string str;
      std::vector<int> vec;
      std::map<std::string, int> map;
      std::set<char> set;
    };
    """
    ida_srclang.parse_decls_with_parser("clang", None, decl, False)
    

    This should produce an identical result as before when we used File>Load file>Parse C header file for stl_example.h.

    Boost Example

    In this example we will show how IDAClang can be used in batch mode to improve the analysis of a binary compiled from Boost headers. The experiment will be performed on Debian Linux with gcc 6.3.0.

    Consider the following source files from the boost/ directory in examples.zip:

    • chat_server.cpp
    • chat_message.hpp

    These sources were taken directly from the Boost 1.77 examples, and we’ll use them to compile a test binary. Begin by downloading the Boost 1.77.0 headers, then compile the chat_server application:

    g++ -I boost_1_77_0 -std=c++11 -o chat_server.elf chat_server.cpp -lpthread
    

    Since Boost is a template library, it will generate a bloated binary that contains thousands of instantiated template functions. Thus, IDA’s initial analysis of chat_server.elf will likely not be very pretty. How can IDAClang help us with this? Consider boost/chat_server.py from examples.zip:

    import sys
    import ida_pro
    import ida_auto
    import ida_srclang
    
    clang_argv = {
      "-target x86_64-pc-linux",
      "-x c++",
      "-std=c++11",
      "-I./boost_1_77_0",
      # NOTE: include paths were copied from the output of `cpp -v`. they might differ on your machine.
      "-I/usr/lib/gcc/x86_64-linux-gnu/6/include",
      "-I/usr/local/include",
      "-I/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
      "-I/usr/include/x86_64-linux-gnu",
      "-I/usr/include",
    }
    
    # invoke the clang parser
    ida_srclang.set_parser_argv("clang", " ".join(clang_argv))
    ida_srclang.parse_decls_with_parser("clang", None, "./chat_server.cpp", True)
    
    # analyze the input file
    ida_auto.auto_mark_range(0, BADADDR, AU_FINAL)
    ida_auto.auto_wait()
    
    # save and exit
    ida_pro.qexit(0)
    

    This script will configure IDAClang to parse the chat_server.cpp source file and extract any type information it finds, then analyze the input with the imported type info, and saves the resulting database in chat_server.i64. You can run the script like this:

    idat64 -c -A -Schat_server.py -Oidaclang:t -ochat_server.i64 -Lchat_server.log chat_server.elf
    

    You may have noticed this option:

    -Oidaclang:t
    

    This option is passed to the IDAClang plugin and it enables CLANG_APPLY_TINFO (see idaclang.cfg for more info).

    Now let’s open the resulting database chat_server.i64 in IDA, and try decompiling some functions. Immediately we see that the analysis does benefit from the imported type info. For example chat_session::do_write seems somewhat intelligible after some minor simplifications:

    boost example1

    Since IDAClang parsed the chat_session class, we now have a correct prototype for chat_session:do_write, as well as a valid chat_session structure. Note that references to chat_session.write_msgs_ (std::deque<chat_message>) and chat_session.socket (boost::asio::ip::tcp::socket) were correctly resolved.

    Granted, this is not the most realistic example. It’s not often we have access to the full source code of the target binary, but hopefully this shows that whenever any relevant source code is available, IDAClang can take full advantage.

    Building Type Libraries with IDAClang

    The IDAClang plugin is useful for enriching your database with complex type information, but often times the imported types are relevant to more than just one database. In this section we discuss how you can use IDAClang to generate rich, generic type libraries for IDA Pro.

    Hex-Rays also provides a command-line version of IDAClang(which you can download from our Customer Portal), specifically designed for building custom Type Information Libraries (TILs) that can be loaded into any IDA database.

    After downloading the idaclang binary, copy it to the idabin/ directory of your IDA installation (next to the libclang dll).

    For an overview of idaclang’s functionality, run:

    idaclang -h
    

    For a quick demonstration, save the following source in a file named test.h:

    class C
    {
      virtual void func(void);
    };
    

    You can compile this header into a type library by invoking idaclang the same way you would typically invoke the clang compiler from the command line:

    idaclang -x c++ -target x86_64-pc-linux test.h
    

    This will generate a file called test.til that contains all types that were parsed in test.h. Try dumping the TIL with the tilib utility.

    tilib -l /tmp/test.til
    
    TYPE INFORMATION LIBRARY CONTENTS
    Description:
    Flags      : 0107 compressed macro_table_present extended_sizeof_info sizeof_long_double
    Base tils  :
    Compiler   : GNU C++
    sizeof(near*) = 8 sizeof(far*) = 8 near code, near data, cdecl
    default_align = 0 sizeof(bool) = 1 sizeof(long)  = 8 sizeof(llong) = 8
    sizeof(enum) = 4 sizeof(int) = 4 sizeof(short) = 2
    sizeof(long double) = 16
    SYMBOLS
    FFFFFFFF 00000000 void __cdecl ZN1C4funcEv(C *__hidden this);
    00000018 00000000 C_vtbl_layout ZTV1C;
    TYPES
    00000008 struct __cppobj C {C_vtbl *__vftable /*VFT*/;};
    00000008 struct /*VFT*/ C_vtbl {void (__cdecl *func)(C *__hidden this);};
    00000018 struct C_vtbl_layout {__int64 thisOffset;void *rtti;void (__cdecl *func)(C *__hidden this);};
    MACROS
    Total 2 symbols, 3 types, 0 macros
    

    The tool also provides extra arguments to configure the til generation. They are given the –idaclang- prefix so they can be easily separated from the clang arguments. For example:

    idaclang --idaclang-tilname /tmp/test2.til -x c++ -target x86_64-pc-linux test.h
    

    This will create the library at /tmp/test2.til, instead of the default location.

    Now let’s try building some type libraries from real-world code. The examples in this section will demonstrate the power of IDAClang by creating TILs from many different opensource C++ projects. They cover a large variety of platforms, architectures, and codebases, so it is best to unify the build system using makefiles.

    At the top level of examples.zip there should be a makefile named idaclang.mak:

    IDACLANG_ARGS += --idaclang-log-all
    IDACLANG_ARGS += --idaclang-tilname $(TIL_NAME)
    IDACLANG_ARGS += --idaclang-tildesc $(TIL_DESC)
    
    CLANG_ARGV += -ferror-limit=50
    
    all: $(TIL_NAME)
    .PHONY: all $(TIL_NAME) clean
    $(TIL_NAME): $(TIL_NAME).til
    
    $(TIL_NAME).til: $(TIL_NAME).mak $(INPUT_FILE)
        idaclang $(IDACLANG_ARGS) $(CLANG_ARGV) $(INPUT_FILE) > $(TIL_NAME).log
        tilib64 -ls $(TIL_NAME).til > $(TIL_NAME).til.txt
    
    clean:
        rm -rf *.til *.txt *.log
    

    This makefile defines a simple rule for building a TIL using the idaclang command-line utility. It will be used extensively in the following examples.

    IDASDK

    Hex-Rays publishes an SDK for developing custom IDA plugins, which is comprised mostly of C++ header files. Thus, it is a perfect use case for IDAClang. In this example we will build a type library for IDA itself, using IDA SDK, which the latest version you can download from Customer Portal.

    After downloading idasdk.zip, unzip it into the idasdk subdirectory of examples.zip.

    To build this TIL we only need to create a single header file that includes all headers from the IDA SDK, and then parse this file with idaclang. See examples/idasdk/idasdk.h, which contains include directives for all files in idasdk77/include (they happen to be in alphabetical order, but the order shouldn’t matter much):

    #include <auto.hpp>
    #include <bitrange.hpp>
    #include <bytes.hpp>
    // ... etc
    #include <typeinf.hpp>
    #include <ua.hpp>
    #include <xref.hpp>
    

    The IDAClang configuration required to parse idasdk.h is highly platform-dependent, so we provide separate makefiles for each of IDA’s supported platforms.

    To demonstrate how we might build idasdk.h on MacOSX, see examples/idasdk/idasdk_mac_x64.mak:

    TIL_NAME = idasdk_mac_x64
    TIL_DESC = "IDA SDK headers for MacOSX"
    INPUT_FILE = idasdk.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
    TOOLCHAIN = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain
    CLANG_ARGV = -target x86_64-apple-darwin                 \
                 -x objective-c++                            \
                 -isysroot $(SDK)                            \
                 -I$(TOOLCHAIN)/usr/include/c++/v1           \
                 -I$(TOOLCHAIN)/usr/lib/clang/11.0.3/include \
                 -I./idasdk77/include/                       \
                 -D__MAC__                                   \
                 -D__EA64__                                  \
                 -Wno-nullability-completeness
    
    include ../idaclang.mak
    

    You can build the TIL with:

    make -f idasdk_mac_x64.mak
    

    This will generate a type library named idasdk_mac_x64.til, along with a dump of the til contents in idasdk_mac_x64.til.txt. In the text dump we might notice some familiar types:

    00000010 struct __cppobj range_t
    {
      ea_t start_ea;
      ea_t end_ea;
    };
    //  0. 0000 0008 effalign(8) fda=0 bits=0000 range_t.start_ea ea_t;
    //  1. 0008 0008 effalign(8) fda=0 bits=0000 range_t.end_ea ea_t;
    //          0010 effalign(8) sda=0 bits=0080 range_t struct packalign=0
    
    00000050 struct __cppobj memory_info_t : range_t
    {
      qstring name;
      qstring sclass;
      ea_t sbase;
      uchar bitness;
      uchar perm;
    };
    //  0. 0000 0010 effalign(8) fda=0 bits=0020 memory_info_t.range_t range_t;
    //  1. 0010 0018 effalign(8) fda=0 bits=0000 memory_info_t.name qstring;
    //  2. 0028 0018 effalign(8) fda=0 bits=0000 memory_info_t.sclass qstring;
    //  3. 0040 0008 effalign(8) fda=0 bits=0000 memory_info_t.sbase ea_t;
    //  4. 0048 0001 effalign(1) fda=0 bits=0000 memory_info_t.bitness uchar;
    //  5. 0049 0001 effalign(1) fda=0 bits=0000 memory_info_t.perm uchar;
    //          004A unpadded_size
    //          0050 effalign(8) sda=0 bits=0080 memory_info_t struct packalign=0
    

    It’s worth building a separate til for both x64 and arm64 macOS. IDA’s source code is not very architecture dependent, but many system headers might be. So it’s best to be as precise as possible.

    To build this TIL on macOS12 for Apple Silicon, the approach is very similar:

    TIL_NAME = idasdk_mac_arm64
    TIL_DESC = "IDA SDK headers for arm64 macOS 12"
    INPUT_FILE = idasdk.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk
    TOOLCHAIN = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain
    CLANG_ARGV = -target arm64-apple-darwin                  \
                 -x objective-c++                            \
                 -isysroot $(SDK)                            \
                 -I$(TOOLCHAIN)/usr/lib/clang/13.0.0/include \
                 -I./idasdk77/include/                       \
                 -D__MAC__                                   \
                 -D__EA64__                                  \
                 -D__ARM__                                   \
                 -Wno-nullability-completeness
    
    include ../idaclang.mak
    

    Note that we did not provide the path to the C++ STL headers like we did in idasdk_mac_x64.mak. On macOS12 the C++ headers are shipped within MacOSX12.0.sdk, so there is no need to explicitly tell idaclang where to find them.

    To parse idasdk.h on Windows, use examples/idasdk/idasdk_win.mak:

    TIL_NAME = idasdk_win
    TIL_DESC = "IDA SDK headers for x64 Windows"
    INPUT_FILE = idasdk.h
    CLANG_ARGV = -target x86_64-pc-win32       \
                 -x c++                        \
                 -I./idasdk77/include          \
                 -D__NT__                      \
                 -D__EA64__                    \
                 -Wno-nullability-completeness
    
    include ../idaclang.mak
    

    Normally we do not need to specify any include paths, since idaclang can find the Visual Studio headers automatically. If it can’t, you can always explicitly provide include paths with the -I option.

    Building idasdk.h on Linux is also fairly straightforward. See idasdk_linux.mak:

    TIL_NAME = idasdk_linux
    TIL_DESC = "IDA SDK headers for x64 linux"
    INPUT_FILE = idasdk.h
    GCC_VERSION = $(shell expr `gcc -dumpversion | cut -f1 -d.`)
    CLANG_ARGV = -target x86_64-pc-linux                                      \
                 -x c++                                                       \
                 -I/usr/lib/gcc/x86_64-linux-gnu/$(GCC_VERSION)/include       \
                 -I/usr/local/include                                         \
                 -I/usr/lib/gcc/x86_64-linux-gnu/$(GCC_VERSION)/include-fixed \
                 -I/usr/include/x86_64-linux-gnu                              \
                 -I/usr/include                                               \
                 -I./idasdk77/include/                                        \
                 -D__LINUX__                                                  \
                 -D__EA64__                                                   \
                 -Wno-nullability-completeness
    
    include ../idaclang.mak
    

    You can also include the decompiler types from the hexrays SDK in the type library for your version of idasdk. Simply copy hexrays.hpp from hexrays_sdk/ in your IDA installation to idasdkXX/include/, then add this line to idasdk.h:

    #include <hexrays.hpp>
    

    Then rebuild the TIL. It will likely yield some useful decompiler types:

    00000050 struct __cppobj minsn_t
    {
      mcode_t opcode;
      int iprops;
      minsn_t *next;
      minsn_t *prev;
      ea_t ea;
      mop_t l;
      mop_t r;
      mop_t d;
    };
    //  0. 0000 0004 effalign(4) fda=0 bits=0000 minsn_t.opcode mcode_t;
    //  1. 0004 0004 effalign(4) fda=0 bits=0000 minsn_t.iprops int;
    //  2. 0008 0008 effalign(8) fda=0 bits=0000 minsn_t.next minsn_t *;
    //  3. 0010 0008 effalign(8) fda=0 bits=0000 minsn_t.prev minsn_t *;
    //  4. 0018 0008 effalign(8) fda=0 bits=0000 minsn_t.ea ea_t;
    //  5. 0020 0010 effalign(8) fda=0 bits=0000 minsn_t.l mop_t;
    //  6. 0030 0010 effalign(8) fda=0 bits=0000 minsn_t.r mop_t;
    //  7. 0040 0010 effalign(8) fda=0 bits=0000 minsn_t.d mop_t;
    //          0050 effalign(8) sda=0 bits=0080 minsn_t struct packalign=0
    
    00000028 struct __cppobj minsn_visitor_t : op_parent_info_t
    {
      minsn_visitor_t_vtbl *__vftable /*VFT*/;
    };
    //  0. 0000 0008 effalign(8) fda=0 bits=0100 minsn_visitor_t.__vftable minsn_visitor_t_vtbl *;
    //  1. 0008 0020 effalign(8) fda=0 bits=0020 minsn_visitor_t.op_parent_info_t op_parent_info_t;
    //          0028 effalign(8) sda=0 bits=0080 minsn_visitor_t struct packalign=0
    

    Qt

    In this example we will build a type library for the Qt Opensource UI Framework. The example uses Qt 5.15.2, but theoretically it can work for any Qt version. We assume you already have a Qt installation present on your system (See the QTDIR variable in the following makefiles).

    Let’s start by creating a file that includes as many Qt headers as we can. Qt makes this easy because they ship “umbrella” headers for the various sub-frameworks, which take care of including most of the critical Qt header files.

    See examples/qt/qt.h from examples.zip:

    #include <QtCore>
    #include <QtGui>
    #include <QtWidgets>
    #include <QtPrintSupport>
    #include <QtNetwork>
    #include <QtConcurrent>
    #include <QtDBus>
    #include <QtDesigner>
    #include <QtDesignerComponents>
    #include <QtHelp>
    #include <QtOpenGL>
    #include <QtSql>
    #include <QtTest>
    #include <QtUiPlugin>
    #include <QtXml>
    

    This will be more than enough to get started.

    To build qt.h on macOS, consider examples/qt/qt_mac.mak:

    TIL_NAME = qt_mac
    TIL_DESC = "Qt 5.15.2 headers for x64 macOS"
    INPUT_FILE = qt.h
    QTDIR = /Users/Shared/Qt/5.15.2-x64
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
    TOOLCHAIN = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
    CLANG_ARGV = -target x86_64-apple-darwin                           \
                 -x objective-c++                                      \
                 -isysroot $(SDK)                                      \
                 -I$(TOOLCHAIN)/usr/include/c++/v1                     \
                 -I$(TOOLCHAIN)/usr/lib/clang/11.0.3/include           \
                 -F$(QTDIR)/lib/                                       \
                 -I$(QTDIR)/lib/QtCore.framework/Headers               \
                 -I$(QTDIR)/lib/QtGui.framework/Headers                \
                 -I$(QTDIR)/lib/QtWidgets.framework/Headers            \
                 -I$(QTDIR)/lib/QtPrintSupport.framework/Headers       \
                 -I$(QTDIR)/lib/QtNetwork.framework/Headers            \
                 -I$(QTDIR)/lib/QtCLucene.framework/Headers            \
                 -I$(QTDIR)/lib/QtConcurrent.framework/Headers         \
                 -I$(QTDIR)/lib/QtDBus.framework/Headers               \
                 -I$(QTDIR)/lib/QtDesigner.framework/Headers           \
                 -I$(QTDIR)/lib/QtDesignerComponents.framework/Headers \
                 -I$(QTDIR)/lib/QtHelp.framework/Headers               \
                 -I$(QTDIR)/lib/QtOpenGL.framework/Headers             \
                 -I$(QTDIR)/lib/QtSql.framework/Headers                \
                 -I$(QTDIR)/lib/QtTest.framework/Headers               \
                 -I$(QTDIR)/lib/QtUiPlugin.framework/Headers           \
                 -I$(QTDIR)/lib/QtXml.framework/Headers
    
    include ../idaclang.mak
    

    For the Qt build we must explicitly add the Headers/ directory for each Qt framework to the include paths. Also pay special attention to the -F$(QTDIR)/lib/ option. This option is specific to macOS and informs libclang that the given directory contains .framework bundles. This is necessary for some include directives to be resolved correctly, e.g.:

    #include <QtCore/QtCoreDepends>
    

    Now we can build the TIL with:

    make -f qt_mac.mak
    

    We might want to check qt_mac.til.txt to see if some core Qt types were correctly added to the TIL:

    00000010 struct __cppobj QObject
    {
      QObject_vtbl *__vftable /*VFT*/;
      QScopedPointer<QObjectData> d_ptr;
    };
    //  0. 0000 0008 effalign(8) fda=0 bits=0100 QObject.__vftable QObject_vtbl *;
    //  1. 0008 0008 effalign(8) fda=0 bits=0000 QObject.d_ptr QScopedPointer<QObjectData>;
    //          0010 effalign(8) sda=0 bits=0080 QObject struct packalign=0
    
    00000030 struct __cppobj QWidget : QObject, QPaintDevice
    {
      QWidgetData *data;
    };
    //  0. 0000 0010 effalign(8) fda=0 bits=0020 QWidget.QObject QObject;
    //  1. 0010 0018 effalign(8) fda=0 bits=0020 QWidget.QPaintDevice QPaintDevice;
    //  2. 0028 0008 effalign(8) fda=0 bits=0000 QWidget.data QWidgetData *;
    //          0030 effalign(8) sda=0 bits=0080 QWidget struct packalign=0
    

    To build the Qt type library on Windows, use examples/qt/qt_win.mak:

    TIL_NAME = qt_win
    TIL_DESC = "Qt 5.15.2 headers for x64 Windows"
    INPUT_FILE = qt.h
    QTDIR = C:\Qt\5.15.2-x64
    CLANG_ARGV = -target x86_64-pc-win32                   \
                 -x c++                                    \
                 -I"$(QTDIR)\include"                      \
                 -I"$(QTDIR)\include\QtCore"               \
                 -I"$(QTDIR)\include\QtGui"                \
                 -I"$(QTDIR)\include\QtWidgets"            \
                 -I"$(QTDIR)\include\QtPrintSupport"       \
                 -I"$(QTDIR)\include\QtNetwork"            \
                 -I"$(QTDIR)\include\QtConcurrent"         \
                 -I"$(QTDIR)\include\QtDBus"               \
                 -I"$(QTDIR)\include\QtDesigner"           \
                 -I"$(QTDIR)\include\QtDesignerComponents" \
                 -I"$(QTDIR)\include\QtHelp"               \
                 -I"$(QTDIR)\include\QtOpenGL"             \
                 -I"$(QTDIR)\include\QtSql"                \
                 -I"$(QTDIR)\include\QtTest"               \
                 -I"$(QTDIR)\include\QtUiPlugin"           \
                 -I"$(QTDIR)\include\QtXml"
    
    include ../idaclang.mak
    

    And on Linux, use examples/qt/qt_linux.mak:

    TIL_NAME = qt_linux
    TIL_DESC = "Qt 5.15.2 headers for x64 Linux"
    INPUT_FILE = qt.h
    QTDIR = /usr/local/Qt/5.15.2-x64
    GCC_VERSION = $(shell expr `gcc -dumpversion | cut -f1 -d.`)
    CLANG_ARGV = -target x86_64-pc-linux                                      \
                 -x c++                                                       \
                 -I/usr/lib/gcc/x86_64-linux-gnu/$(GCC_VERSION)/include       \
                 -I/usr/local/include                                         \
                 -I/usr/lib/gcc/x86_64-linux-gnu/$(GCC_VERSION)/include-fixed \
                 -I/usr/include/x86_64-linux-gnu                              \
                 -I/usr/include                                               \
                 -I$(QTDIR)/include                                           \
                 -I$(QTDIR)/include/QtCore                                    \
                 -I$(QTDIR)/include/QtGui                                     \
                 -I$(QTDIR)/include/QtWidgets                                 \
                 -I$(QTDIR)/include/QtPrintSupport                            \
                 -I$(QTDIR)/include/QtNetwork                                 \
                 -I$(QTDIR)/include/QtConcurrent                              \
                 -I$(QTDIR)/include/QtDBus                                    \
                 -I$(QTDIR)/include/QtDesigner                                \
                 -I$(QTDIR)/include/QtDesignerComponents                      \
                 -I$(QTDIR)/include/QtHelp                                    \
                 -I$(QTDIR)/include/QtOpenGL                                  \
                 -I$(QTDIR)/include/QtSql                                     \
                 -I$(QTDIR)/include/QtTest                                    \
                 -I$(QTDIR)/include/QtUiPlugin                                \
                 -I$(QTDIR)/include/QtXml
    
    include ../idaclang.mak
    

    Linux Kernel

    This section demonstrates how to build a type library from the Linux Kernel headers.

    First you must ensure that you have the kernel headers installed on your system:

    apt-get install linux-headers-`uname -r`
    

    As well as the tools necessary to build against them:

    apt-get install build-essential
    

    The tricky part about building a TIL for the Linux kernel is configuring the correct include paths. The kernel header directory structure is not consistent between different distros, so there is no one configuration that works on all machines. We’ve found that the easiest way to discover the correct kernel header paths on your system is to build a trivial Linux kernel module, then copy the paths used within the kernel build system.

    Consider examples/linux/lkm_example/lkm_example.c from examples.zip:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Robert W. Oliver II");
    MODULE_DESCRIPTION("A simple example Linux module.");
    MODULE_VERSION("0.01");
    
    static int __init lkm_example_init(void)
    {
      printk(KERN_INFO "Hello, world!\n");
      return 0;
    }
    
    static void __exit lkm_example_exit(void)
    {
      printk(KERN_INFO "Goodbye, world\n");
    }
    
    module_init(lkm_example_init);
    module_exit(lkm_example_exit);
    

    This is a simple kernel module taken from this tutorial. It can be built with:

    cd lkm_example/
    make
    

    After building, you may notice that the kernel build system added many hidden files to the build directory. One of them being .lkm_example.o.cmd. This file contains the gcc command used to compile the kernel module source file. It will contain many important compiler switches that we will need to copy over to idaclang, including the proper include paths:

    -I./arch/x86/include -I./arch/x86/include/generated  -I./include -I./arch/x86/include/uapi
    

    These paths are relative to the directory:

    /usr/src/linux-headers-$(uname -r)
    

    We will need to copy them to idaclang as absolute paths. For example, consider examples/linux/linux_kernel_5_11.mak:

    TIL_NAME = linux_kernel_5_11
    TIL_DESC = "Linux kernel headers for 5.11.0-41-generic (Ubuntu 20.04)"
    INPUT_FILE = linux.h
    KERNEL_HEADERS = /usr/src/linux-headers-5.11.0-41-generic
    CLANG_ARGV = -target x86_64-pc-linux-gnu                               \
                 -nostdinc                                                 \
                 -isystem /usr/lib/gcc/x86_64-linux-gnu/9/include          \
                 -I$(KERNEL_HEADERS)/arch/x86/include                      \
                 -I$(KERNEL_HEADERS)/arch/x86/include/generated            \
                 -I$(KERNEL_HEADERS)/include                               \
                 -I$(KERNEL_HEADERS)/arch/x86/include/uapi                 \
                 -I$(KERNEL_HEADERS)/arch/x86/include/generated/uapi       \
                 -I$(KERNEL_HEADERS)/include/uapi                          \
                 -I$(KERNEL_HEADERS)/include/generated/uapi                \
                 -include $(KERNEL_HEADERS)/include/linux/compiler_types.h \
                 -D__KERNEL__                                              \
                 -O2                                                       \
                 -mfentry                                                  \
                 -DCC_USING_FENTRY                                         \
                 -Wno-gnu-variable-sized-type-not-at-end
    
    include ../idaclang.mak
    

    This is a makefile we used to successfully generate a Linux kernel TIL on Ubuntu 20.04. The input file linux.h contains include directives for a few interesting kernel header files:

    #include <linux/kconfig.h>
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/acpi.h>
    #include <linux/fs.h>
    #include <linux/efi.h>
    #include <linux/bpf.h>
    #include <linux/usb.h>
    #include <linux/kmod.h>
    #include <linux/device.h>
    #include <linux/blkdev.h>
    

    It is not an exhaustive list. You can easily make the TIL more robust by adding more headers to linux.h, but for demonstration purposes this is enough to get the ball rolling.

    Inspecting the dump of the til we can see some important kernel types have already been added:

    struct kobject
    {
      const char *name;
      list_head entry;
      kobject *parent;
      kset *kset;
      kobj_type *ktype;
      kernfs_node *sd;
      kref kref;
      unsigned __int32 state_initialized : 1;
      unsigned __int32 state_in_sysfs : 1;
      unsigned __int32 state_add_uevent_sent : 1;
      unsigned __int32 state_remove_uevent_sent : 1;
      unsigned __int32 uevent_suppress : 1;
    };
    
    struct kset
    {
      list_head list;
      spinlock_t list_lock;
      kobject kobj;
      const kset_uevent_ops *uevent_ops;
    };
    

    On Debian Linux the configuration is slightly different. The kernel header package tends to be split across multiple root directories. We must let idaclang know about both of them. See examples/linux/linux_kernel_4_9.mak:

    TIL_NAME = linux_kernel_4_9
    TIL_DESC = "Linux kernel headers for 4.9.0-16-amd64 (Debian 9.13)"
    INPUT_FILE = linux.h
    KERNEL_HEADERS1 = /usr/src/linux-headers-4.9.0-16-common
    KERNEL_HEADERS2 = /usr/src/linux-headers-4.9.0-16-amd64
    CLANG_ARGV = -target x86_64-pc-linux-gnu                          \
                 -nostdinc                                            \
                 -isystem /usr/lib/gcc/x86_64-linux-gnu/6/include     \
                 -I$(KERNEL_HEADERS1)/arch/x86/include                \
                 -I$(KERNEL_HEADERS1)/include                         \
                 -I$(KERNEL_HEADERS1)/arch/x86/include/uapi           \
                 -I$(KERNEL_HEADERS1)/include/uapi                    \
                 -I$(KERNEL_HEADERS2)/arch/x86/include/generated/uapi \
                 -I$(KERNEL_HEADERS2)/arch/x86/include/generated      \
                 -I$(KERNEL_HEADERS2)/include                         \
                 -I$(KERNEL_HEADERS2)/include/generated/uapi          \
                 -D__KERNEL__                                         \
                 -O2                                                  \
                 -mfentry                                             \
                 -DCC_USING_FENTRY                                    \
                 -Wno-gnu-variable-sized-type-not-at-end
    
    include ../idaclang.mak
    

    We used this makefile to generate a Linux kernel TIL on Debian 9.13. It should produce almost the same result as the Ubuntu example discussed above.

    XNU Kernel

    The XNU kernel for macOS and iOS relies heavily on C++ object-oriented development via the IOKit framework. The goal of this section is to create a type library for the XNU kernel, focusing specifically on the C++ type information in the IOKit headers.

    Apple publishes the kernel SDK via Kernel.framework in the macOS SDK:

    MacOSX12.0.sdk/System/Library/Frameworks/Kernel.framework
    

    The IOKit C++ headers are usually present at:

    MacOSX12.0.sdk/System/Library/Frameworks/Kernel.framework/Headers/IOKit
    

    See examples/xnu/xnu.h in examples.zip, which includes some of the important header files from the IOKit/ directory. We’ll use this file to generate our type library.

    Now consider examples/xnu/xnu_x64.mak:

    TIL_NAME = xnu_x64
    TIL_DESC = "Darwin Kernel Headers for x64 macOS"
    INPUT_FILE = xnu.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk
    CLANG_ARGV = -target x86_64-apple-macos12.0                              \
                 -x c++                                                      \
                 -isysroot $(SDK)                                            \
                 -I$(SDK)/System/Library/Frameworks/Kernel.framework/Headers \
                 -nostdinc                                                   \
                 -std=gnu++1z                                                \
                 -stdlib=libc++                                              \
                 -mkernel                                                    \
                 -DKERNEL                                                    \
                 -DAPPLE                                                     \
                 -DNeXT
    
    include ../idaclang.mak
    

    We can use this makefile to generate an XNU TIL:

    make -f xnu_x64.mak
    

    Now let’s have a look at the OSMetaClassBase class in the text dump xnu_x64.til.txt:

    00000008 struct __cppobj OSMetaClassBase
    {
      OSMetaClassBase_vtbl *__vftable /*VFT*/;
    };
    //  0. 0000 0008 effalign(8) fda=0 bits=0100 OSMetaClassBase.__vftable OSMetaClassBase_vtbl *;
    //          0008 effalign(8) sda=0 bits=0080 OSMetaClassBase struct packalign=0
    

    More specifically the OSMetaClassBase_vtbl type, which has some peculiar members at the end of it:

    00000088 struct /*VFT*/ OSMetaClassBase_vtbl
    {
      ...
      void (__cdecl *_RESERVEDOSMetaClassBase4)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase5)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase6)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase7)(OSMetaClassBase *__hidden this);
    }
    

    Apple added several dummy virtual methods to this class so that they can add new methods without breaking binary compatibility. This is a common paradigm in the XNU kernel source, but we must be very careful with it. From the original source code in OSMetaClass.h, we can see that it is heavily platform dependent:

    #if APPLE_KEXT_VTABLE_PADDING
    // Virtual Padding
    #if defined(__arm64__) || defined(__arm__)
        virtual void _RESERVEDOSMetaClassBase0();
        virtual void _RESERVEDOSMetaClassBase1();
        virtual void _RESERVEDOSMetaClassBase2();
        virtual void _RESERVEDOSMetaClassBase3();
    #endif /* defined(__arm64__) || defined(__arm__) */
        virtual void _RESERVEDOSMetaClassBase4();
        virtual void _RESERVEDOSMetaClassBase5();
        virtual void _RESERVEDOSMetaClassBase6();
        virtual void _RESERVEDOSMetaClassBase7();
    #endif /* APPLE_KEXT_VTABLE_PADDING */
    

    Note that the APPLE_KEXT_VTABLE_PADDING macro is not defined for iOS builds. The iOS kernel does not pad its vtables in order to conserve memory, so these extra vtable members will only be present for macOS builds. Moreover, from the above source we can see that arm64 macOS uses more vtable padding than on x64.

    Why is this a big deal? Because almost every single important C++ class in IOKit inherits from OSMetaClassBase. Thus if the vtable type for OSMetaClassBase is not 100% correct, all of our vtable types will be useless. We have no choice but to build separate TILs for each of x64 macOS, arm64 macOS, and iOS, to ensure that we’re working with precise vtables.

    See examples/xnu/xnu_m1.mak, which builds the XNU TIL for arm64 macOS:

    TIL_NAME = xnu_m1
    TIL_DESC = "Darwin Kernel Headers for arm64 macOS"
    INPUT_FILE = xnu.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk
    CLANG_ARGV = -target arm64e-apple-macos12.0                              \
                 -x c++                                                      \
                 -isysroot $(SDK)                                            \
                 -I$(SDK)/System/Library/Frameworks/Kernel.framework/Headers \
                 -nostdinc                                                   \
                 -std=gnu++1z                                                \
                 -stdlib=libc++                                              \
                 -mkernel                                                    \
                 -DKERNEL                                                    \
                 -DAPPLE                                                     \
                 -DNeXT
    
    include ../idaclang.mak
    

    From the text dump we can see that OSMetaClassBase_vtbl is a bit larger, as expected:

    000000A8 struct /*VFT*/ OSMetaClassBase_vtbl
    {
      ...
      void (__cdecl *_RESERVEDOSMetaClassBase0)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase1)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase2)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase3)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase4)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase5)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase6)(OSMetaClassBase *__hidden this);
      void (__cdecl *_RESERVEDOSMetaClassBase7)(OSMetaClassBase *__hidden this);
    }
    

    To build the TIL for iOS, use xnu_ios.mak:

    TIL_NAME = xnu_ios
    TIL_DESC = "Darwin Kernel Headers for arm64e iOS"
    INPUT_FILE = xnu.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk
    CLANG_ARGV = -target arm64e-apple-ios15-macabi                           \
                 -x c++                                                      \
                 -isysroot $(SDK)                                            \
                 -I$(SDK)/System/Library/Frameworks/Kernel.framework/Headers \
                 -nostdinc                                                   \
                 -std=gnu++1z                                                \
                 -stdlib=libc++                                              \
                 -mkernel                                                    \
                 -DKERNEL                                                    \
                 -DAPPLE                                                     \
                 -DNeXT
    
    include ../idaclang.mak
    

    Which yields smaller vtables without any padding, as expected:

    00000068 struct /*VFT*/ OSMetaClassBase_vtbl
    

    Hopefully this section demonstrates how easy it is to get in trouble when building type libraries from C++ source, and how the precision of idaclang can help deal with it.

    MFC

    The makefile examples/mfc/mfc.mak from examples.zip demonstrates how to build a type library for the Microsoft Foundation Class Library (MFC) on Windows:

    TIL_NAME = mfc
    TIL_DESC = "Microsoft Foundation Class library for x86"
    INPUT_FILE = mfc.h
    CLANG_ARGV = -x c++ -target i386-pc-win32
    include ../idaclang.mak
    

    This makefile instructs idaclang to parse examples/mfc/mfc.h, which contains some essential MFC headers:

    #include <afxwin.h>         // MFC core and standard components
    #include <afxext.h>         // MFC extensions
    #include <afxdisp.h>        // MFC OLE automation classes
    #include <afxcmn.h>         // MFC support for Windows Common Controls
    #include <atlbase.h>
    #include <atlcom.h>
    

    This is enough to generate a solid type library for MFC. You can build it with:

    make -f mfc.mak
    

    From the dump of the til in mfc.til.txt, it appears some essential types are successfully created:

    00000004 #pragma pack(push, 8)
    struct __cppobj CObject
    {
      CObject_vtbl *__vftable /*VFT*/;
    };
    #pragma pack(pop)
    //  0. 0000 0004 effalign(4) fda=0 bits=0100 CObject.__vftable CObject_vtbl *;
    //          0004 effalign(4) sda=0 bits=0080 CObject struct packalign=4
    
    00000014 #pragma pack(push, 8)
    struct __cppobj CFile : CObject
    {
      HANDLE m_hFile;
      BOOL m_bCloseOnDelete;
      CString m_strFileName;
      ATL::CAtlTransactionManager *m_pTM;
    };
    #pragma pack(pop)
    //  0. 0000 0004 effalign(4) fda=0 bits=0020 CFile.CObject CObject;
    //  1. 0004 0004 effalign(4) fda=0 bits=0000 CFile.m_hFile HANDLE;
    //  2. 0008 0004 effalign(4) fda=0 bits=0000 CFile.m_bCloseOnDelete BOOL;
    //  3. 000C 0004 effalign(4) fda=0 bits=0000 CFile.m_strFileName CString;
    //  4. 0010 0004 effalign(4) fda=0 bits=0000 CFile.m_pTM ATL::CAtlTransactionManager *;
    //          0014 effalign(4) sda=0 bits=0080 CFile struct packalign=4
    

    There are many more headers that could be included in the build, so don’t hesitate to add more headers to mfc.h if you think they might contain relevant types.

    macOS/iOS SDK

    One advantage of using libclang is that we can parse the complex Objective-C syntax used in macOS and iOS Frameworks. Thus we can create type libraries from Apple’s SDKs without much issue.

    See examples/macsdk/macos12_sdk.mak in examples.zip, which creates a TIL from the macOS12 SDK:

    TIL_NAME = macos12_sdk
    TIL_DESC = "MacOSX12.0.sdk headers for x64"
    INPUT_FILE = macos12_sdk.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk
    TOOLCHAIN = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain
    CLANG_ARGV = -target x86_64-apple-darwin                 \
                 -x objective-c++                            \
                 -isysroot $(SDK)                            \
                 -I$(TOOLCHAIN)/usr/lib/clang/13.0.0/include
    
    include ../idaclang.mak
    

    The input file used here is examples/macsdk/macos12_sdk.h, which simply includes the umbrella header from every Framework present in the SDK:

    #include <CoreFoundation/CoreFoundation.h>
    #include <CoreServices/CoreServices.h>
    #include <CoreText/CoreText.h>
    // ... etc
    #include <WidgetKit/WidgetKit.h>
    #include <SystemExtensions/SystemExtensions.h>
    #include <Virtualization/Virtualization.h>
    

    The Frameworks that have an umbrella header can be easily identified by their module.modulemap file. For example:

    $ cat MacOSX12.0.sdk/System/Library/Frameworks/Network.framework/Modules/module.modulemap
    framework module Network [system] [extern_c] {
        umbrella header "Network.h"
        export *
    }
    

    Some Frameworks don’t have an umbrella header and they were left out, but this still gives us plenty of useful type info. From macos12_sdk.til.txt we can see that many Objective-C types were successfully parsed:

    00000030 struct NSCalendarDate
    {
      NSDate super;
      NSUInteger refCount;
      NSTimeInterval _timeIntervalSinceReferenceDate;
      NSTimeZone *_timeZone;
      NSString *_formatString;
      void *_reserved;
    };
    //  0. 0000 0008 effalign(8) fda=0 bits=0000 NSCalendarDate.super NSDate;
    //  1. 0008 0008 effalign(8) fda=0 bits=0000 NSCalendarDate.refCount NSUInteger;
    //  2. 0010 0008 effalign(8) fda=0 bits=0000 NSCalendarDate._timeIntervalSinceReferenceDate NSTimeInterval;
    //  3. 0018 0008 effalign(8) fda=0 bits=0000 NSCalendarDate._timeZone NSTimeZone *;
    //  4. 0020 0008 effalign(8) fda=0 bits=0000 NSCalendarDate._formatString NSString *;
    //  5. 0028 0008 effalign(8) fda=0 bits=0000 NSCalendarDate._reserved void *;
    //          0030 effalign(8) sda=0 bits=0000 NSCalendarDate struct packalign=0
    

    Also the prototypes for many Objective-C methods were added to the symbol table:

    NWHostEndpoint *__cdecl +[NWHostEndpoint endpointWithHostname:port:](id, SEL, NSString *hostname, NSString *port);
    

    Having such detailed and accurate prototypes for Objective-C Frameworks is particularly useful when analyzing dyld_shared_cache files. The type information parsed in the source headers is much more detailed than the Objective-C type information embedded in the module binaries.

    Note that you can build the same TIL for Apple Silicon by simply changing the -target argument to:

    -target arm64-apple-darwin
    

    Building a TIL for the iPhoneOS.sdk is just as easy. See ios15_sdk.mak and ios15_sdk.h:

    TIL_NAME = ios15_sdk
    TIL_DESC = "iPhoneOS15.0.sdk headers for arm64"
    INPUT_FILE = ios15_sdk.h
    SDK = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.0.sdk
    TOOLCHAIN = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain
    CLANG_ARGV = -target arm64-apple-darwin                  \
                 -x objective-c++                            \
                 -isysroot $(SDK)                            \
                 -I$(TOOLCHAIN)/usr/lib/clang/13.0.0/include
    
    include ../idaclang.mak
    

    TILIB

    TILIB is a utility to create custom type libraries for IDA Pro. Since IDA 9.1, TILIB is shipped with IDA, in the tools folder within the main IDA installation directory.

    This small utility creates type library (til) files for IDA Pro. Its functionality overlaps with “Parse C header file…” from IDA Pro. However, this utility is easier to use and provides more control over the output. Also, it can handle the preprocessor symbols, while the built-in command ignores them.

    The utility takes a C header file and extracts all type information from it. The extracted type information is stored in an internal format as a type library file. Type library files can be loaded and used in IDA Pro by opening the Type Library Window and pressing Insert.

    TILIB support only C header files. C++ files (classes, templates, etc) are not supported, but some popular C++ keywords are recognized and properly handled. For example, TILIB knows about the inline keyword and properly skips the definition of the inline function.

    Installation

    1. Just copy the tilib executable file into the IDA Pro directory.

    If you prefer to keep it in another directory, you will need to specify the location of the ida.hlp file using the NLSPATH variable:

    set NLSPATH=c:\program files\ida
    

    Please note that you do not need to define this variable if you just copy the tilib executable file to the IDA Pro directory.

    Usage

    If started without parameters, the utility displays a short explanation. Below are some command line samples.

    Parse a header file and create a new type library:

    tilib -c -hinput_header_file output_til_file
    
    • -c means to create a new type library
    • -h denotes the name of the input file to read

    If you need to parse multiple files into one type library, you may create a text file with #include directives and specify it as the input.

    TILIB can handle input files for Visual Studio, Borland, GCC out of the box. Please check the configuration files for them in the archive (*.cfg).

    If you need to fine-tune TILIB for another compiler (or unusual compiler settings), feel free to copy the provided configuration files and modify them.

    TILIB is not very good at error handling and some error messages may be quite unhelpful (e.g. syntax error). To alleviate this problem, use the -z switch. If this switch is specified, TILIB will create a .i file with the preprocessed contents. All recognized type names are prepended with @, like this: @my_type_name.

    In some urgent cases, the -e switch may be used to ignore any parsing errors. Please note that the problematic type definitions will be skipped in this mode. This switch may be used together with the -R switch to allow type redeclarations.

    If your input file uses another header file (e.g. windows.h), you may opt to use the vc6win.til file instead of parsing it again. For that, just use the -b switch and specify vc6win.til as the base til. TILIB will load the contents of the specified file into the memory and parse the input file. All definitions from windows.h, including the preprocessor definitions, will be avaible:

    tilib -c -hinput_header_file -bbase_til_file output_til_file
    

    TILIB can also be used to list the contents of a til file:

    tilib -l input_til_file
    

    If the -c switch is not specified, TILIB uses the specified til file as the input and as the output file. This mode allows you to modify existing til files.

    How to create preprocessor macro enums?

    TILIB can also convert selected preprocessor macros into enums. If the input file has lines like the following:

    #define MY_SYMBOL_ONE   1
    #define MY_SYMBOL_TWO   2
    #define MY_SYMBOL_THREE 3
    

    they can be converted to enum and used in IDA Pro. This is a three step process. At the first step, we create a .mac file (note the -M switch):

    tilib -c -Moutput_mac_file -hinput_header_file output_til_file
    

    The second step is to edit the generated MAC file: to remove undesired macro definitions and regroup macros if necessary. Macro group names start at the beginning of a line, symbol definitions are indented:

    MY_SYMBOL
      MY_SYMBOL_ONE   1
      MY_SYMBOL_TWO   2
      MY_SYMBOL_THREE 3
    

    Feel free to edit the macro file to your taste.

    It is also possible to describe the changes to the macro group names and rerun TILIB to regenerate the macro file. There are two ways to describe the changes:

    1. Through the -g[nb]X:Y command-line options. If the regex X matches the macro name (n) or the macro body (b), the group is set to Y. For example:

      tilib -gnFOO_:ERRORS -gbERR:ERRORS -c -Moutput_mac_file -hinput_header_file output_til_file
      

      with this header file:

      #define ERR(x)  x
      #define FOO_OK  0
      #define FOO_BAD 1
      #define BAR_BAD ERR(-1)
      

      produces this macro file:

      ERRORS
      FOO_OK 0
      FOO_BAD 1
      BAR_BAD -1
      

      Using an empty regex will prevent the group from being created (useful when you want to leave a group name available from a base til).

    2. Adding a tilib-specific #pragma to the header files:

      #pragma tilib-group ERRNO
      // all macros before resetting tilib-group will be added to the ERRNO group
      #include <errno.h>
      #pragma tilib-group
      
    3. The third and last step is to specify the macro file as the input for TILIB:

      tilib -c -minput_mac_file -hinput_header_file output_til_file
      

    The generated til file will have all normal type definitions and all macro definitions from the .mac file.

    List of supported keywords

    Below is the list of supported keywords. If your header files happen to have an unsupported keyword, you take one of the following actions:

    • edit the input files and remove the unsupported keywords
    • use #define to replace or hide the unsupported keywords
    • use the -D command line switch for the same purpose
    __cdecl     do       goto      return     protected      __ptr32
    __pascal    if       long      signed     __unaligned    __ptr64
    __stdcall   _es      cpp_this  sizeof     __userpurge    __restrict
    __fastcall  _cs      void      static     _BYTE          __hidden
    __thiscall  _ss      break     struct     _WORD          __array_ptr
    __usercall  _ds      catch     switch     _DWORD         __struct_ptr
    __export    asm      class     default    _QWORD         __return_ptr
    __import    for      const     mutable    _OWORD
    __thread    int      float     private    _TBYTE
    __declspec  new      short     typedef    _UNKNOWN
    __far       try      throw     virtual    _BOOL1
    __near      auto     union     continue   _BOOL2
    __huge      bool     while     register   _BOOL4
    __int8      case     double    template   __spoils
    __int16     char     extern    unsigned   __attribute__
    __int32     else     friend    volatile   __pure
    __int64     enum     inline    interrupt  __noreturn
    __int128    flat     public    namespace  __cppobj
    

    What’s next?

    Learn more about TILIB utility and check Igor’s tip of the week about creating custom libraries.

    Configuration

    Configuration files

    The configuration files are searched first in %IDADIR%\cfg, then in %IDAUSR%\cfg.

    See documentation about the IDAUSR environment variable.

    In the configuration files, you can use C,C++ style comments and include files. If no file is found, IDA uses default values. IDA uses the following configuration files:

    • IDA.CFG - general config file
    • IDAGUI.CFG - graphics mode interface config file
    • IDAPYTHON.CFG - configuration file for IDAPython

    {% hint style=“info” %} The IDA text UI and its configuration file (IDATUI.CFG) were removed starting with IDA 9.2. {% endhint %}

    Command line switches

    IDA recognizes the following command line switches:

    SwitchEffect
    -adisable auto analysis. (-a- enables it)
    -Aautonomous mode. IDA will not display dialog boxes. Designed to be used together with -S switch.
    -b####loading address, a hexadecimal number, in paragraphs (a paragraph is 16 bytes)
    -Bbatch mode. IDA will generate .IDB and .ASM files automatically
    -cdisassemble a new file (delete the old database)
    -C####set compiler in format name:abi
    -ddirectiveA configuration directive which must be processed at the first pass. Example: -dVPAGESIZE=8192
    -DdirectiveA configuration directive which must be processed at the second pass.
    -fdisable FPP instructions (IBM PC only)
    -hhelp screen -i#### program entry point (hex)
    -I#set IDA as just-in-time debugger (0 to disable and 1 to enable)
    -L####name of the log file
    -Mdisable mouse (text only)
    -O####options to pass to plugins. This switch is not available in the IDA Home edition.
    -o####specify the output database (implies -c)
    -p####processor type
    -P+compress database (create zipped idb)
    -Ppack database (create unzipped idb)
    -P-do not pack database (not recommended, see the Abort command)
    -r###immediately run the built-in debugger format of this switch is explained here
    -Rload MS Windows exe file resources
    -S###Execute a script file when the database is opened
    -T###interpret the input file as the specified file type The file type is specified as a prefix of a file type visible in the ‘load file’ dialog box To specify archive member put it after the colon char, for example:
    -TZIP:classes.dex You can specify any nested paths:
    -T| <ftype>[:<member>{:<ftype>:<member>}[:<ftype>]] IDA does not display the “Load file” dialog in this case
    -tcreate an empty database.
    -W###specify MS Windows directory
    -xdo not create segmentation (used in pair with Dump database command) this switch affects EXE and COM format files only.
    -zturn on debugging
    -?this screen (works for the text version)
    ?this screen (works for the text version)
    -hthis screen (works for the text version)
    -Hthis screen (works for the text version)
    --helpthis screen (works for the text version)

    Debugging flags

    The following bitfield can be used with the -z directive:

    00000001 drefs
    00000002 offsets
    00000004 flirt
    00000008 idp module
    00000010 ldr module
    00000020 plugin module
    00000040 ids files
    00000080 config file
    00000100 check heap
    00000200 licensing
    00000400 demangler
    00000800 queue
    00001000 rollback
    00002000 already data or code
    00004000 type system
    00008000 show all notifications
    00010000 debugger
    00020000 [dbg\_appcall](1572.md)
    00040000 source-level debugger
    00080000 accessibility
    00100000 network
    00200000 full stack analysis (simplex method)
    00400000 handling of debug info (e.g. pdb, dwarf)
    00800000 lumin
    

    Batch mode

    It is possible to run IDA in so-called “batch mode”, using the following the -B switch:

        ida -B input-file
    

    which is equivalent to:

        ida -c -A -Sanalysis.idc input-file
    

    (For more information, please see the analysis.idc file in the IDC subdirectory.)

    A couple notes:

    • regular plugins are not automatically loaded in batch mode because the analysis.idc file quits and the kernel has no chance to load them.
    • Although the GUI version of IDA is perfectly of running batch scripts, we recommend using the “idalib” Python module for this task as it uses fewer system resources.

    Executing a script

    The script file extension (.idc, .py) is used to determine which interpreter will be used to run the script.

    It is possible to pass command line arguments after the script name. For example: -S"myscript.py argument1 \\"argument 2\\" argument3"

    The passed parameters are stored in the “ARGV” global IDC variable, which means:

    • For IDC scripts:
      • Use ARGV.count to determine the number of arguments.
      • The first argument, ARGV[0], contains the script name.
    • For Python scripts:
      • you can import the idc compatibility layer (import idc), and then
      • access the idc.ARGV array

    NOTE: The -S switch is not available in the IDA Home edition.

    UI/Fonts/Themes

    Coming soon!

    Shortcuts

    This doc provide a quick references to common default shortcuts to streamline your workflow in IDA. You can configure and customize shortcuts via Options → Shortcuts….


    ActionShortcut
    Jump to OperandEnter
    Jump in a New WindowAlt+Enter
    Jump to Previous PositionEsc
    Jump to Next PositionCtrl+Enter
    Jump to AddressG
    Jump by NameCtrl+L
    Jump to FunctionCtrl+P
    Open Cross-References WindowX
    View PseudocodeTab
    Jump to SegmentCtrl+S
    Jump to Segment RegisterCtrl+G
    Jump to ProblemQ
    Jump to Entry PointCtrl+E

    Bookmarks

    ActionShortcut
    Mark PositionAlt+M
    Jump to BookmarkCtrl+M
    Open Bookmarks WindowCtrl+Shift+M

    Search

    ActionShortcut
    Search TextAlt+T
    Search Next TextCtrl+T
    Search Sequence of BytesAlt+B
    Search Immediate ValueAlt+I
    Search Next Immediate ValueCtrl+I
    Search Next CodeAlt+C
    Search Next DataCtrl+D

    Debugging

    ActionShortcut
    Add BreakpointF2
    Start ProcessF9
    Terminate ProcessCtrl+F2
    Step IntoF7
    Step OverF8
    Run Until ReturnCtrl+F7
    Breakpoint ListCtrl+Alt+B
    View Stack TraceCtrl+Alt+S

    Operands

    ActionShortcut
    Change to HexadecimalQ
    Change to DecimalH
    Change to BinaryB
    Change to CharacterR
    Change Enum MemberCtrl+O
    Change to Offset (data segment)O
    Change to Offset (in any segment)Alt+R
    Change to Offset (user-defined)Ctrl+R
    Select Union MemberT
    Change to Stack VariableK
    Bitwise Negate~
    Change Sign_

    Function Management

    ActionShortcut
    Create FunctionP
    Edit FunctionAlt+P
    Set Function EndE
    Edit Stack VariablesCtrl+K
    Set TypeY
    Open Stack Variables WindowCtrl+K

    Annotate

    ActionShortcut
    Annotate (Rename)N
    Enter Repeatable Comment;
    Enter Comment:
    Insert Line BeforeIns
    Insert Line AfterShift+Ins
    Enter Anterior LinesAlt+Q
    Enter Posterior LinesAlt+A

    Open Subviews

    SubviewShortcut
    Local TypesShift+F1
    FunctionsShift+F3
    NamesShift+F4
    SignaturesShift+F5
    SegmentsShift+F7
    Segment RegistersShift+F8
    StructuresShift+F9
    Type LibrariesShift+F11
    StringsShift+F12

    Miscellaneous

    ActionShortcut
    UndoCtrl+Z
    RedoCtrl+Shift+Z
    Begin SelectionAlt+L
    Open Calculator?
    SaveCtrl+S
    ExitAlt+X

    Get the handy shortcuts cheatsheet

    You can download the cheatsheet here: {% file src=“assets/ida_cheatsheet.pdf” %}

    Customizing IDA

    IDA offers a MDI tabbed interface. Here are a few tips to customize it.

    {% file src=“assets/customize.pdf” %}

    CSS-based styling Tutorial

    Before IDA 7.3

    IDA used to store colors in the registry:

    • HKEY_CURRENT_USER\Software\Hex-Rays\IDA on Windows,
    • ~/.idapro/ida.reg on Linux & Mac OSX.

    This was somewhat inconvenient because color values were stored in binary format, and hard to move from computer to computer.

    In addition, this only lets users style a small subset of the widgets that compose IDA, which can be insufficient.

    IDA 7.3: CSS-based styling

    Since we had to introduce yet another set of new colors in 7.3, we took the opportunity to moved away from the registry-stored, binary-only approach, to a CSS-based approach.

    This gives us the following advantages:

    • CSS is a well-known format
    • CSS is human-readable
    • Qt understands CSS out-of-the-box (parts of it, at least)
    • Using CSS will therefore let us style not only the custom IDA widgets, but all widgets

    This last point is important, because many users have been asking for the ability to style IDA more thoroughly, rather than just styling a few custom widgets (such as the disassembly views, navigation band, …)

    How IDA 7.3 CSS-based styling works

    IDA 7.3 ships with 2 themes by default:

    • default
    • dark

    Those themes are located in $IDA_INSTALL/themes/:

    aundro@flatiron:~/IDA-7.3$ tree themes/
    themes/
    ├── _base
    │   └── theme.css
    ├── dark
    │   ├── icons
    │   │   ├── expand.png
    │   │   └── spacer.png
    │   └── theme.css
    └── default
        └── theme.css
    
    4 directories, 5 files
    aundro@flatiron:~/IDA-7.3$
    

    Notice that, in addition to dark and default directories, you can also spot an additional _base directory.

    The _base theme holds all the CSS directives that are required for IDA to work correctly, and therefore it must be “imported” by other themes (using the IDA-specific @importtheme directive) before any other styling directives are declared.

    For example, here are the first 3 lines of $IDA_RELEASE/themes/dark/theme.css:

    aundro@flatiron:~/IDA-7.3$ head -n 3 themes/default/theme.css
    
    @importtheme "_base";
    
    aundro@flatiron:~/IDA-7.3$
    

    What happens when colors are modified through the “Colors” dialog?

    When you change colors in the ‘Colors’ dialog, IDA will not modify the files that are present in $IDA_INSTALL/themes/.

    Instead, IDA will create a file in IDA’s user directory, holding what we will refer to as “user overrides”.

    Let’s assume the user:

    • switched to the dark theme,
    • modified the Instruction text color to red.
    • clicked ‘OK’

    IDA will then have created the file:

    • ~/.idapro/themes/dark/user.css
    • %APPDATA%\Hex-Rays\IDA Pro\themes\dark\user.css on Windows

    with the following contents:

    aundro@flatiron:~/.idapro$ tree themes
    themes
    └── dark
        └── user.css
    
    1 directory, 1 file
    aundro@flatiron:~/.idapro$
    aundro@flatiron:~/.idapro$ cat themes/dark/user.css
    /* NOTE: This is an autogenerated file; please do not edit. */
    
    CustomIDAMemo
    {
        qproperty-line-fg-insn: red;
    }
    aundro@flatiron:~/.idapro$
    

    In other words, the themes that are shipped with IDA are never modified, but instead a “user override” file is created, that will contain whatever customization the user made to the theme.

    Importing/Exporting themes customization

    IDA 7.3 removed the Import/Export feature from its Colors dialog, because an equivalent is already automatically present in the form of those “user overrides” files, which can be found in:

    • %APPDATA%\Hex-Rays\IDA Pro\themes\*\user.css on Windows,
    • ~/.idapro/themes/*/user.css on Linux and Mac OSX.

    In order to re-use customizations across different computers, it is enough to just copy those user.css file(s).

    Debugging style sheets lookup

    In case IDA misbehaves, and appears to ignore some styling directives, it’s possible to launch IDA with the following command-line flag to debug themes loading: ida -z1000000

    In IDA’s Output window, you should spot something along the lines of this:

    Themes: Trying file "/home/aundro/IDA-7.3/themes/dark/theme.css" ... found.
    Themes: Trying file "/home/aundro/.idapro/themes/dark/theme.css" ... not found.
    Themes: Found @importtheme (/home/aundro/IDA-7.3/themes/dark/theme.css:6)
    Themes: Trying file "/home/aundro/IDA-7.3/themes/_base/theme.css" ... found.
    Themes: Trying file "/home/aundro/.idapro/themes/_base/theme.css" ... not found.
    Themes: Trying file "/home/aundro/IDA-7.3/themes/dark/user.css" ... not found.
    Themes: Trying file "/home/aundro/.idapro/themes/dark/user.css" ... found.
    

    First of all, IDA tries to load the desired (dark) theme contents (that corresponds to the first 5 lines):

    • IDA looked for $IDA_INSTALL/themes/dark/theme.css, and found it
    • IDA also looked for ~/.idapro/themes/dark/theme.css! (we’ll discuss this in the following chapter)
    • IDA spotted that the dark theme imports the _base theme, and loaded contents from that one as well.

    Then, IDA tries to load user overrides for the dark theme (corresponds to the 2 final lines):

    • IDA looked for $IDA_INSTALL/themes/dark/user.css, but didn’t find it (this is, in fact, pretty much unnecessary, since user overrides should never be in IDA’s installation directory. We’ll eventually get rid of this.)
    • IDA looked for in ~/.idapro/themes/dark/user.css, and found it.

    Adding themes

    As was mentioned in the previous chapter, IDA also looks for themes contents in IDA’s user directory:

    • %APPDATA%\Hex-Rays\IDA Pro\themes on Windows,
    • ~/.idapro/themes on Linux & Mac OSX

    That means it’s possible to add your own themes there, without having to modify the (possibly read-only) $IDA_INSTALL directory.

    In addition, putting additional themes in IDA’s user directory means that new version of IDA will be able to pick them up automatically.

    Example new theme

    Let’s say you want to create a new theme, called blue.

    You should therefore create the following CSS file:

    • ~/.idapro/themes/blue/theme.css

    …in which you can override anything you want, after importing the _base theme.

    For example:

    aundro@flatiron:~/.idapro$ cat themes/blue/theme.css
    
    @importtheme "_base";
    
    QWidget
    {
        background-color: lightblue;
    }
    
    CustomIDAMemo
    {
        qproperty-line-fg-regular-comment: red;
        [...snipped...]
    }
    aundro@flatiron:~/.idapro$
    

    You can then ship that ~/.idapro/themes/blue/theme.css file to other users, and any personal modifications they make to it, will be stored in ~/.idapro/themes/blue/user.css, leaving your original blue theme untouched.

    What can be styled, and how?

    Conceptually, IDA’s CSS styling can be “split” into 2 categories:

    1. Core Qt widgets styling
    2. IDA custom widgets styling

    1) Core Qt widgets styling

    In order to know what, and how to style Qt widgets, the best is to have a look at the references:

    2) IDA custom widgets styling

    IDA’s main stylable custom widgets have the following class names:

    • CustomIDAMemo
    • TextArrows
    • MainMsgList
    • TCpuRegs
    • navband_t

    You can find the entire set of properties supported by those, by looking at the contents of:

    • $IDA_INSTALL/themes/_base/theme.css
    • $IDA_INSTALL/themes/default/theme.css

    A note about the “.clr” file format

    In order to re-use color schemes with IDA < 7.3, users had to export, and then import them using .clr files.

    It’s worth pointing out that colors in those files, are in the form "BBGGRR", while CSS expects "#RRGGBB", so you will need to pay attention to that when porting colors from a .clr file.

    Alternatively, you can use the following script, which might help get most of the job done.

    {% file src=“../.gitbook/assets/port_clr72_to_css.py” %} Download a script {% endfile %}

    A note about the dark theme

    Note that even though IDA ships with a ‘dark’ theme, the version of Qt we use still doesn’t support OS-induced theme switches, and therefore IDA won’t automatically switch to it; the user will still have to change it manually.

    Restrictions

    Qt is mostly stylable using CSS, but it has a few restrictions:

    • Styling of URLs in QLabel instances is not supported (see this question)
    • In tabular views (e.g., the Functions window widget), we added the ability to highlight the portions of text that match the “quick filter” query (which can be opened using Ctrl+F). Unfortunately, the code we added to do that, will simply not be called for items in those views to which CSS directives apply. This is the case for e.g., “selected” items, in the dark mode. We will try and solve this in the future, but currently don’t have a fix.

    Teams

    Diffing and Merging Databases with IDA Teams

    Overview

    IDA 8.0 introduces IDA Teams - a mechanism that provides revision control for your IDA database files. Perhaps the most essential feature of this new product is the ability to natively diff and merge databases using IDA, allowing multiple reverse engineers to manage work on the same IDA database.

    This document discusses in detail the steps involved when diffing and merging IDA databases.

    Before continuing, you might want to take a quick look at the tutorial for HVUI, the GUI client for IDA Teams’ revision control functionality. It will be referenced multiple times in this document, although here we will focus specifically on the merging functionality.

    Inspecting changes

    After having done some reverse-engineering work on an IDA database, it is possible to view those changes in a special mode in IDA: right-click, and choose the diff action:

    Opening IDA for diff

    Here a new instance of IDA will be launched in a special “diff” mode:

    IDA in "diff" mode

    IDA’s diff mode

    This new IDA mode lets the user compare two databases, in a traditional “diff” fashion: essentially a two-panel window, showing the unmodified file on the left and the version with your changes on the right.

    The “Progress” widget

    Diff progress

    Represents the current step in the diff process.

    The left panel

    The left panel

    Shows the “untouched” version of the database (i.e., the one without your changes)

    The right panel

    The right panel

    Shows your version of the database (i.e., featuring your changes)

    Diff region details

    The details area

    Notice how both panels have a little area at the bottom, that is labeled “Details”.

    Details are available on certain steps of the diffing process, and provide additional information about the change that is currently displayed.

    The “diffing” toolbar

    The diff toolbar

    The actions in the toolbar are:

    Using actions in the toolbar, you can now iterate through the differences between the two databases, with each change shown in context as if viewed through a normal IDA window.

    The ability to view changes in context was a major factor in the decision to use IDA itself as the diffing/merging tool for IDA Teams.

    Diff mode IDA’s toolbar actions

    Previous chunk

    Move to the previous change

    Center chunk

    Re-center the panels to show the current chunk (useful if you navigated around to get more context)

    Next chunk

    Move to the next change

    Proceed to the next step

    Move to the next step in the diffing process.

    Toggle ‘Details’

    Toggle the visibility of the “Details” widgets in the various panels (note that some steps do not provide details, so even if the “Details” are requested, they might not be currently visible.)

    Terminology

    It is important to note the difference between the terms “diff” and “merge”.

    This document will sometimes use the two terms interchangeably. This is because to IDA, a diff is just a specialized merge. Both diffing and merging are handled by IDA’s “merge mode”, which involves up to 3 databases, one of which can be modified to contain the result of the merge.

    A diff is simply a merge operation that involves only 2 databases, neither of which are modified.

    This is why often times you will see the term “merge” used in the context of a diff. In this case “merge” is referring to IDA’s “merge mode”, rather than the process of merging multiple databases together into a combined database.

    Using IDA as a diffing tool

    We must stress the fact that performing a merge between two IDA databases is quite different than performing a merge between, say, two text files. A change in a chunk of text file will not have an impact over another chunk.

    IDA databases are not so simple. A change in one place in an idb will often have an impact on another place. For example, if a structure mystruct changed between two databases, it will have an impact not only on the name of the structure, but on cross-references to structure members, function prototypes, etc.

    This is why IDA’s merge mode is split into a strict series of “steps”:

    Progress steps

    Within a single step it is possible to go forward & backward between different chunks. But because of possible inter-dependencies between steps, it is not possible to move backwards between steps, you can only go forward:

    Apply changes button

    Since IDA’s diff mode is just a variation of its merge mode, diffing databases is also subject to this sequential application of steps in order to view certain bits of information. That is why, in some steps (e.g., the “Disassembly/Items”) IDA might not report some changes that were performed at another level.

    For instance, if a user marked a function as noret, the listings that will be shown in “Disassembly/Items” step, will not advertise that there was a change at that place (even though the "Attributes: noreturn" is visible in the left-hand listing), only the changes to the instructions (and data, …​) are visible in the current step:

    `noret` attribute missing

    The change will, however, be visible at a later step (i.e., “Functions/Registry”):

    `noret` attribute visible

    The changes applied during the “diff” process are only temporary. Exiting IDA (at any moment) will not alter the files being compared.

    Merging concurrent modifications (conflicts)

    As with any collaborative tool, it may happen that two coworkers work on the same dataset (e.g., IDA database), and make modifications to the same areas, resulting in “conflicts”. Conflicts must be “resolved” prior to committing.

    File in worklist requiring resolve

    To do that, right-click and pick one of the “resolve” options:

    The different resolve options

    IDA Teams provides the following merge strategies.

    Interactive merging

    If the option that was chosen (e.g., Interactive merge mode) requires user interaction due to conflicts, IDA will show in 3-pane “merge” mode.

    IDA in interactive merge mode

    When a conflict is encountered, you’ll have the ability to pick, for all conflicts, which change should be kept (yours, or the other). Every time you pick a change (and thus resolve a conflict), IDA will proceed with the merging, applying all the non-conflicting changes it can, until the next conflict - if any. When all conflicts are resolved, you can leave IDA, and the new resulting file is ready to be submitted.

    Appendix A

    Merge Steps

    This section provides a detailed overview of the steps involved in the merge process. The list of predefined merge steps is defined in merge.hpp of the IDASDK:

    enum merge_kind_t
    {
      MERGE_KIND_NETNODE,           ///< netnode (no merging, to be used in idbunits)
      MERGE_KIND_AUTOQ,             ///< auto queues
      MERGE_KIND_INF,               ///< merge the inf variable (global settings)
      MERGE_KIND_ENCODINGS,         ///< merge encodings
      MERGE_KIND_ENCODINGS2,        ///< merge default encodings
      MERGE_KIND_SCRIPTS2,          ///< merge scripts common info
      MERGE_KIND_SCRIPTS,           ///< merge scripts
      MERGE_KIND_CUSTDATA,          ///< merge custom data type and formats
      MERGE_KIND_STRUCTS,           ///< merge structs (globally: add/delete structs entirely)
      MERGE_KIND_STRMEM,            ///< merge struct members
      MERGE_KIND_ENUMS,             ///< merge enums
      MERGE_KIND_TILS,              ///< merge type libraries
      MERGE_KIND_TINFO,             ///< merge tinfo
      MERGE_KIND_UDTMEM,            ///< merge UDT members (local types)
      MERGE_KIND_SELECTORS,         ///< merge selectors
      MERGE_KIND_STT,               ///< merge flag storage types
      MERGE_KIND_SEGMENTS,          ///< merge segments
      MERGE_KIND_SEGGRPS,           ///< merge segment groups
      MERGE_KIND_SEGREGS,           ///< merge segment registers
      MERGE_KIND_ORPHANS,           ///< merge orphan bytes
      MERGE_KIND_BYTEVAL,           ///< merge byte values
      MERGE_KIND_FIXUPS,            ///< merge fixups
      MERGE_KIND_MAPPING,           ///< merge manual memory mapping
      MERGE_KIND_EXPORTS,           ///< merge exports
      MERGE_KIND_IMPORTS,           ///< merge imports
      MERGE_KIND_PATCHES,           ///< merge patched bytes
      MERGE_KIND_FLAGS,             ///< merge flags_t
      MERGE_KIND_EXTRACMT,          ///< merge extra next or prev lines
      MERGE_KIND_AFLAGS_EA,         ///< merge aflags for mapped EA
      MERGE_KIND_IGNOREMICRO,       ///< IM ("$ ignore micro") flags
      MERGE_KIND_HIDDENRANGES,      ///< merge hidden ranges
      MERGE_KIND_SOURCEFILES,       ///< merge source files ranges
      MERGE_KIND_FUNC,              ///< merge func info
      MERGE_KIND_FRAMEMGR,          ///< merge frames (globally: add/delete frames entirely)
      MERGE_KIND_FRAME,             ///< merge function frame info (frame members)
      MERGE_KIND_STKPNTS,           ///< merge SP change points
      MERGE_KIND_FLOWS,             ///< merge flows
      MERGE_KIND_CREFS,             ///< merge crefs
      MERGE_KIND_DREFS,             ///< merge drefs
      MERGE_KIND_BPTS,              ///< merge breakpoints
      MERGE_KIND_WATCHPOINTS,       ///< merge watchpoints
      MERGE_KIND_BOOKMARKS,         ///< merge bookmarks
      MERGE_KIND_TRYBLKS,           ///< merge try blocks
      MERGE_KIND_DIRTREE,           ///< merge std dirtrees
      MERGE_KIND_VFTABLES,          ///< merge vftables
      MERGE_KIND_SIGNATURES,        ///< signatures
      MERGE_KIND_PROBLEMS,          ///< problems
      MERGE_KIND_UI,                ///< UI
      MERGE_KIND_NOTEPAD,           ///< notepad
      MERGE_KIND_LOADER,            ///< loader data
      MERGE_KIND_DEBUGGER,          ///< debugger data
      MERGE_KIND_LAST,              ///< last predefined merge handler type.
                                    ///< please note that there can be more merge handler types,
                                    ///< registered by plugins and processor modules.
    };
    

    The list of merge steps is not final. If for example there is a conflict in structure members then the new merge phase to resolve this conflict will be created. The same is hold for UDT, functions, frames and so on. In other words in general case the exact number of merge steps is undefined and depends on the databases.

    Each item in a merge step is assigned to a difference position named diffpos. It may be an EA (effective address), enum id, structure member offset, artificial index and so on. In other words, a diffpos is a way of addressing something in the database.

    Every merge step starts with the calculation of differences and conflicts between items at the corresponding difference positions. As the result there is a list of diffpos with differences or conflicts. The diffpos`s without differences are not included in the list. Adjacent `diffpos`s are combined into a difference range called `diffrange.

    The merging process operates on a difference range diffrange. For one diffrange, a single merge policy can be selected.

    Global settings/Database attributes

    Merging of global database attributes. These attributes are mainly stored in the idainfo structure. This phase has two subphases:

    • Global settings/Database attributes/Graph mode
    • Global settings/Database attributes/Text mode

    The “Detail” pane is absent.

    merge mh inf

    Global settings/Processor specific

    Merging of global processor options. Usually these options are stored in the idpflags netnode.

    The “Detail” pane is absent.

    merge mh proc global

    Encodings/Registry

    Merging of registered string literal encodings. These encodings are used to properly display string literal in the disassembly listing.

    The “Detail” pane is absent.

    merge mh encodings

    Encodings/Settings

    Merging of default string encodings: what string encoding among the registered ones are considered as the default ones.

    The “Detail” pane is absent.

    merge mh encodings2

    Scripts/Registry

    Merging of embedded script snippets.

    When merging of embedded script snippets, the script name/language is displayed, and the “Detail” pane contains the script source with the highlighted differences:

    merge mh scripts

    Scripts/Settings

    Merging of the default snippet and tabulation size.

    The “Detail” pane is absent.

    merge mh scripts2

    Custom data/Types and Custom data/Formats

    Merging of the registered custom data types and formats.

    The “Detail” pane is absent.

    merge mh custdata

    Types/Enums

    Merging of assembler level enums (enum_t). Ghost enums are skipped in this phase, they will be merged when handling local types.

    To calculate diffpos, IDA Teams matches enum members by name and maps all enums with common member names into one diffpos.

    An example of enum merging:

    local_idb
      ;--------------------------
      ; enum enum_1, mappedto_1
      A                = 0
      B                = 1
    
    remote_idb
      ;--------------------------
      ; enum enum_1, mappedto_1
      A                = 0
      ;--------------------------
      ; enum enum_2, mappedto_2
      B                = 1
    

    In both idbs, enum constant “B” is present. However, in the remote idb “B” has a different parent enum, “enum_2”. Therefore enum_1 in the local idb corresponds to enum_1 and enum_2 in the remote idb. The user can select either enum_1 from the local idb or enum_1 and enum_2 from the remote idb.

    In other words, IDA will display both enum_1 and enum_2 in the Remote pane, indicating that the difference between the Local and Remote databases corresponds to two separate enums, but they are treated as a single difference location. The “Detail” pane will display the full enum definitions, with the differences highlighted:

    merge mh enums

    Types/Structs

    Merging of assembler level structures (struc_t).

    To calculate diffpos, IDA Teams matches structs by the following attributes, in this order:

    1. the structure name
    2. the structure tid and size

    If we fail to match a structure, then it will stay unmatched. Such an unmatched structure will have it own diffpos, allowing the user to copy it to the other idb or to delete it altogether.

    This merge phase deals with the entire structure types and their attributes. Entire structure types may be added or deleted, and/or conflicts in the structure attributes are resolved.

    If members of matched structures (at the same diffpos) differ, the conflict will be resolved later, during the Types/Struct members/…​ merge phase.

    In the UI, IDA will display the list of structure names, with the “Detail” pane showing the structure attributes:

    merge mh structs

    Types/Type libraries

    Merging of the loaded type libraries.

    This merge phase uses the standard “Type libraries” widget.

    The “Detail” pane is absent.

    merge mh tils

    Types/Local types

    Merging of local types.

    To calculate diffpos, IDA Teams matches local types by the following attributes, in this order:

    1. the type name
    2. the ordinal number and base type

    If we fail to match a type, then it will stay unmatched. Such an unmatched type will have it own diffpos, allowing the user to copy it to the other idb or to delete it altogether.

    This merge phase deals with entire types and their attributes. Entire local types may be added or deleted, and/or conflicts in their attributes are resolved. Differences in type members (e.g., struct members) will be resolved in a separate phase: Types/Local type members

    This merge phase uses the standard “Local types” widget. The “Detail” pane displays the type definition and its attributes.

    merge mh tinfo

    Types/Struct members/…​ and Types/Local type members/…​

    For example:

    • Types/Struct members/struct_t
    • Types/Local type members/struct conflict_t

    These merge phases merges the conflicting members of a structure or a local type.

    The “Detail” pane displays full information about the current member along with its attributes.

    merge mh udtmem

    Types/Ghost struct comments

    Ghost structs may have comments attached to them.

    This merge phase handles these comments:

    merge mh ghstrcmt

    We need a separate phase for these comments in order not to lose them during merging because by default ghost types are considered secondary to the corresponding non-ghost type. Normally during merge ghost types may be overwritten. However, local types cannot have comments at all. This is why ghost structure comments, if created, are valuable.

    Types/Struct members comments/…​

    Similarly to comments attached to entire structures, each structure member may have a comment.

    The same logic applies to ghost struct member comments:

    merge mh strmemcmt

    Addressing/Selectors

    Merging of selectors.

    This merge phase uses the standard widget “Selectors”.

    The “Detail” pane is absent.

    merge mh selectors

    Addressing/Storage types

    IDA Pro allocates so-called flags for each program address. These flags describe how to display the corresponding bytes in the disassembly listing: as instruction or data.

    There are two different storage methods for flags: virtual array (VA) and sparse storage (MM). The virtual array method is the default one, it allocates 32 bits for each program address. However, for huge segments this method is not efficient and may lead to unnecessarily huge databases. Therefore for huge segments IDA Pro uses sparse storage.

    This merge phase handles the defined program ranges and their storage types.

    The “Detail” pane is absent.

    merge mh stt

    Addressing/Segmentation

    This merge phase handles the program segmentation.

    When merging segments, IDA combines them into non-overlapping groups. Each group will have its own diffpos. For example, the following segmentations:

    local_idb
      seg000:00000000
      ...
      seg000:00000020
      ...
    
    remote_idb
      seg000:00000000
      ...
      seg001:00000010
      ...
      seg001:00000020
    

    will result in a single diffpos:

    merge mh segments

    The “Detail” pane displays segments in the combined group with their attributes.

    When merging segment, IDA tries to move the segment boundaries in a way that preserves the segment contents. If it fails to do so, the conflicting segments are deleted and new ones are created.

    Addressing/Segment groups

    Merging of segment groups. Segment groups are used only in OMF files. They correspond to the group keyword in assembler.

    The “Detail” pane is absent.

    merge mh seggrps

    Addressing/Segment register/…​

    Some processor have so-called segment registers. IDA Pro knows about them and can remember their value (one value per address range).

    For example, the x86 processor has ds, ss, and many other registers. IDA Pro can remember that, say, ds has the value of 1000 at the range 401000..402000.

    This merge phase handles segment registers. For each register, a separate merge phase is created. It contains address ranges: inside each address range the value of the segment register stays the same.

    To prepare diffpos, IDA Teams combines segment register ranges into non-overlapping ranges. diffpos is a range number.

    The “Detail” pane displays segment register ranges in diffpos with the value and the suffix that denotes the range type (u-user defined, a-automatically inherited from the previous range)

    merge mh segregs

    Addressing/Orphan bytes

    The database may have bytes that do not belong to any segment.

    To prepare diffpos, IDA Teams groups orphan bytes in the databases into nonintersecting ranges. diffpos is a range number.

    The “Detail” pane is absent.

    merge mh orphans

    Addressing/Patched

    Merging of the patched bytes.

    The “Detail” pane is absent.

    merge mh patches

    Addressing/Byte values

    Byte values in segments may differ even for non-patched addresses, for example if a snapshot of the process memory was taken during a debugger session.

    IDA Teams combines the sequential bytes in one diffpos.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays the conflicting byte values.

    merge mh byteval

    Addressing/Fixups

    Merging of fixup records.

    The “Detail” pane is absent.

    merge mh fixups

    Addressing/Manual memory mapping

    Merging of memory mappings.

    The “Detail” pane is absent.

    merge mh mapping

    Symbols/Exports

    Merging of exported symbols.

    Merge phase uses the standard “Exports” widget.

    The “Detail” pane is absent.

    merge mh exports

    Symbols/Imports

    Merging of imported symbols.

    Merge phase uses the standard “Imports” widget.

    The “Detail” pane is absent.

    merge mh imports

    Disassembly/Items

    When merging, IDA Teams compares disassembly items (instructions and data). IDA Teams compares disassembly items by length, flags, opinfo, name, comment, and netnode information (NALT_* and NSUP_* flags).

    This merge step uses the standard “IDA-View” widget so that items can be viewed in their context. For example:

    merge mh flags

    Comments/Anterior lines and Comments/Posterior lines

    Merging of extra comments.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays comment content.

    merge mh extracmt

    Disassembly/EA additional flags

    Merging of additional flags aflags_t.

    Each disassembly item may have additional flags that further describe it.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays additional flags.

    merge mh aflags ea

    Disasembly/Hidden ranges

    To prepare diffpos, IDA Teams groups hidden ranges into nonintersecting ranges. diffpos is a range number.

    The “Detail” pane displays the hidden range description.

    merge mh hiddenranges

    Disassembly/Source file ranges

    To prepare diffpos, IDA Teams groups source file ranges into nonintersecting ranges. diffpos is a range number.

    The “Detail” pane displays source file definition.

    merge mh sourcefiles

    Functions/Registry

    Function definitions (func_t) are merged using the standard “Functions” widget, while the “Detail” pane displays function attributes:

    merge mh func

    Functions/IM flags

    Merging of instruction kinds.

    To simplify decompilation, IDA has the notion of the instruction kind:

    • PROLOG instruction
    • EPILOG instruction
    • SWITCH instruction

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays instruction kind.

    merge mh ignoremicro

    Functions/Frames (global)

    This merge phase deals with the entire function frames. Function frame may be added or deleted.

    If members of the matched function frame differ, the conflict will be resolved later during the Functions/Frame/…​ merge phase. Each differing frame will be assigned its own merge step.

    The “Detail” pane is absent.

    merge mh framemgr

    Functions/Frame

    Merging of function frame details.

    A separate phase is created for each function. For example:

    • Functions/Frames/sub_401200 at 401200
    • Functions/Frames/_main at 4014E0

    Every of these phases merges the conflicting members of the function frame.

    The “Detail” pane displays the detailed information about the current function frame member.

    merge mh frame

    Functions/SP change points

    Merging of function SP change points.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays the SP change point details.

    merge mh stkpnts

    Cross-references/Flow

    Merging of regular execution flow from the previous instruction. IDA stores cross-references that correspond to regular execution flow in a special format, different from other cross-reference types.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane is absent.

    merge mh flows

    Cross-references/Code

    Merging of code cross-references.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays code references to address (diffpos).

    merge mh crefs

    Cross-references/Data

    Merging of data cross-references.

    This merge phase uses the standard “IDA-View” widget.

    The “Detail” pane displays data references to address (diffpos).

    merge mh drefs

    Marked positions/…​

    The following merge phases exist:

    • Marked positions/structplace_t
    • Marked positions/enumplace_t
    • Marked position/idaplace_t

    They deal with merging of bookmarks for:

    • structures
    • enums
    • addresses

    The “Detail” pane is absent.

    merge mh bookmarks

    Debug/Breakpoints/…​

    The following merge phases exist:

    • Breakpoints/Absolute bpts
    • Breakpoints/Relative bpts
    • Breakpoints/Symbolic bpts
    • Breakpoints/Source level bpts

    They deal with merging of various debugger breakpoints.

    The “Detail” pane is absent.

    merge mh bpts

    Debug/Watchpoints

    Merging of watch points.

    The “Detail” pane is absent.

    merge mh watchpoints

    Dirtree/$ dirtree/…​

    The following merge phases exist:

    • Dirtree/$ dirtree/tinfos
    • Dirtree/$ dirtree/structs
    • Dirtree/$ dirtree/enums
    • Dirtree/$ dirtree/funcs
    • Dirtree/$ dirtree/names
    • Dirtree/$ dirtree/imports
    • Dirtree/$ dirtree/bookmarks_idaplace_t
    • Dirtree/$ dirtree/bookmarks_structplace_t
    • Dirtree/$ dirtree/bookmarks_enumplace_t
    • Dirtree/$ dirtree/bpts

    They deal with merging of the standard dirtrees.

    The “Detail” pane is absent.

    merge mh dirtree tinfos
    merge mh dirtree structs

    Misc/Try blocks

    Merging of try and catch block info.

    The “Detail” pane describes try block.

    merge mh tryblks

    Misc/Virtual function tables

    Merging of virtual function tables.

    The “Detail” pane is absent.

    merge mh vftables

    Misc/Notepad

    Merging of database notepads. Each line of text is a diffpos.

    The “Detail” pane is absent.

    merge mh notepad

    Processor specific/…​

    Each processor plugin creates its own merge steps to handle the processor plugin’s specific data.

    For example, the PC processor module adds the following merge steps:

    • Processor specific/Analyze ea for a possible offset
    • Processor specific/Frame pointer info
    • Processor specific/Pushinfo
    • Processor specific/VXD info 2
    • Processor specific/Callee EA|AH value
    • …​
    merge mh proc pushinfo
    merge mh proc vxd2

    Plugins/Decompiler/…​

    Merging of the decompiler data starts with the global configuration parameters from hexrays.cfg:

    merge mh vd cfg

    To handle decompilation of specific functions, IDA stores the decompilation data in a database netnode named Hexrays node.

    The merge step Plugins/Decompiler/Hexrays nodes adds or deletes netnodes, indicating which functions have or haven’t been decompiled in each databases:

    merge mh vd nodes

    The decompilation data for matching functions is compared using the following attributes:

    • Plugins/Decompiler/…​/Numforms
    • Plugins/Decompiler/…​/mflags
    • Plugins/Decompiler/…​/User-defined funcargs
    • Plugins/Decompiler/…​/User-defined variable mapping
    • Plugins/Decompiler/…​/User-defined lvar info
    • Plugins/Decompiler/…​/lvar settings
    • Plugins/Decompiler/…​/IFLAGS
    • Plugins/Decompiler/…​/User labels
    • Plugins/Decompiler/…​/User unions
    • Plugins/Decompiler/…​/User comments
    • Plugins/Decompiler/…​/User-defined call

    If there is a difference, each comparison criteria will be assigned its own merge step. Each step will use the standard “Pseudocode” widget so that differences can be viewed in-context with the full pseudocode:

    merge mh numforms
    merge mh mflags
    merge mh funcargs
    merge mh vmap
    merge mh lvinfo
    merge mh lvar settings
    merge mh iflags
    merge mh labels
    merge mh unions
    merge mh cmts
    merge mh ucall

    Loader data merge phases

    The file loader that was used to create the database may have stored some data in the database that is specific to the loader itself.

    There are merge phases for each loader, for example:

    • Loader/PE file/…​
    • Loader/NE file/…​
    • Loader/ELF file/…​
    • Loader/TLS/…​
    • Loader/ARM segment flags/…​
    merge mh ldr pe
    merge mh ldr arm

    Debugger data merge phases

    To handle the differences in debugger data the following merge steps may be created:

    • Debugger/pin
    • Debugger/gdb
    • Debugger/xnu
    • Debugger/ios
    • Debugger/bochs
    • Debugger/windbg
    • Debugger/rmac_arm
    • Debugger/lmac_arm
    • Debugger/rmac
    • Debugger/lmac

    As can be deduced by their names, they handle debugger-specific data in the database.

    merge mh dbg pin
    merge mh dbg windbg

    Other plugins merge phases

    There are a number of IDA plugins that need to merge their data.

    For example:

    • Plugins/PDB
    • Plugins/golang
    • Plugins/EH_PARSE
    • Plugins/Callgraph
    • Plugins/swift

    Any third party plugin may add merge phases using the IDA SDK. We provide sample plugins that illustrate how to add support for merging into third party plugins.

    merge mh pdb
    merge mh swift

    Appendix B

    Using IDASDK to add merge functionality to plugin

    Overview

    Any plugin that stores its data in the database must implement the logic for merging its data. For that, the plugin must provide the description of its data and ask the kernel to create merge handlers based on these descriptions.

    The kernel will use the created handlers to perform merging and to display merged data to the users. The plugin can implement callback functions to modify some aspects of merging, if necessary.

    The plugin may have two kinds of data with permanent storage:

    1. Data that applies to entire database (e.g. the options). To describe this data, the idbattr_info_t type is used.
    2. Data that is tied to a particular address. To describe this data, the merge_node_info_t type is used.

    The kernel will notify the plugin using the processor_t::ev_create_merge_handlers event. On receiving it, the plugin should create the merge handlers, usually by calling the create_merge_handlers() function.

    Plugin

    The IDA SDK provides several sample plugins to demonstrate how to add merge functionality to third party plugins:

    • mex1/
    • mex2/
    • mex3/
    • mex4/

    The sample plugin without the merge functionality consists of two files:

    • mex.hpp
    • mex_impl.cpp

    It is a regular implementation of a plugin that stores some data in the database. Please check the source files for more info.

    We demonstrate several approaches to add the merge functionality. They are implemented in different directories mex1/, mex2/, and so on.

    The MEX_N macros that are defined in makefile are used to parameterize the plugin implementation, so that all plugin examples may be used simultaneously.

    You may check the merge results for the plugins in one session of IDA Teams. Naturally, you should prepare databases by running plugins before launching of IDA Teams session.

    Merge functionality

    The merge functionality is implemented in the merge.cpp file. It contains create_merge_handlers(), which is responsible for the creation of the merge handlers.

    Variants:

    mex1/
    Merge values are stored in netnodes. The kernel will read the values directly from netnodes, merge them, and write back. No further actions are required from the plugin. If the data is stored in a simple way using altvals or supvals, this simple approach is recommended.

    mex2/
    Merge values are stored in variables (in the memory). For more complex data that is not stored in a simple way in netnodes, (for example, data that uses database blobs), the previous approach cannot be used. This example shows how to merge the data that is stored in variables, like fields of the plugin context structure. The plugin provides the field descriptions to the kernel, which will use them to merge the data in the memory. After merging, the plugin must save the merged data to the database.

    mex3/
    Uses mex1 example and illustrates how to improve the UI look.

    mex4/
    Merge data that is stored in a netnode blob. Usually blob data is displayed as a sequence of hexadecimal digits in a merge chooser column. We show how to display blob contents in detail pane.

    Resolving conflicts in a file

    When a user needs to commit changes made to a file, but that same file has received other modifications (likely from other users) in the meantime, it is necessary to first “merge” the two sets of modifications together.

    When the two sets of modifications do not overlap, merging is trivial - at least conceptually. But when they do overlap, they produce conflict(s).

    Since IDA Teams focuses on collaboration over IDA database files, the rest of this section will focus on the different strategies that are available for resolving conflicts among those.

    IDA Teams comes with multiple strategies to help in conflict resolution of IDA database files:

    Auto-resolve (if no conflicts)

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If any conflict is discovered, bail out of the merge process, and don’t modify the local database.

    Auto-resolve, prefer local

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If a conflict is discovered, assume that the “local” change (i.e., the current user’s change) is the correct one, and apply that.

    Once all merging is done and conflicts are resolved, write those to the local database and exit IDA

    Auto-resolve, prefer remote

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If a conflict is discovered, assume that the “remote” change (i.e., the change made by another user) is the correct one, and apply that.

    Once all merging is done and conflicts are resolved, write those to the local database and exit IDA

    Interactive merge mode

    Manual merge mode.

    This will launch IDA in an interactive, 3-pane mode, allowing the user to decide how to resolve each conflict.

    Once all merging is done and conflicts are resolved, exit IDA and write the changes to the local database.

    Use local, discard remote

    Select the local database, ignoring all changes in the remote database.

    No IDA process is run.

    Use remote, discard local

    Select the remote database, ignoring all changes in the local database.

    No IDA process is run.

    hv command reference manual

    hv credentials

    In order to connect to the vault server, hv must at least have:

    • a username
    • a password
    • a hostname

    For example:

    $ hv -hhexvault.acme.com:65433 -uadmin -psecret users
    LastActive Adm    Login        Email
    ---------- --- ------------ ------------
    2022-06-27  *  admin
    2022-06-22     alice       Alice <[email protected]>
    Never          bob         Bob <[email protected]>
    ...
    

    There are 3 ways to specify credentials (in decreasing order of priority):

    All credentials, including usernames, are case-senstive, meaning that “Joe” and “joe” would be different users.

    Command line

    Passing credentials on the command line will always take precedence over environment variables and registry+keychain.

    -uUSERNAMEspecify username
    -pPASSWORDspecify password
    -hHOSTspecify host (server:port) (if port is omitted, defaults to 65433)
    -sSITENAMEspecify site
    --setremember credentials. This option doesn’t require the credentials to be passed through the command line, credentials passed through environment variables will work as well

    Environment variables

    Credentials can also be passed through environment variables. They will take precedence over those possibly found in the registry+keychain.

    VAULT_HOSTthe server host name
    VAULT_PORTthe server port
    VAULT_USERthe username to connect to the server
    VAULT_PASSthe user’s password
    VAULT_SITEthe site to use (most commands need a site to operate)

    Registry + keychain

    Unless environment variables or command-line arguments are provided, hv will look for credentials in the registry (and the OS’s keychain for passwords.)

    Credentials can be stored in the registry (and keychain) like so:

    alice@alice_PC$ hv --set -ualice -palice -hvaultserver -salice_on_alicepc
    

    The user, host (and optional site) will be persisted in the registry, while the password will be saved to the OS’s keychain.

    For this operation to succeed, at least a user and host must be provided

    In order to keep the various commands’ syntax as clear as possible, we will assume that the user has stored credentials (in either the registry+keychain or environment variables) for the rest of this manual.

    Best practices

    We recommend persisting credentials using the registry+keychain method.

    Once that is done, commands will become cleaner:

    >./hv info
    
    Hex-Rays Vault Server v1
    Vault time: 2022-04-14 15:36:29, up since 2022-04-14 15:17:25
    ...
    

    if you login to the server using hvui and save the login information, it will end up in the the registry+keychain method, and thus hv will then be able to use that information as well.

    Path formats

    Local paths refer to a file on the host file system.

    Vault paths refer to a file mapped on the vault. They can start with // to refer to the root of the vault.

    Some vault paths can optionally specify the revision of the path.

    Special symbols were created to access specific revisions:

    ^last revision available on the vault
    =current revision, that is synced on the site
    *all revisions

    Special file revision symbols

    subdir/means all files in all subdirectories
    subdirmeans all files in all subdirectories (same as subdir/)
    subdir/*means all files in the directory

    Directories and wildcards

    Examples

    Get the first revision of a file:

    $ hv sync //malware/Ransomware.WannaCry/41aa.exe.i64#1
    ok synced //malware/Ransomware.WannaCry/41aa.exe.i64#1 (838724 bytes)
    ok sync completed
    

    Sync to the last version of a file:

    $ hv sync malware/Ransomware.WannaCry/41aa.exe.i64#^
    ok synced //malware/Ransomware.WannaCry/41aa.exe.i64#3 (846916 bytes)
    ok sync completed
    

    Force sync to the current revision (we must specify -f to force a file transfer):

    $ hv sync -f malware/Ransomware.WannaCry/41aa.exe.i64#=
    ok synced //malware/Ransomware.WannaCry/41aa.exe.i64#2 (846916 bytes)
    ok sync completed
    

    Display md5 checksums of all revisions of a file:

    $ hv md5 malware/Ransomware.WannaCry/41aa.exe.i64#*
    ok 8F464140FA3DA4A20B03166F2E80325B //malware/Ransomware.WannaCry/41aa.exe.i64#1
    ok E0F7B984151FEF497985F375C64FA5C7 //malware/Ransomware.WannaCry/41aa.exe.i64#2
    ok 5C3B88306CF0D93DC35FFD67A710AE3B //malware/Ransomware.WannaCry/41aa.exe.i64#3
    

    List Hex-Rays Vault server’s toplevel directory contents:

    $ hv dir //
    2022-06-02 10:29:30       140267 CL29/edit //malware/cppobj_virtcall.i64#9
    2022-06-14 16:44:19      2173541 CL36/edit //iOS/dyld_ios16.i64#3
    

    Plan to add a file to the vault:

    $ hv add /path/to/local_rootdir/enable.png
    ok added '//enabled.png'
    

    Plan to add a directory:

    $ hv add /path/to/local_rootdir/REsearch
    ok added '//REsearch/vm2vm.dat'
    ok added '//REsearch/vm2vm.exe'
    ok added '//REsearch/vm2vm.i64'
    

    Plan to delete a file:

    $ hv del /path/to/local_rootdir/REsearch/*.dat
    ok checked out '//REsearch/vm2vm.dat' for 'del' (worklist 1)
    

    Show worklist to which files were added:

    $ hv worklist show
    WL 1 add  //REsearch/vm2vm.exe#0
    WL 1 add  //REsearch/vm2vm.i64#0
    WL 1 edit //cppobj_virtcall.i64#9
    WL 1 add  //enabled.png#0
    

    It is safe to interrupt a command using Ctrl-C. The file transfers in action will be gracefully terminated, so that no partially received files will be left on the disk. However, the requests that were delivered to the server will still be carried out up to the completion. For example, if the user asked to check out thousands of files for editing, this will be performed even if the user presses Ctrl-C after invoking the command.

    If the command syntax specifies ellipsis (…​), it means that multiple path patterns can be specified. The path patterns can be specified using local paths or vault paths, which start with a double slash (//).

    Commands

    Sites

    Commands in this section manipulate sites.

    A user must be using a site in order for most commands to work correctly.

    site add

    site add [-u USER] SITENAME ROOTDIR [HOST]

    Creates a new site.

    The specified user will be the owner of the new site. If the user is not specified, the current user will own the site. Only the site owner can use a site.

    Only admins can create sites for other users.

    To use a site, it must be specified as described in the credentials section.

    -u USERThe user (owner) of the new site, must be an existing username. Defaults to the current user. Admins can specify a different user.
    SITENAMEThe name of the site that will be created, it must be unique (no site can already exist with that name). It must not exceed 64 characters, and it must be composed of alphanumerics or underscore or dash. The first character cannot be a digit or a dash.
    ROOTDIRThe absolute path to the directory that will hold the vault files.
    HOSTThe computer from which the site can be used. It can be specified as an empty string. In this case the server will let the site to be used by any computer. However, since it is a safety feature that prevents from inadvertently using a site from a wrong computer, we do not recommend to specify it as an empty string. When creating a site for the current user, the host defaults to the current computer.

    Examples:

    # Example: Create a new site:
    alice@alice_PC$ hv site add alicepc /home/alice/vault_site
    
    # Example: Ensure that is exists:
    alice@alice_PC$ hv sites
    Site name User  Host     Last Used  Rootdir
    --------- ----- -------- ---------- ------------
    alicepc   alice alice_PC Never     /home/alice/vault_site
    
    # Example: Remember the new site in the registry:
    alice@alice_PC$ hv --set -salicepc
    Information has been saved into the registry.
    
    # Example: The new site is used in all future commands:
    alice@alice_PC$ hv info |grep site
    Client site: alicepc
    

    site del

    site del [-f] SITENAME

    Deletes a site.

    If -f was passed and the site has some pending worklists, they will be deleted.

    This is not a reversible operation, so we recommend caution.

    Only admins can delete sites that belong to other users.

    -fForce the deletion even if the site still has worklists.
    SITENAMEName of the site to delete.

    Example:

    # Example: Delete the site, forcing deletion of the site's worklists
    alice@alice_PC$ hv site del alice_old_laptop
    'alice_old_laptop' not empty
    
    alice@alice_PC$ hv site del -f alice_old_laptop
    

    site edit

    site edit [-u USER] SITENAME ROOTDIR [HOST]

    Edits an existing site’s details, such as the rootdir and the host it is bound to.

    Admins can reassign a site to a new user or edit sites of other users.

    -u USERThe new user (owner) of the site, can only be different than the previous owner if the current user is admin.
    SITENAMEThe name of the site that will be edited. It must exist and be owned by the current user, unless if the current user is admin.
    ROOTDIRThe new absolute path to the directory that will hold the site files.
    HOSTThe new hostname that will be used for the site. It can be omitted if no changes are desired.

    Examples:

    # Example: Change the root directory of a site:
    alice@alice_PC$ hv site edit alicepc /home/alice/vault
    
    
    # Example: Transfer ownership of site "local_on_shared_machine" to Bob:
    alice@alice_PC$ hv site edit -u bob local_on_shared_machine /home/shared/projects re.acme.com
    
    

    sites

    sites [SITENAME]

    Lists all sites.

    Show a list of sites, and their associated information.

    SITENAMEName of the site to show.

    Example:

    alice@alice_PC$ hv sites 
    Site name  User   Host       Last Used  Rootdir                Cur
    ---------- ------ ---------- ---------- ---------------------- ---
    alicepc    alice  alice_PC   2022-06-22 /home/alice/vault_site  *
    joe_laptop joe    ThinkPad14 2022-05-30 c:/work/vault
    chrispc    chris  chris_PC   Never      W:/vault
    

    Site filters

    filt get

    filt get [-s SITENAME]

    Displays the filter table associated with the site.

    Only admins can see filter tables of other users.

    -s SITENAMEThe sitename whose filter table should be displayed. If omitted, defaults to the current site.

    Examples:

    # Example: Show the default (i.e., empty) filter table
    alice@alice_PC$ hv filt get 
    ##### If the site filters were not set yet, the following info will be displayed:
    alice@alice_PC$ hv filt get
    ##### By default all vault files are visible.
    ##### The admin can set up permissions to deny access
    ##### to some files. The user too can set up filter
    ##### patterns to make some files invisible. For that,
    ##### each site has a user-controlled filter table.
    #####
    ##### The below table controls vault file visibility.
    ##### The table is scanned from the beginning to the end.
    ##### Lines starting with '!' hide the matching files.
    ##### Other lines make the matching files visible.
    ##### If the first line starts with '!', all files are
    ##### visible by default. Otherwise, all files are
    ##### invisible by default.
    # Example: !*.mov will hide all *.mov files.
    
    
    # Example: Set site filters from the standard input:
    alice@alice_PC$ hv filt set
    /work/research/
    <Ctrl-D>
    
    
    # Example: Verify the new filters:
    alice@alice_PC$ hv filt get 
    /work/research/
    ##### The files outside of /work/research/ are not visible anymore
    

    filt set

    filt set [-s SITENAME] [@file]

    Sets the filter table associated to the site, either interactively or from @file.

    Information about the format of site filters can be retrieved by issuing the filt get command.

    Only admins can modify filter tables of other users.

    -s SITENAMEThe sitename whose filter table should be set. If omitted, defaults to current site.
    @fileFile containing the new table.

    Examples:

    # Example: Make everything in the current site hidden, but `.bak` files
    alice@alice_PC$ echo *.bak | hv filt set
    
    
    # Example: Set site filters, from a file
    alice@alice_PC$ cat @tablefile
    *.idb
    *.exe
    alice@alice_PC$ hv filt set -s site1 @tablefile
    

    File manipulation

    add

    add [-s] [-w WORKLIST_ID] PATH_PATTERN…

    Adds new file(s) to a worklist.

    Issuing this command will not upload the file(s) to the server right away: the new file name(s) will be placed into a worklist, which then needs to be committed to the server. Once a worklist is committed, its files will be available to other users.

    The specified file(s) are not required to exist, it is possible to add a file that does not exist yet.

    The files must be inside the site’s rootdir.

    The files will be filtered using hvignore rules.

    -sSilent mode; do not output any messages.
    -w WORKLIST_IDThe id of the worklist that the file(s) will be added to. If omitted, defaults to worklist 1.
    PATH_PATTERN…Local path to file(s) to add to the vault.

    Examples:

    alice@alice_PC$ hv add new.idb
    ok added '//new.idb'
    
    
    # Example: add files to worklist 2
    alice@alice_PC$ hv add -w 2 cuda_demo_suite/*
    ok added '//cuda_demo_suite/bandwidthTest'
    ok added '//cuda_demo_suite/busGrind'
    ok added '//cuda_demo_suite/deviceQuery'
    ok added '//cuda_demo_suite/nbody'
    ok added '//cuda_demo_suite/nbody_data_files/nbody_galaxy_20K.bin'
    ok added '//cuda_demo_suite/oceanFFT'
    ok added '//cuda_demo_suite/oceanFFT_data_files/ocean.frag'
    ok added '//cuda_demo_suite/oceanFFT_data_files/ocean.vert'
    ok added '//cuda_demo_suite/oceanFFT_data_files/ref_slopeShading.bin'
    ok added '//cuda_demo_suite/oceanFFT_data_files/ref_spatialDomain.bin'
    ok added '//cuda_demo_suite/randomFog'
    ok added '//cuda_demo_suite/randomFog_data_files/ref_randomFog.bin'
    ok added '//cuda_demo_suite/vectorAdd'
    

    copy

    copy [-s] [-w WORKLIST_ID] SRC_PATH DST_PATH

    Makes a copy of vault file(s).

    This command creates a copy of the original file at the requested destination, and place the new file into a worklist. Once the worklist is committed, the new file will be visible to other users.

    NOTE: The source file will be downloaded from the server to the new file. If the source file was modified locally, those modifications won’t be part of the copy. This implies that if a file has just been added to the {hrvsrv} but not committed yet, it can’t be copied because it does not exist on the server yet.

    -sSilent mode; do not output any messages.
    -w WORKLIST_IDThe id of the worklist that the files will be added to. If omitted, defaults to worklist 1.
    SRC_PATHThe source path.
    DST_PATHThe destination path.

    Examples:

    # Example: Copy `newfile` into the `rust_samples` subdirectory. The worklist #2 will hold the change.
    alice@alice_PC$ hv copy -w 2 newfile rust_samples/newfile
    ok copied '//newfile#1' to '//rust_samples/newfile'
    
    
    # Example: Copy an entire subdirectory (note the trailing slash at the destination):
    alice@alice_PC$ hv copy source_subdir/ destination/subdir/
    ok copied '//source_subdir/aaa/sample.idb#1' to '//destination/subdir/aaa/sample.idb'
    ok copied '//source_subdir/common.idb#1' to '//destination/subdir/common.idb'
    
    
    # Example: Copy a subdirectory without recursion:
    alice@alice_PC$ hv copy source_subdir/* destination/subdir/
    ok copied '//source_subdir/common.idb#1' to '//destination/subdir/common.idb'
    
    
    # Example: Copy a file that was just added but not yet committed, it will fail:
    alice@alice_PC$ hv add test.text
    ok added '//test.text'
    alice@alice_PC$ hv copy test.text test.text.copy
    no matching files for '//test.text'
    
    

    move

    move [-s] [-w WORKLIST_ID] SRC_PATH DST_PATH

    Opens tracked file(s) for moving/renaming.

    This is similar to performing a copy, followed by a del: the new file will be checked out for copy while the original file will be checked out for deletion.

    -sSilent mode; do not output any messages.
    -w WORKLIST_IDThe id of the worklist that the file(s) will be added to. If omitted, defaults to the worklist 1.
    SRC_PATHThe source path.
    DST_PATHThe destination path.

    Example:

    alice@alice_PC$ hv move //VxWorks/CP05x/info.txt //VxWorks/CP05x/info.md
    ok moved '//VxWorks/CP05x/info.txt#1' to '//VxWorks/CP05x/info.md'
    
    alice@alice_PC$ hv wk show 1
    WL 1 copy //VxWorks/CP05x/info.md#0
    WL 1 del  //VxWorks/CP05x/info.txt#1
    
    alice@alice_PC$ hv edit //VxWorks/CP05x/info.txt
    file '//VxWorks/CP05x/info.txt' is already checked out
    

    del

    del [-s] [-w WORKLIST_ID] PATH_PATTERN…

    Opens tracked file(s) for deletion, adding them to a worklist.

    Once the worklist is committed, the file(s) won’t be tracked anymore by the {hrvsrv}, and will be removed from the local filesystem.

    NOTE: That this does not remove all revisions of the file on the server: that is the role of the purge command.

    -sSilent mode; do not output any messages.
    -w WORKLIST_IDThe id of the worklist that the file(s) will be added to. If omitted, defaults to worklist 1.
    PATH_PATTERN…Vault path of file(s) to delete.

    Example:

    alice@alice_PC$ ls /path/to/site_rootdir/cat
    /path/to/site_rootdir/cat
    
    alice@alice_PC$ hv del -w2 cat
    ok checked out '//cat' for 'del' (worklist 2)
    
    alice@alice_PC$ ls /path/to/site_rootdir/cat
    /path/to/site_rootdir/cat
    
    alice@alice_PC$ hv commit 2 "Deleted 'cat'"
    ok commit #39 completed
    
    alice@alice_PC$ ls /path/to/site_rootdir/cat
    ls: cannot access '/path/to/site/rootdir/cat': No such file or directory
    

    edit

    edit [-s] [-w WORKLIST_ID] PATH_PATTERN…

    Opens tracked file(s) for edit, adding them to a worklist.

    This command is used to instruct the {hrvsrv} that we will be working on files, so that it knows what revision of the file(s) that work will be based on and so later diff or resolve commands can work correctly.

    -sSilent mode; do not output any messages.
    -w WORKLIST_IDThe id of the worklist that the file(s) will be added to. If omitted, defaults to worklist 1.
    PATH_PATTERN…Vault path of file(s) to checkout for edit.

    Example:

    alice@alice_PC$ hv edit cat.i64
    ok checked out '//cat.i64' for 'edit' (worklist 1)
    
    (...do some work...)
    
    alice@alice_PC$ hv commit 1 "Analyzed 'main' function"
    ok commit #12 completed
    

    scan

    scan [-a] [-e] [-d] [-s] [PATH_PATTERN…]

    Reconciles the contents of the current directory (or the one(s) provided) on the local filesystem, with those of the corresponding path(s) on the server.

    This command will recursively look for:

    • new files (if -a is provided)
    • deleted files (if -d is provided)
    • modified files (if -e is provided)

    If any is found will create a new worklist and, add those for addition/deletion/modification.

    This command is particularly useful if the user didn’t have access to the server at a time it was necessary (e.g., to issue an edit command, while flying across the Atlantic.) Users can still get work done in such cases, and once they gain access to the server again, issue a scan to commit the changes.

    NOTE: The -e option causes the scan command to compute checksums of the local files, in order to compare them against those known to the server, in order to spot modifications.

    NOTE: If no options were given, defaults to -e -d.

    The files found by the scan command will be filtered by hvignore.

    -aCheckout for add files that are present only on the client side.
    -eCheckout for edit files that are present on both the vault and the client side but differ.
    -dCheckout for delete files that are present only on the server side.
    -sSilent mode; do not output any messages.
    PATH_PATTERN…Local path of file(s) to scan, if omitted defaults to current directory.

    Example:

    alice@alice_PC$ hv scan -a -e -d //
    added worklist 3
    checked out '//afile' for 'del' (worklist 3)
    checked out '//Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin.i64' for 'edit' (worklist 3)
    

    Working with worklists

    worklists

    worklists [WORKLIST_ID] [USER]

    Lists information about worklists.

    Show a (possibly filtered) list of pending worklists, and their metadata:

    • the timestamp of when they were last changed
    • the number of files they contain
    • the owner
    • the site
    • their description

    See also worklist show

    WORKLIST_IDRestrict to the provided worklist, defaults to showing all worklists.
    USERRestrict to user USER, defaults to the current user.

    Example:

    alice@alice_PC$ hv worklists 
    WL 4 2022-06-27 17:24:51 2 files; $USER@$ALICE_SITE More work on L30DS2 firmware
    
    

    Manipulating a worklist

    The following worklist commands will also work with the shorter wk alias.

    worklist add

    worklist add DESCRIPTION

    Creates a new worklist, with the provided description.

    The worklist will initially be empty, and assigned a free ID.

    Files can be associated to that new worklist when they are marked for addition, deletion, or edition.

    DESCRIPTIONThe description of the new worklist.

    Example:

    alice@alice_PC$ hv worklist add "Working on the 'TMutexLocker' vtable"
    added worklist 3
    alice@alice_PC$ hv edit -w 3 //cppobj*
    ok checked out '//cppobj_virtcall.i64' for 'edit' (worklist 3)
    alice@alice_PC$ hv worklist add "vm2vm: WIP"
    added worklist 4
    alice@alice_PC$ hv edit -w 4 //REsearch/*
    ok checked out '//REsearch/vm2vm.exe' for 'edit' (worklist 4)
    ok checked out '//REsearch/vm2vm.i64' for 'edit' (worklist 4)
    

    worklist show

    worklist show [-s SITE] [-u USER] [WORKLIST_ID]

    Lists worklist contents.

    Show a list of files opened for editing, addition or deletion, and their associated worklist(s).

    -s SITERestrict to site SITE. If omitted, defaults to the current site.
    -u USERRestrict to user USER. If omitted, defaults to the current user.
    WORKLIST_IDRestrict to the provided worklist, defaults to showing all worklists.

    Examples:

    alice@alice_PC$ hv worklist show 3
    WL 3 edit //cppobj_virtcall.i64#9
    alice@alice_PC$ hv worklist show 4
    WL 4 edit //REsearch/vm2vm.exe#1
    WL 4 edit //REsearch/vm2vm.i64#1
    alice@alice_PC$ hv worklist show 
    WL 4 edit //REsearch/vm2vm.exe#1
    WL 4 edit //REsearch/vm2vm.i64#1
    WL 3 edit //cppobj_virtcall.i64#9
    
    
    # Example: Show the worklist contents of another user
    alice@alice_PC$ hv worklist show -u ted
    WL 4 edit //malware/unk_2022#1/6 SITE=ted_laptop
    WL 2 copy //docs/onboarding.md#0 SITE=TEDPC
    WL 1 del  //ida64.i64#6 SITE=TEDPC
    
    

    worklist edit

    worklist edit WORKLIST_ID DESCRIPTION

    Edits a worklist description.

    WORKLIST_IDThe worklist to modify.
    DESCRIPTIONThe new description for the worklist.

    Example:

    # Example: change description of worklist 4
    alice@alice_PC$ hv worklist edit 4 "vm2vm: resolved all offsets in 'main' function"
    

    worklist del

    worklist del WORKLIST_ID

    Deletes a worklist.

    This command will only succeed if the worklist is currently empty.

    WORKLIST_IDThe worklist to delete.

    Example:

    alice@alice_PC$ hv worklist del 3
    worklist 3 is not empty
    alice@alice_PC$ hv revert //cppobj*
    ok reverted //cppobj_virtcall.i64
    alice@alice_PC$ hv worklist del 3
    

    Committing a worklist to the server

    commit

    commit [-f] [-s] WORKLIST_ID [DESCRIPTION]

    Commits files to the vault (push).

    This command uploads files from the local computer to the vault.

    After a successful commit, the modifications made to the files contained in the worklist will be made available for other users.

    A commit may fail if another user uploaded another revision of the changed files meanwhile. In this case resolve is necessary to merge the changes.

    If the worklist does not yet have a proper description, the DESCRIPTION is mandatory.

    -fForce commit of unchanged files.
    -sSilent mode; do not output any messages.
    WORKLIST_IDThe id of the worklist to commit to the vault.
    DESCRIPTIONA description for the commit.

    Example:

    alice@alice_PC$ hv commit 1
    worklist 1 has empty description
    alice@alice_PC$ hv commit 1 "more samples"
    ok accepted //newfile#1 (5 bytes)
    ok commit #2 completed
    

    Syncing files, resolving & reverting

    sync

    sync [-f] [-p] [-s] [@COMMIT_ID] [PATH_PATTERN[=REVISION]…]

    Downloads the requested revisions of the files from the server, and stores them on the local filesystem.

    NOTE: If no paths are provided, all files from the server will be retrieved.

    Requires that a site to be currently selected.

    -fForce sync. This will force a download of the files, even when the server thinks the client has the desired revision. This is a dangerous operation: any modification made to local files will be lost.
    -pThe server will perform sync without really transferring files. This options is useful if the local files are already in sync but the server has stale info about them.
    -sSilent mode; do not output any messages.
    @COMMIT_IDSync to state right after COMMIT_ID was committed, cannot be used with =REVISION.
    PATH_PATTERN[=REVISION]Vault path of file(s) to sync, if path is omitted, defaults to current directory, if no revision is specified, defaults to last revision available on vault (#^).

    Examples:

    # Example: Sync all
    alice@alice_PC$ hv sync 
    
    
    # Example: Sync only the specified subtree
    alice@alice_PC$ hv sync -f //work/ds1_10
    
    
    # Example: Sync a file to specific revision
    alice@alice_PC$ hv sync //malware/Trojan.Shylock.Skype/D57D.i64#1
    ok synced //malware/Trojan.Shylock.Skype/D57D.i64#1 (4374263 bytes)
    ok sync completed
    

    resolve

    resolve METHOD PATH_PATTERN

    Resolves conflicts in a file, using the specified strategy.

    After the strategy is successfully applied and the local file has incorporated both the “local” and “remote” changes, it will be ready to be committed.

    METHODOne of “auto”, “lmerge”, “rmerge”, “manual”, “local” or “remote”.
    PATH_PATTERNVault path of file(s) to resolve.

    Example:

    alice@alice_PC$ hv resolve lmerge depot/file1.txt
    

    revert

    revert [-a] [-p] [-s] PATH_PATTERN…

    Reverts opened files to their current revisions.

    -aRevert only unchanged files.
    -pThe server will revert the files without transferring files.
    -sSilent mode; do not output any messages. This options is useful if the local files are already in sync but the server has stale info about them.
    PATH_PATTERN…Vault path of file(s) to revert.

    Example:

    alice@alice_PC$ hv revert -a //
    ok reverted //Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin
    ok reverted //Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin.asm
    ok reverted //Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin.log
    

    migrate

    migrate [-s] PATH_PATTERN… WORKLIST_ID

    Moves opened files between worklists.

    -sSilent Mode; do not output any messages.
    PATH_PATTERN…Vault path of file(s) to move.
    WORKLIST_IDThe id of the worklist to move the files to, the worklist must already exist.

    Example:

    alice@alice_PC$ hv migrate afile subdir/for/fred/interfaces 3
    ok migrated //afile#1 to worklist 3
    ok migrated //subdir/for/fred/interfaces#0 to worklist 3
    

    Various information

    files

    files [-d] [-s] [PATH_PATTERN_OR_SUBSTRING[=REVISION]…]

    Displays the list of the files present in the vault.

    The command will collect files from the vault (that match the selection) and display for each file:

    • the file path
    • the revision
    • the file size if it hasn’t been deleted
    • the last commit id
    • the last action
    -dInclude deleted files.
    -sSearch for substring instead of using a path.
    PATH_PATTERN_OR_SUBSTRING[=REVISION]Vault path of file(s) to include in search or substring to search for if -s. If revision is not specified, defaults to current revision (#=). If no path is specified, defaults to the root directory of the vault.

    Examples:

    alice@alice_PC$ hv files -d //malware/Ransomware.WannaCry
    //malware/Ransomware.WannaCry/ed01ebfbc9eb5bbea545af4d01bf5f1071661840480439c6e5babe8e080e41aa.exe#1 (size 3514368 CL1/add)
    //malware/Ransomware.WannaCry/ed01ebfbc9eb5bbea545af4d01bf5f1071661840480439c6e5babe8e080e41aa.exe.asm#2 (CL2/del)
    //malware/Ransomware.WannaCry/ed01ebfbc9eb5bbea545af4d01bf5f1071661840480439c6e5babe8e080e41aa.exe.i64#1 (size 838724 CL1/add)
    //malware/Ransomware.WannaCry/ed01ebfbc9eb5bbea545af4d01bf5f1071661840480439c6e5babe8e080e41aa.exe.log#2 (CL2/del)
    
    
    alice@alice_PC$ hv files -s i64
    //malware/EquationGroup.GrayFish/GrayFish_9B1CA66AAB784DC5F1DFE635D8F8A904.i64#1 (size 2929035 CL1/add)
    //malware/Ransomware.WannaCry/ed01ebfbc9eb5bbea545af4d01bf5f1071661840480439c6e5babe8e080e41aa.exe.i64#1 (size 838724 CL1/add)
    //malware/Trojan.Ransom.Petya/eefa052da01c3faa1d1f516ddfefa8ceb8a5185bb9b5368142ffdf839aea4506.i64#1 (size 4535045 CL1/add)
    //malware/Trojan.Shylock.Skype/Shylock-skype_8FBEB78B06985C3188562E2F1B82D57D.i64#1 (size 4374263 CL1/add)
    //malware/Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin.i64#1 (size 319858 CL1/add)
    
    

    dir

    dir [-d] [-s] [-u] PATH_PATTERN_OR_SUBSTRING…

    Displays vault directory listing (current revisions).

    For each file entry the command will display:

    • the timestamp of when the file was committed
    • the file size
    • the commit id
    • the type of action that was executed on the file in the commit
    • the path
    • the current revision on disk
    • an extra label if the file is unsynced

    Directories will be displayed as: <subdir> PATH

    -dInclude deleted files.
    -sPath patterns are simple substrings.
    -uInclude unsynced files.
    PATH_PATTERN_OR_SUBSTRING…Vault path of file(s) to include in search or substring to search for if -s.

    Examples:

    alice@alice_PC$ hv dir -u -d //
    1970-02-04 01:52:08       573440 CL1/add  //malware/EquationGroup.GrayFish/A904#1
    2022-06-29 11:30:10            0 CL2/del  //malware/EquationGroup.GrayFish/A904.asm#0/2 UNSYNCED
    1970-02-04 01:52:08      2929035 CL1/add  //malware/EquationGroup.GrayFish/A904.i64#1
    2022-06-29 11:30:10            0 CL2/del  //malware/EquationGroup.GrayFish/A904.log#0/2 UNSYNCED
    1970-02-04 01:52:08      3514368 CL1/add  //malware/Ransomware.WannaCry/41aa.exe#1
    2022-06-29 11:30:10            0 CL2/del  //malware/Ransomware.WannaCry/41aa.exe.asm#0/2 UNSYNCED
    2022-06-29 13:52:57       846916 CL3/edit //malware/Ransomware.WannaCry/41aa.exe.i64#2/3 UNSYNCED
    
    
    alice@alice_PC$ hv dir "//*"
                        <subdir>              //malware
    

    show

    show PATH_PATTERN[=REVISION]

    Writes the contents of a file on the vault to the command line.

    PATH_PATTERN[=REVISION]Vault path to file(s) to display. If no revision is specified, defaults to current revision (#=). If the file revision denotes a deleted revision of the file, the contents will not be displayed.

    Example:

    alice@alice_PC$ hv show patterns/ubuntu-libgcc-10.pat
    415729CE415641554D89C54154554C89CD5389D34881EC280100004C8BBC2470 FF 15C2 14AD :0000 add_and_round.constprop.0 010000F30F6F842470010000C7442474000000004C8B842480010000C7442478000000000F294424504C8B742458F30F6F8C24800100004C897C2428488B9424
    415729CE415641554D89C54154554C89CD5389D34881EC280100004C8BBC2470 FF 90F7 14A0 :0000 add_and_round.constprop.0 010000F30F6F842470010000C7442474000000004C8B842480010000C7442478000000000F294424504C8B742458F30F6F8C24800100004C897C2428488B9424
    415729CE415641554D89C54154554C89CD5389D34881EC380100004C8BBC2480 FF 2016 157D :0000 add_and_round.constprop.0 0100004C8B842490010000C784248400000000000000F30F6F842480010000F30F6F8C2490010000C7842488000000000000004C897C2438488B842470010000
    415741564155415455534881EC780100004889542410488B9424B80100004889 FF 26D7 8168 :0000 bid128_ext_fma 4C24184C8BB424B001000048B9DDBADDBADDBADDBA4889742408488B8424C801000048..................48893C244C89F34C8B9C24C001000048898C24C0
    415741564155415455534881EC780100004889542410488B9424B80100004889 FF D77A 80B0 :0000 bid128_ext_fma 4C24184C8BB424B001000048B9DDBADDBADDBADDBA4889742408488B8424C801000048..................48893C244C89F34C8B9C24C001000048898C24C0
     ...
    

    diff

    diff PATH[=REVISION] PATH_OR_REV[=REVISION]

    Compares two databases, will launch IDA in diff mode.

    Only IDA databases (.i64, .idb) can be diffed with this command. If revisions of databases requested for comparison are currently not in the site, they will be downloaded to a temporary directory and will be deleted when IDA exits. On unix the temporary directory can be specified with $TMPDIR.

    PATH[=REVISION]Database 1.
    PATH_OR_REV[=REVISION]Database 2. If no path is specified, it will default to the path of Database 1. If no revision is specified, it will default to the current revision (#=).

    Examples:

    # Example: with `interfaces.i64` opened for edit and changed, this will open IDA and show the differences with the current revision on vault
    alice@alice_PC$ hv diff interfaces.i64
    
    
    alice@alice_PC$ hv changes interfaces.i64
    CM 9 2022-06-30 23:55:33 edit alice@alicepc interfaces.i64: deobfuscated some string
    CM 8 2022-06-28 23:30:17 edit john@johnpc interfaces.i64: annotated areas to inves
    CM 1 1970-02-04 01:52:08 add  john@johnpc added samples
    alice@alice_PC$ hv diff interfaces.i64 "#2"
    

    md5

    md5 PATH_PATTERN[=REVISION]

    Prints the md5 checksum of a file on the vault.

    PATH_PATTERN[=REVISION]Vault path of file(s) to process, if no revision is specified, defaults to the current revision (#=).

    Example:

    alice@alice_PC$ hv md5 Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin
    ok D243C0B2DBA37565CE3601AD78A73E07 //Win32.Emotet/29D6161522C7F7F21B35401907C702BDDB05ED47.bin#1
    

    info

    info

    Displays info about the vault and current session.

    Example:

    alice@alice_PC$ hv info 
    Hex-Rays Vault Server v1
    Vault time: 2022-06-29 00:13:55, up since 2022-06-28 09:40:53
    License user : Johnny Appleseed
    License email: [email protected]
    License: IDAULTTL; 10 users out of 30; expires on 2023-10-13
    MAC address: 7F:A7:B3:C1:8D:79
    Vault directory: /opt/hexvault/files
    Client name: john *ADMIN*
    Client site: johnpc
    Client host: johnpc (127.0.0.1)
    Client root: /home/john/vault
    Login time : 2022-06-29 00:13:55
    Last active: 2022-06-29 00:13:55
    

    changes

    changes [-s SITENAME] [-u USERNAME] [-c MIN_COMMIT] [-C MAX_COMMIT] [-m MAX_REPORTED_ENTRIES] [-d MIN_DATE] [-D MAX_DATE] [-l] [PATH_PATTERN…]

    Displays list of commits that affect a path.

    List can be refined using options.

    For each commit the following info will be displayed:

    • the commit id
    • the timestamp of the commit
    • if only one file was changed, the action that was done to it (e.g. edit)
    • the user who sent the commit
    • the site from which the commit was sent
    • a description of the commit, truncated to 40 chars unless if -l is enabled

    [horizontal] TIP:: This command is also available under the alias commits.

    -s SITENAMERestrict to commits from SITENAME.
    -u USERNAMERestrict to commits from USERNAME.
    -c MIN_COMMITRestrict to commits after commit: MIN_COMMIT.
    -C MAX_COMMITRestrict to commits prior to commit: MAX_COMMIT.
    -m MAX_REPORTED_ENTRIESLimit number of reported commits to: MAX_REPORTED_ENTRIES.
    -d MIN_DATERestrict to commits after MIN_DATE using format YYYY-MM-DD.
    -D MAX_DATERestrict to commits prior to MAX_DATE using format YYYY-MM-DD.
    -lDisplay long (>40 characters) commit descriptions.
    PATH_PATTERN…Filter commits by vault paths. If omitted, defaults to all files.

    Examples:

    # Example: find all commits made by john
    alice@alice_PC$ hv changes -u john
    CM 109 2022-04-05 17:09:18 john@johnpc reverted commit 85
    CM 108 2022-04-05 17:00:02 john@johnpc added more malware samples
    CM 107 2022-04-05 16:37:02 john@johnpc WannaCry: annotated a few funcs
    CM 106 2022-04-05 16:35:57 john@johnpc removed unused files
    
    
    # Example: show last 2 commits on a file with full descriptions
    alice@alice_PC$ hv changes -m 2 -l //iOS/dyld_ios16.i64
    Commit 42 2022-06-14 16:44:19 edit gregm@gregpc
            iOS: dyld iOS 16 WIP
    
            annotated more struct members
    
    Commit 35 2022-06-14 00:35:43 edit gregm@gregpc
            iOS: RE of ios16 split cache loading
    
            discovered some structures and their members
    
    

    users

    users

    Shows users.

    Example:

    alice@alice_PC$ hv users 
    LastActive Adm Login   RealName/Email         Notes
    ---------- --- ------- ---------------------- -----
    2022-07-27  *  admin   
    2022-09-16     alice   Alice <[email protected]>
    Never          bob     Bob <[email protected]>
    

    groups

    groups

    Displays all the existing groups and their users.

    Example:

    alice@alice_PC$ hv groups 
    malware: alice michael matt sarah jason
    audit: stephen ilse
    interns: russ
    

    group show

    group show GROUP_NAME

    Displays the list of users in a group.

    GROUP_NAMEA group name.

    Example:

    alice@alice_PC$ hv group show "malware"
    malware: alice michael matt sarah jason
    

    user show

    user show USERNAME

    Displays the full details of a specific user.

    The following details will be displayed:

    • the timestamp of when the user was last active
    • the username, with a * next to it if the user has admin privileges
    • the license id of the user
    • the full name of the user
    • the email address of the user
    • notes about the user
    USERNAMEThe username of the user to display.

    Example:

    alice@alice_PC$ hv user show johndoe
    2022-06-27     johndoe      99-9999-9999-99 John doe <[email protected]> NOTES
    

    commit show

    commit show COMMIT_ID

    Displays the contents of a commit.

    This will list all of the files that were changed by the commit.

    For each file the following details will be displayed:

    • the action that was performed on it in the commit
    • the path
    • the revision
    • if it’s unsynced, an extra label will be displayed
    • the size of the file
    COMMIT_IDThe id of the commit to display.

    Example:

    alice@alice_PC$ hv commit show 5
    add  //cat.i64#1 (size 503909)
    

    Misc.

    passwd

    passwd PASS [USER]

    Sets a new password for a user.

    PASSThe new password.
    USERThe username whose password should be changed. Only admins can change other users’ passwords. If omitted, defaults to the current user.

    Examples:

    alice@alice_PC$ hv passwd newpw
    
    
    alice@alice_PC$ hv passwd newpw user1
    

    commit edit

    commit edit COMMIT_ID DESCRIPTION

    Edits a commit description.

    Regular users may modify only their own commits. Admins may modify any commit.

    COMMIT_IDThe id of the commit to amend.
    DESCRIPTIONNew description of the commit.

    Example:

    alice@alice_PC$ hv commit edit 42 "removed unused file, it had been wrongfully added with commit #39"
    

    licenses

    licenses

    Shows active licenses

    Example:

    alice@alice_PC$ hv licenses 
    Vault licenses:
      99-9999-9999-99 IDAULTTW: used 2 out of 10 seat(s)
      Expires: 2023-04-15
      Online users: john@johnpc (99.999.99.99): 1 IDA instance(s)
    

    borrow

    borrow PRODUCT END_DATE

    Borrow a license

    A borrowed license can be used offline but other users will not have access to it.

    A borrowed license can be returned to the vault using return. If not returned earlier, it will automatically be returned to the vault at the expiration time.

    PRODUCTThe product code or license id.
    END_DATEYYYY-MM-DD - exact date, +Nd - N days since now, +Nw - N weeks since now. DD-MON-YYYY can be used to specify an exact date too.

    Example:

    alice@alice_PC$ hv borrow IDAULTTW 2022-07-31
    License IDAULTTW 99-9999-9999-99 has been borrowed until 2022-07-31 00:00:00
    alice@alice_PC$ hv borrow IDAULTTL +6d
    License IDAULTTL 99-9999-9999-99 has been borrowed until 2022-07-31 13:53:23
    

    return

    return PRODUCT

    Return a borrowed license

    A returned license becomes available to other vault users.

    PRODUCTThe product code or license id.

    Example:

    alice@alice_PC$ hv return IDAULTTW
    Licence 99-9999-9999-99 has been returned
    

    gc

    gc [-r] [-s] MAX_SIZE PATH_PATTERN…

    Deletes old files from the vault cache on the client.

    This command examines the contents of the .vault subdirectory in the specified directories and deletes old files from them, so that the total size of files does not exceed MAX_SIZE. MAX_SIZE can be specified as a plain number of bytes or using the k,M,G suffixes to denote KBs, MBs, GBs. The default value is 1GB.

    If -r is specified, all subdirectories of the current directory will be processed.

    -rRecursive
    -sSilent mode; do not output any messages.
    MAX_SIZEmax size of the cache.
    PATH_PATTERN…Local directories to process

    Example:

    alice@alice_PC$ hv gc 3G /mydir
    deleted /mydir/.vault/B52C6B8E8039752CE8BC6793816EB490: 120M freed, still 4.19G used
    deleted /mydir/.vault/C693254A5A370F609CC86A1F31CE5B84: 149M freed, still 4.05G used
    deleted /mydir/.vault/90CFB553818B2C44DE25759C0D14C811: 670M freed, still 3.39G used
    deleted /mydir/.vault/E8652439192CD33E8D4417C468AFFA49: 213M freed, still 3.18G used
    deleted /mydir/.vault/D0F3CF8A94A646E6EBBB15BD54847B31: 404M freed, still 2.79G used
    

    Administrative commands

    These commands require that the user executing them has admin privileges.

    Managing users

    user add

    user add USERNAME REALNAME EMAIL IS_ADMIN NOTES

    Adds a user.

    USERNAMEThe username of the user.
    REALNAMEThe full name of the user.
    EMAILThe email address of the user.
    IS_ADMINShould be 1 if the user is admin, otherwise 0.
    NOTESExtra notes about the user.

    Example:

    alice@alice_PC$ hv user add johndoe "John Doe" [email protected] 0 "NOTES"
    

    user edit

    user edit USERNAME REALNAME EMAIL IS_ADMIN NOTES

    Edits a user definition.

    USERNAMEThe username of the user to modify.
    REALNAMEThe full name of the user.
    EMAILThe email address of the user.
    IS_ADMINShould be 1 if the user is admin, otherwise 0.
    NOTESExtra notes about the user.

    Example:

    alice@alice_PC$ hv user edit johndoe "John Doe" [email protected] 0 "NOTES"
    

    user del

    user del [-b] [-f] USERNAME

    Deletes a user.

    Cuation: deleting a user with borrowed licenses will make the borrowed licenses unavailable until their expiration date.

    -bForce deletion even if the user has borrowed licenses.
    -fForce deletion even if the user has checked out files.
    USERNAMEThe name of the user to delete from the vault.

    Example:

    alice@alice_PC$ hv user del -f johndoe
    

    Managing groups

    group add

    group add GROUP_NAME

    Adds a new group.

    An empty group with the specified name is created.

    GROUP_NAMEthe name of the new group.

    Example:

    alice@alice_PC$ hv group add my_group
    

    group edit

    group edit GROUP_NAME USER ADD_OR_DELETE

    Edits a group by adding or deleting users.

    GROUP_NAMEthe name of the group.
    USERthe name of the user.
    ADD_OR_DELETEadd or delete the specified user from the group, 0 is delete, 1 is add.

    Example:

    alice@alice_PC$ hv group edit "my_group" "user1" 1
    alice@alice_PC$ hv group edit "my_group" "user1" 0
    

    group del

    group del GROUP_NAME

    Deletes a group.

    GROUP_NAMEthe name of the group to delete.

    Example:

    alice@alice_PC$ hv group del my_group
    

    Managing permissions

    perm get

    perm get

    Displays permission table.

    The current permission table is printed to the standard output.

    Example:

    alice@alice_PC$ hv perm get 
    ##### The permission for each vault file is determined as the result of applying
    ##### all matching lines, from the beginning of the permission table to the end.
    ##### An empty permission table grants all access to everyone.
    ##### A non-empty permission table starts by denying all access to everyone.
    grant user fred write //subdir-for-fred/
    deny group remote list //local-secret
    grant group analysts write //subdir/for/idbs/
    grant user * read //subdir/for/idbs/
    

    perm set

    perm set [@FILE]

    Sets new permissions table from STDIN or from file.

    The installed permission table becomes active immediately.

    We recommend using perm check to ensure that the new permission table works correctly.

    @FILEThe file from which to set the new permissions table.

    Example:

    alice@alice_PC$ hv perm set <perms.txt
    

    perm check

    perm check USERNAME PATH_PATTERN

    Checks permissions for a user.

    The list of files that are visible to the user is printed, along with the permissions that the user has. The read access is denoted by ‘r’ and the write access is denoted by ‘w’.

    USERNAMEThe USERNAME of the user whose permissions that will be tested.
    PATH_PATTERNVault path of file(s) that will be tested.

    Example:

    alice@alice_PC$ hv perm check fred
    rw //subdir-for-fred/afile
    rw //subdir-for-fred/anotherfile
    r- //subdir/for/idbs/interfaces.i64
    
    alice@alice_PC$ hv perm check fred //local-secret
    

    Others

    sessions

    sessions

    Displays the sessions info.

    For each session on the vault, the following info will be displayed:

    • the site
    • the user
    • the hostname
    • the timestamp of the login time
    • the timestamp of the last activity
    • “ADM” if the user has admin privileges
    • “*” for the session executing the command

    Example:

    alice@alice_PC$ hv sessions 
    gregpc       gregm        GREGPC-554HW             LOGIN=2022-07-04 LAST=2022-07-04 ADM *
    lindapc      linda        lindasmac                LOGIN=2022-07-02 LAST=2022-07-04
    

    purge

    purge [-s] [-y] PATH_PATTERN…

    Purges file(s) from the Vault server, permanently deleting it and all of its history.

    The path patterns must be specified using full paths, starting with //

    -sSilent mode; do not output any messages.
    -yReally purge the files, without this parameter the command does a dry-run.
    PATH_PATTERN…Vault path of file(s) to purge from the vault.

    Example:

    alice@alice_PC$ hv purge -s -y //work/ds1_10 //work/more_work
    

    Concepts

    What is a “site”?

    A site represents a mapping of the server files to the local filesystem. Normally each computer has a site associated with it. A site has the following attributes:

    • A site name
    • A host name
    • The path to a folder on the filesystem (a.k.a., “root directory”)
    • Path filters (optional)

    site details

    Root directory

    The root directory is the essential attribute of a site. It denotes where all files from the vault server will be mapped to the local disk. Everything inside the root directory can potentially be uploaded to the vault server and shared with other team members.

    The vault server cannot manage files located outside the root directory. However, this limitation is straightforward to overcome: create a symbolic link (or, on Windows, a junction point) from the root directory to the directory of your choice. This will make the target of the symbolic link visible as part of the root directory.

    The vault server keeps track of each site’s state: what files have been downloaded to the local disk, what files have been checked out for editing, etc. This simplifies the housekeeping tasks, especially for big repositories with millions of files. Even for them, downloading the latest files or reconciling the local disk with the server, are almost instantaneous.

    The host name is a security feature that prevents from using a site on a wrong computer. Since the server keeps track of the files downloaded to each site, using a wrong site may lead to an inconsistent mapping between the server and local disk. However, if the user does not want this protection, it is possible to erase the host name in the site definition.

    Sites can be edited from the “Sites” view.

    Path filters

    By default all server files are visible, but for servers that manage gigabytes of data this can be problematic: it may be undesirable for users to download all files to their local computer.

    Site filters provide a mechanism that lets users restrict the set of files their IDA Teams client works with. Users who want to work on some specific projects can set a filter that restricts the visibility only to selected subdirectories.

    Each site has its own filters, that con be modified at any time. Filters do not directly affect any files on the local disk, or on the server: they are strictly about visibility.

    WARNING: Site filters are meant simplify a user’s life by letting them focus on specific projects. Since they can be modified by users, they should not be considered a security measure: that would be the role of the permissions system, which can only be managed by vault_server administrators.

    NOTE: The purpose of site filters is to create a subset of the full set of files provided by the server. Site filters don’t directly affect what locally-available files (i.e., present in the site’s rootdir, but not tracked by the server) are visible by IDA Teams clients.

    There is another mechanism to specify what files should not be added to the vault. See .hvignore for more info.

    Examples

    An empty filter

    $ cat empty_filter.txt
    $
    

    Hide all files, except those in malware/

    $ cat only_malware.txt
    malware/
    $
    

    Show all files, except those from the pentesting team

    $ cat hide_pentest.txt
    !pentesting/
    $
    

    Show all files but those from the pentesting team, except their produced documents

    $ cat hide_pentest_but_docs.txt
    !pentesting/
    pentesting/research_docs/
    $
    

    Resolving conflicts in a file

    When a user needs to commit changes made to a file, but that same file has received other modifications (likely from other users) in the meantime, it is necessary to first “merge” the two sets of modifications together.

    When the two sets of modifications do not overlap, merging is trivial

    • at least conceptually. But when they do overlap, they produce conflict(s).

    Since IDA Teams focuses on collaboration over IDA database files, the rest of this section will focus on the different strategies that are available for resolving conflicts among those.

    IDA Teams comes with multiple strategies to help in conflict resolution of IDA database files:

    Auto-resolve (if no conflicts)

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If any conflict is discovered, bail out of the merge process, and don’t modify the local database.

    Auto-resolve, prefer local

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If a conflict is discovered, assume that the “local” change (i.e., the current user’s change) is the correct one, and apply that.

    Once all merging is done and conflicts are resolved, write those to the local database and exit IDA

    Auto-resolve, prefer remote

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If a conflict is discovered, assume that the “remote” change (i.e., the change made by another user) is the correct one, and apply that.

    Once all merging is done and conflicts are resolved, write those to the local database and exit IDA

    Interactive merge mode

    Manual merge mode.

    This will launch IDA in an interactive, 3-pane mode, allowing the user to decide how to resolve each conflict.

    Once all merging is done and conflicts are resolved, exit IDA and write the changes to the local database.

    Use local, discard remote

    Select the local database, ignoring all changes in the remote database.

    No IDA process is run.

    Use remote, discard local

    Select the remote database, ignoring all changes in the local database.

    No IDA process is run.

    hvignore (and .hvignore) files

    IDA Teams comes with a mechanism that lets users specify what files should be ignored when adding files from their local machines to the vault_server.

    The main hvignore file (path/to/install-dir/hvignore)

    In IDA Teams’ install directory, you will find the “main” hvignore file, that is pre-populated with a list of files that you would typically not want to add to the vault_server, such as .bak backup files and unpacked IDA database files: .id0, .nam, etc…

    The syntax for hvignore is very close to that of .gitignore files.

    Additional .hvignore files

    In addition to that file, you can have .hvignore file (notice the . - dot) placed in your site’s directory structure.

    When found, those files’ contents will be appended to the main file’s contents.

    The registry

    On Microsoft Windows, IDA Teams will store certain bits of information in the registry (host name, user name, site name.)

    On macOS and Linux, it will use a pseudo-registry file, located at $HOME/.idapro/hvui.reg.

    Passwords storage in the OS’s keychain

    While hosts, user names & site names are persisted to the registry, passwords are stored securely in the operating system’s keychain.

    • On Windows, the Windows Credential Store is used (therefore requiring Windows 7 or newer)
    • On macOS, the macOS Keychain is used
    • On Linux, the “Secret service” is used (through libsecret-1)

    Managing permissions on a vault

    The vault_server includes a way to restrict the access of users and groups to the data stored in the vault_server.

    The permission file is a text file that contains the permission table. The file consists of lines that grant or deny access to certain path patterns in the vault. The syntax for an entry is the following:

    grant/deny group/user NAME PERMISSION VAULT_PATH_PATTERN

    Possible PERMISSION values are: list, read and write. read includes list, write includes read (and thus also includes list).

    Example of a permission file:

    # deny everything to everyone. no need to specify it explicitly,
    # it is the default for a non-empty permission table:
    # deny  user *      list  //*
    
    deny  user *      list  //secret/   # nobody can see //secret. this line is superfluous
                                        # because everything is denied by default.
    grant user hughes write //secret/   # but hughes can write to secret and its subdirs
    grant user john   read  //secret/   # and john can read the entire directory.
    deny  user *      list  //secret/supersecret # supersecret is not visible to anyone
    grant user hughes write //secret/supersecret # but hughes can modify it (john cannot)
    grant user *      write //local_files/ # everyone can work with 'local_files'
    deny group remote list //local_files/  # except that the 'remote' group cannot see 'local_files'
    

    An empty permission table means that no permissions are enforced rendering all files accessible by everyone. As soon as a non-empty permission table is specified, all access is denied to everyone by default.

    Path patterns may refer to (yet) unexisting files. Users and groups too may refer to unexisting users and groups.

    The order of the permission file is important as the last lines will take precedence over the preceding lines (if there are conflicts).

    Admins are not affected by the permission table, they are granted all access.

    To install a new permission table, use perm set.

    The current permissions can be retrieved using perm get.

    Hex-Rays Vault’s visual client user manual

    About this manual

    This user guide provides information about HVUI, the Hex-Rays Vault visual client.

    HVUI is provided in addition to the command-line client, HV.

    This manual assumes that the reader has an understanding of the IDA Teams general concepts.

    NOTE: Although Hex-Rays Vault will host any file you want, its primary use-case is to allow users to keep a history, and allow collaborative work on, IDA databases (i.e., .idb and .i64 files.) Throughout this manual, we will be using the terms “idbs” and “files” interchangeably.

    Getting started

    In order to function, HVUI will need to connect to a Hex-Rays Vault server.

    This guide assumes that such a server is running, accessible, and an account is available:

    Connection attributes
    Hostvaultserver
    Port65433
    User namejoe
    User passwordsecret

    Starting HVUI

    The first time the user starts the application, credentials will need to be input:

    Credentials

    NOTE: Checking the checkbox at the bottom of the form, will cause HVUI to store credentials in the registry, password(s) will be stored in the OS’s keychain.

    If this is the first time a login is performed from this machine, the user will have to specify a directory where files will be locally stored:

    Provide site information

    This will a site (that is, a mapping of the server files on the local disk) for use on this computer.

    After accepting the dialog, you will be presented with the main view:

    Main view

    Getting the latest revision

    The widget now shows what files are available.

    Notice the #0/1 suffixes: it means we currently have revision number 0 (i.e., no revision at all) of those files.

    Let’s sync those files to their latest revision, from the server:

    Sync to latest

    And the files are now up-to-date:

    After syncing to latest revision

    Working with files

    In the previous chapter, we have introduced the notion of “syncing to the latest revision”.

    This chapter will go a bit further, and introduce the most common, day-to-day operations users will want to perform on their files.

    What are worklists, and commits?

    Any work done in HVUI will involve worklists, and commits.

    Worklist

    A worklist holds files that have been

    • modified,
    • marked for addition or
    • deletion,
    • …​

    Those modifications are local to the user’s site. They will only be made available for everyone after the user commits the worklist.

    Commit

    Once a worklist is committed, it becomes a commit, and makes its modifications available for everyone.

    In comparison to a worklist, a commit holds “published” modifications, and any user syncing to that commit will benefit from those.

    Let’s look at a concrete example illustrating worklists and commits: adding a file to the Hex-Rays Vault!

    Adding files to the vault

    From the “Local files” widget, I can add a file that is not yet present in the Hex-Rays Vault server:

    Adding a local file

    That file will now be added to the current worklist (one will be created if needed):

    Local file marked for addition

    For this new file to become available for everyone, the user will need to “commit” the worklist:

    Committing a {wl}

    Once the worklist is committed, it becomes a commit, and the modifications are then available for everyone:

    Commits

    TIP: Notice how our commit isn’t the first one in the system: another user submitted a commit before us — it’s that commit that added the files we’ve seen in the getting-started portion of this guide.

    Modifying files

    When working on a file, a user must first check it out for modification:

    Check out for modification

    Just like with the adding, the file will now show in a worklist:

    File checked out for modification

    …​and just like with the adding, whatever modification you make to the file, will only be visible to coworkers after committing that worklist.

    Committing

    Files that have been checked out (e.g. for modification) or opened for adding will go into a worklist until they are committed, which then turns the worklist into a commit. A worklist can be committed to make its changes available to other users: right-click, commit

    Committing a {wl}

    The worklist becomes a commit:

    Commits

    …​and the worklist is gone:

    Worklists

    Synchronizing files

    To fetch the latest set of the changes (changes/additions/deletions), use “Get latest revision”.

    Viewing the history of a file

    To get an overview of all of the changes made to a file: right-click, File history

    File history

    {widget_label_history}

    From the “History of …​” widget, you can view any revision of a file.

    Open revision

    It’s also possible to synchronize files to older revisions, from this widget.

    Sync to revision

    When asked to do that, HVUI will retrieve that older revision of the file from the server. This is what will now be present on your filesystem.

    Notice how the file now shows as ‘outdated’:

    File is marked as outdated

    Opening files

    On many widgets, it’s possible to view/open a file. If the file extension has a corresponding association it will be used to open the file.

    File associations

    Out-of-the-box, HVUI associates .i64 files with IDA. In addition to that, it provides a default “fallback” "*" association that will cause matching files to be opened in IDA.

    Users can specify their file extension associations via a form available from the View menu.

    File extension associations

    Deleting files

    Files can be removed from the server (if they have become unnecessary for example): right-click, delete.

    Checkout for delete

    Just like other file actions, the change (deletion) needs to be committed for its effects to be visible on the server.

    Reverting changes to files

    To revert unwanted changes to a file: right-click, Revert

    Reverting a file

    It is also possible to use “Revert if unchanged” to only revert files that were checked out without actual changes. This is especially useful when used on a selection of files or a directory.

    Renaming and Moving Files or Folders

    One may wish to rename and/or move around files/folders in their workspace, for that “Checkout for move/rename…” can be used.

    Renaming a directory

    Renaming a directory

    Copying Files or Folders

    {hvui_app} provides an action to copy files or directories easily. Use “Checkout for copy…”.

    Copying a file

    Copying a file

    Finding a file in the vault

    When a vault contains a lot of files, manually searching for a file in the directory tree becomes inefficient. To help you locate files easily, you can use the Find in vault…​ action.

    You can navigate between the search results by using Next search result and Previous search result, located next to Find in vault…​ both in the toolbar, and in the “Search” menu.

    Font styles

    As you may have noticed by now, files are shown with different font styles in different circumstances.

    A gray font denotes a file that is not in the vault. It has been added or renamed and not yet commited.

    A bold font means that this file is being worked on, or has been changed.

    An italic font means that it’s not the latest version of this file.

    Some combinations are possible, for example a file being resolved (not latest version and being worked on) will have a bold and italic font style. The combination gray (not in vault) and italic (not latest version) is for example not possible.

    Inspecting changes

    After having done some reverse-engineering work on an IDA database, it is possible to view those changes in a special mode in IDA: right-click, and choose the diff action:

    Opening IDA for diff

    Here a new instance of IDA will be launched in a special “diff” mode:

    IDA in “diff” mode

    IDA’s diff mode

    This new IDA mode lets the user compare two databases, in a traditional “diff” fashion: essentially a two-panel window, showing the unmodified file on the left and the version with your changes on the right.

    The “Progress” widget

    Diff progress

    Represents the current step in the diff process.

    The left panel

    The left panel

    Shows the “untouched” version of the database (i.e., the one without your changes)

    The right panel

    The right panel

    Shows your version of the database (i.e., featuring your changes)

    Diff region details

    The details area

    Notice how both panels have a little area at the bottom, that is labeled “Details”.

    Details are available on certain steps of the diffing process, and provide additional information about the change that is currently displayed.

    The “diffing” toolbar

    The diff toolbar

    The actions in the toolbar are:

    • Previous chunk
    • Center chunk
    • Next chunk
    • Proceed to the next step
    • Toggle ‘Details’

    Using actions in the toolbar, you can now iterate through the differences between the two databases, with each change shown in context as if viewed through a normal IDA window.

    The ability to view changes in context was a major factor in the decision to use IDA itself as the diffing/merging tool for IDA Teams.

    Diff mode IDA’s toolbar actions
    Previous chunk

    Move to the previous change

    Center chunk

    Re-center the panels to show the current chunk (useful if you navigated around to get more context)

    Next chunk

    Move to the next change

    Proceed to the next step

    Move to the next step in the diffing process.

    Toggle ‘Details’

    Toggle the visibility of the “Details” widgets in the various panels (note that some steps do not provide details, so even if the “Details” are requested, they might not be currently visible.)

    Terminology

    It is important to note the difference between the terms “diff” and “merge”.

    This document will sometimes use the two terms interchangeably. This is because to IDA, a diff is just a specialized merge. Both diffing and merging are handled by IDA’s “merge mode”, which involves up to 3 databases, one of which can be modified to contain the result of the merge.

    A diff is simply a merge operation that involves only 2 databases, neither of which are modified.

    This is why often times you will see the term “merge” used in the context of a diff. In this case “merge” is referring to IDA’s “merge mode”, rather than the process of merging multiple databases together into a combined database.

    Using IDA as a diffing tool

    We must stress the fact that performing a merge between two IDA databases is quite different than performing a merge between, say, two text files. A change in a chunk of text file will not have an impact over another chunk.

    IDA databases are not so simple. A change in one place in an idb will often have an impact on another place. For example, if a structure mystruct changed between two databases, it will have an impact not only on the name of the structure, but on cross-references to structure members, function prototypes, etc.

    This is why IDA’s merge mode is split into a strict series of “steps”:

    Progress steps

    Within a single step it is possible to go forward & backward between different chunks. But because of possible inter-dependencies between steps, it is not possible to move backwards between steps, you can only go forward:

    Apply changes button

    Since IDA’s diff mode is just a variation of its merge mode, diffing databases is also subject to this sequential application of steps in order to view certain bits of information. That is why, in some steps (e.g., the “Disassembly/Items”) IDA might not report some changes that were performed at another level.

    For instance, if a user marked a function as noret, the listings that will be shown in “Disassembly/Items” step, will not advertise that there was a change at that place (even though the "Attributes: noreturn" is visible in the left-hand listing), only the changes to the instructions (and data, …) are visible in the current step:

    noret attribute missing

    The change will, however, be visible at a later step (i.e., “Functions/Registry”):

    noret attribute visible

    NOTE: The changes applied during the “diff” process are only temporary. Exiting IDA (at any moment) will not alter the files being compared.

    Merging concurrent modifications (conflicts)

    As with any collaborative tool, it may happen that two coworkers work on the same dataset (e.g., IDA database), and make modifications to the same areas, resulting in “conflicts”. Conflicts must be “resolved” prior to committing.

    File in worklist requiring resolve

    To do that, right-click and pick one of the “resolve” options:

    The different resolve options

    IDA Teams provides the following merge strategies.

    Interactive merging

    If the option that was chosen (e.g., Interactive merge mode) requires user interaction due to conflicts, IDA will show in 3-pane “merge” mode.

    IDA in interactive merge mode

    When a conflict is encountered, you’ll have the ability to pick, for all conflicts, which change should be kept (yours, or the other). Every time you pick a change (and thus resolve a conflict), IDA will proceed with the merging, applying all the non-conflicting changes it can, until the next conflict - if any. When all conflicts are resolved, you can leave IDA, and the new resulting file is ready to be submitted.

    General concepts

    Collaboration in the reverse-engineering field

    Over the years, a trend has been emerging in the field of reverse-engineering: a need to enable collaboration between different (teams of) individuals and share their work with one another.

    In order to achieve that, different groups of people have come up with different strategies, the most common ones being:

    • “live” propagation of changes from one IDA session, to other sessions (this requires all IDA instances are either directly connected, or talk to a server, at all time)
    • extracting some of the important bits of work done on an .idb, and applying those to another one – in fact, we at Hex-Rays have also been providing a tool that enables this type of workflow: the lumina server.

    While those solutions have interesting properties, they also typically suffer from significant drawbacks as well:

    • they might require a live connection at all times in order to work,
    • there is no way to make sure many supposedly-synced IDA sessions are indeed working with exactly the same data,
    • the information that’s extracted isn’t complete enough,

    So we took a step back and looked at how things are done in other places, and in particular in the field of software engineering, where collaboration over a piece of software is typically achieved by using revision control.

    That is why one of the key features of IDA Teams, is software engineering-inspired revision control, applied to reverse-engineering.

    NOTE: Plans for IDA Teams span well beyond just revision control, but this was our first, significant milestone.

    Revision control for reverse-engineering projects

    The general concepts behind IDA Teams revision control, are essentially the same as those behind many other revision control systems, and uses a client-server architecture.

    • On the server-side, we will find a new component: the vault server
    • On the client side, we will find that an IDA Teams installation now install a few additional binaries: a pair of clients to connect to the server

    The vault_server

    The server, called vault_server, maintains a ledger of operations that were performed on the files that it hosts: modifications, added files, deleted files, …

    It should be made available to all members of a team destined to work on common projects.

    The server comes with its own installer, and an “admin guide” explaining how to tune the installation & perform common tasks.

    The clients

    On the client-side, IDA Teams will consist of an IDA installer, to be installed on each user’s computer.

    In addition to the regular IDA binaries, that new installer will also place two clients to connect to the vault_server:

    • hv: a command-line interface client
    • hvui: a visual client

    Users interact with the server using those tools, which lets them get a good view over who contributed what, and offer functionality for organizing their work in the most efficient way possible.

    Online vs Offline

    Users have all the freedom to organize their work the way they see fit: they don’t have to be connected at all times, and will only need to be able to connect to the server when it is time to publish their changes so they are available for others to benefit from.

    Resolving conflicts in a file

    When a user needs to commit changes made to a file, but that same file has received other modifications (likely from other users) in the meantime, it is necessary to first “merge” the two sets of modifications together.

    When the two sets of modifications do not overlap, merging is trivial

    • at least conceptually. But when they do overlap, they produce conflict(s).

    Since IDA Teams focuses on collaboration over IDA database files, the rest of this section will focus on the different strategies that are available for resolving conflicts among those.

    IDA Teams comes with multiple strategies to help in conflict resolution of IDA database files:

    Auto-resolve (if no conflicts)

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If any conflict is discovered, bail out of the merge process, and don’t modify the local database.

    Auto-resolve, prefer local

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If a conflict is discovered, assume that the “local” change (i.e., the current user’s change) is the correct one, and apply that.

    Once all merging is done and conflicts are resolved, write those to the local database and exit IDA

    Auto-resolve, prefer remote

    Launch IDA in a non-interactive batch mode, attempting to perform all merging automatically.

    If a conflict is discovered, assume that the “remote” change (i.e., the change made by another user) is the correct one, and apply that.

    Once all merging is done and conflicts are resolved, write those to the local database and exit IDA

    Interactive merge mode

    Manual merge mode.

    This will launch IDA in an interactive, 3-pane mode, allowing the user to decide how to resolve each conflict.

    Once all merging is done and conflicts are resolved, exit IDA and write the changes to the local database.

    Use local, discard remote

    Select the local database, ignoring all changes in the remote database.

    No IDA process is run.

    Use remote, discard local

    Select the remote database, ignoring all changes in the local database.

    No IDA process is run.

    What is a “site”?

    A site represents a mapping of the server files to the local filesystem. Normally each computer has a site associated with it. A site has the following attributes:

    • A site name
    • A host name
    • The path to a folder on the filesystem (a.k.a., “root directory”)
    • Path filters (optional)

    site details

    Root directory

    The root directory is the essential attribute of a site. It denotes where all files from the vault server will be mapped to the local disk. Everything inside the root directory can potentially be uploaded to the vault server and shared with other team members.

    The vault server cannot manage files located outside the root directory. However, this limitation is straightforward to overcome: create a symbolic link (or, on Windows, a junction point) from the root directory to the directory of your choice. This will make the target of the symbolic link visible as part of the root directory.

    The vault server keeps track of each site’s state: what files have been downloaded to the local disk, what files have been checked out for editing, etc. This simplifies the housekeeping tasks, especially for big repositories with millions of files. Even for them, downloading the latest files or reconciling the local disk with the server, are almost instantaneous.

    The host name is a security feature that prevents from using a site on a wrong computer. Since the server keeps track of the files downloaded to each site, using a wrong site may lead to an inconsistent mapping between the server and local disk. However, if the user does not want this protection, it is possible to erase the host name in the site definition.

    Sites can be edited from the “Sites” view.

    Path filters

    By default all server files are visible, but for servers that manage gigabytes of data this can be problematic: it may be undesirable for users to download all files to their local computer.

    Site filters provide a mechanism that lets users restrict the set of files their IDA Teams client works with. Users who want to work on some specific projects can set a filter that restricts the visibility only to selected subdirectories.

    Each site has its own filters, that con be modified at any time. Filters do not directly affect any files on the local disk, or on the server: they are strictly about visibility.

    WARNING: Site filters are meant simplify a user’s life by letting them focus on specific projects. Since they can be modified by users, they should not be considered a security measure: that would be the role of the permissions system, which can only be managed by vault_server administrators.

    NOTE: The purpose of site filters is to create a subset of the full set of files provided by the server. Site filters don’t directly affect what locally-available files (i.e., present in the site’s rootdir, but not tracked by the server) are visible by IDA Teams clients.

    There is another mechanism to specify what files should not be added to the vault. See .hvignore for more info.

    Examples

    An empty filter

    $ cat empty_filter.txt
    $
    

    Hide all files, except those in malware/

    $ cat only_malware.txt
    malware/
    $
    

    Show all files, except those from the pentesting team

    $ cat hide_pentest.txt
    !pentesting/
    $
    

    Show all files but those from the pentesting team, except their produced documents

    $ cat hide_pentest_but_docs.txt
    !pentesting/
    pentesting/research_docs/
    $
    

    hvignore (and .hvignore) files

    IDA Teams comes with a mechanism that lets users specify what files should be ignored when adding files from their local machines to the vault_server.

    The main hvignore file (path/to/install-dir/hvignore)

    In IDA Teams’ install directory, you will find the “main” hvignore file, that is pre-populated with a list of files that you would typically not want to add to the vault_server, such as .bak backup files and unpacked IDA database files: .id0, .nam, etc…

    The syntax for hvignore is very close to that of .gitignore files.

    Additional .hvignore files

    In addition to that file, you can have .hvignore file (notice the . - dot) placed in your site’s directory structure.

    When found, those files’ contents will be appended to the main file’s contents.

    The registry

    On Microsoft Windows, IDA Teams will store certain bits of information in the registry (host name, user name, site name.)

    On macOS and Linux, it will use a pseudo-registry file, located at $HOME/.idapro/hvui.reg.

    Passwords storage in the OS’s keychain

    While hosts, user names & site names are persisted to the registry, passwords are stored securely in the operating system’s keychain.

    • On Windows, the Windows Credential Store is used (therefore requiring Windows 7 or newer)
    • On macOS, the macOS Keychain is used
    • On Linux, the “Secret service” is used (through libsecret-1)

    Managing permissions on a vault

    The vault_server includes a way to restrict the access of users and groups to the data stored in the vault_server.

    The permission file is a text file that contains the permission table. The file consists of lines that grant or deny access to certain path patterns in the vault. The syntax for an entry is the following:

    grant/deny group/user NAME PERMISSION VAULT_PATH_PATTERN

    Possible PERMISSION values are: list, read and write. read includes list, write includes read (and thus also includes list).

    Example of a permission file:

    # deny everything to everyone. no need to specify it explicitly,
    # it is the default for a non-empty permission table:
    # deny  user *      list  //*
    
    deny  user *      list  //secret/   # nobody can see //secret. this line is superfluous
                                        # because everything is denied by default.
    grant user hughes write //secret/   # but hughes can write to secret and its subdirs
    grant user john   read  //secret/   # and john can read the entire directory.
    deny  user *      list  //secret/supersecret # supersecret is not visible to anyone
    grant user hughes write //secret/supersecret # but hughes can modify it (john cannot)
    grant user *      write //local_files/ # everyone can work with 'local_files'
    deny group remote list //local_files/  # except that the 'remote' group cannot see 'local_files'
    

    An empty permission table means that no permissions are enforced rendering all files accessible by everyone. As soon as a non-empty permission table is specified, all access is denied to everyone by default.

    Path patterns may refer to (yet) unexisting files. Users and groups too may refer to unexisting users and groups.

    The order of the permission file is important as the last lines will take precedence over the preceding lines (if there are conflicts).

    Admins are not affected by the permission table, they are granted all access.

    To install a new permission table, use perm set.

    The current permissions can be retrieved using perm get.

    Tour of hvui’s widgets

    Vault files

    The “Vault files” widget represents the data that’s available on the server.

    Vault files

    Since its contents can be very similar to what is shown in the “Local files” (depending on whether user’s site is using site filters or not), it has been given differentiating background color, in the hope of not confusing it with that other widget.

    Actions

    A typical context menu for “Vault files”

    Local files

    The “Local files” widget represents the data that’s available on the local disk.

    Local files

    The root of the tree starts at the site’s workdir.

    Note that this widget honors the hvignore file that’s placed in the installation directory next to hvui, and also any .hvignore file found in the directory structure.

    Actions

    Worklists

    Worklists

    The “Worklists” widget groups all the modifications that are still pending (and are thus not yet visible to other users)

    Those changes are grouped by “Worklist” (i.e., topic). A typical worklist will hold files that are related, and will be made available to all once a worklist is committed.

    It is possible to move file(s) from a worklist to another, by “drag & drop”’ing them, “cut & paste”’ing them, or using the Migrate to another worklist…​ action.

    By default, this widget will only show the current user’s worklists, but can be made to show everyone’s worklists, in read-only mode: the current user will still only be able to modify (or commit) his/her own worklists.

    Actions

    Commits

    Commits

    The “commits” widget shows a list of previous commits made to the server, in a concise and condensed way.

    It is possible to request a detailed view for any entry in that list.

    NOTE: The amount of entries displayed by this widget can be configured through the “Options” dialog.

    Actions

    Commit

    Commit

    Using the “commits” widget, it is possible to inspect what changes were previously submitted to the vault in a particular commit.

    Actions

    Sites

    Sites

    The “Sites” widget provides the ability for a user (or an admin) to administrate users’ sites.

    Non-admin users will only be able to modify their own site(s), while an admin will have the ability to do so for all users’ sites.

    If you find yourself using more than one site on any specific machine, you will likely have to resort to the Use this site…​ to switch between them.

    Actions

    Users

    Users

    The “Users” widget lists all knows users of the Hex-Rays Vault server.

    Non-admin users have the possibility to change their password.

    Users with administrator rights will, in addition, be able to add, remove, modify users - and modify anyone’s password.

    Actions

    Log window

    Log window

    The logging area is helpful in providing feedback about different types of events:

    • Details of successful operations
    • Connection state (logins, logout’s, network issues, …)
    • …other various bits of information that the program deems relevant for the user to know

    Actions

    The logging area provides typical text-manipulating functions (copying, searching, …) as well as the ability to turn timestamps on/off.

    File history

    File history

    The “File history” widget shows all changes ever commited to a single file.

    Actions

    User interface actions

    The following is a list of actions, available in hvui. Note that most actions are “contextualized” in the sense that they require certain conditions to be met, in order to work:

    • the widget being operated on,
    • whether or not a selection is available,
    • the state of the selected file(s),
    • …​

    All actions are available from the toplevel menubar’s submenus. Those whose operating conditions are not met, will appear disabled.

    NOTE: Contrary to the toplevel menubar’s submenus, context menus (AKA: popup menus, right-click menus, …​) will not feature actions that are disabled. Those menus are created on-the-fly, and it’s best not to pollute them with unnecessary noise.

    Get the latest revision

    Sync the selected file(s) (or the entire server contents), to the latest revision.

    This effectively updates all local copies of the files, except for those that are currently opened for edition, addition or deletion: those will be left untouched in order to not risk losing user modifications made to them.

    Commit…​

    Prompts the user for a commit description, and submits the files that are part of the current worklist, to the server.

    Once successfully committed, a worklist will disappear and a new entry will be added to the list of commits.

    Committed changes (modifications, additions and deletions) are available for all users that can access those files.

    Scan and commit

    Scan the selected files/folders (or the entire root directory), and create a worklist with all changes that were found: files that have been added, removed, modified, …​

    Unless you explicitly tell it not to (by checking the “Do not show this dialog anymore” checkbox), this action will first offer the possibility to refine what exactly the scan should be looking for:

    Scan and commit options

    Spotting new or deleted files is fairly straightforward, but when it comes to existing files, hvui will also perform a md5 checksum comparison.

    If differences are found, hvui will prepare a new worklist with those.

    This is especially useful if one had to work on some files while no connection to the server was available (e.g., on a plane).

    The files found will be filtered by hvignore.

    Details…​ (on “Commits” widget)

    Opens a detailed view of the commit details, including a list of the files that were modified:

    Commit

    Sync to this revision

    Retrieve the specified revision from the server, and replace the local file with it.

    Diff against previous revision

    For each selected file, perform a diff of the selected file, against its previous revision.

    NOTE: If a file is opened and has been modified, those yet-unsubmitted modifications will not be part of the diff: only those between the two recorded revisions, will be visible.

    Diff against…​

    A more powerful version of diff, that lets the user pick for each “side” of the diff:

    • either the current revision, any revision number, or to the local file on disk
    • the path to the file (it is therefore possible to diff entirely unrelated files together)

    Checkout for edit

    Informs the server that we will be working on those files in the near future.

    They will be added to the worklist number 1 (which will be created if it doesn’t exist), and will turn bold, to draw attention to them.

    Add to vault

    Informs the server that we wish to add the selected file(s) to the list of files managed by the server.

    They will be added to the worklist number 1 (which will be created if it doesn’t exist), and will turn bold, to draw attention to them.

    The files selected will be filtered by hvignore.

    Checkout for delete

    Informs the server that we wish to delete the selected file(s) from the list of files managed by the server.

    They will be added to the worklist number 1 (which will be created if it doesn’t exist), and will turn bold, to draw attention to them.

    Checkout for move/rename…​

    For each selected file (or directory), prompt the user for a new name to rename to.

    This is the equivalent of executing , followed by .

    Checkout for copy…​

    For each selected file or directory, prompt the user for a new name to create a copy into.

    The copied files will be added to the worklist number 1 (which will be created if it doesn’t exist).

    Open this revision

    For each selected file, launch the associated application.

    NOTE: The file is retrieved from the server, and downloaded into a temporary location. It is cleaned after the application exits.

    File history

    For each selected file, open a widget showing the list of modifications that were made to the file.

    Revert…​

    Reverts the selection - that is: remove from the worklist(s), and restore the current revision from the server.

    NOTE: This action will lose all changes made to the selected file(s), and thus will first prompt for confirmation.

    See also

    Revert if unchanged

    A “safe” version of , that will first verify if files have been modified, before reverting them.

    Files that have not been modified, will be reverted. Those that have been, will remain untouched.

    Since this is a safe operation (in the sense that no data can be lost), this action will not ask for confirmation.

    See also

    Open

    For each entry in the selection, launch the associated “View” application.

    If no association is present for a specific file extension (or if the file does not have an extension), the default * association will be used.

    Open the containing folder

    For each folder in the selection, asks the OS to open a file browser at the corresponding place.

    What file browser is opened, depends on the OS’s settings.

    Resolve actions

    hvui comes with many strategies to resolve files:

    However, hvui only knows how to handle a successful merge operation when IDA is used. Consequently, only the last 2 operations will be available for non-.idb/.i64 files.

    Resolve actions prolog

    The first thing that happens is that the last revision of the file is retrieved from the server (and stored in a temporary location).

    Then (for all but and ) IDA will be launched in a special mode, and with different set of parameters that depend on the exact nature of the operation.

    Auto resolve (if no conflicts)…​

    Perform the “resolve actions” prolog, then launch IDA non-interactively: IDA will attempt merging the changes made to the local file with those that were made to the last revision of the file, and succeed if no conflicting changes were found.

    This is a safe operation in the sense that, should there be any conflict, it will not touch the local file.

    Auto resolve, prefer local…​

    Perform the “resolve actions” prolog, then launch IDA non-interactively: IDA will merge the changes made to the local file with those that were made to the last revision of the file. Each time a conflict is found, automatically pick the local change.

    Auto resolve, prefer remote…​

    Perform the “resolve actions” prolog, then launch IDA non-interactively: IDA will merge the changes made to the local file with those that were made to the last revision of the file. Each time a conflict is found, automatically pick the other change.

    Interactive merge

    Perform the “resolve actions” prolog, then launch IDA interactively: the user will be presented with a 3-panel IDA instance, where it will be possible to manually pick either the local, or the remote change, for each conflict.

    Once the user is done and exits IDA saving the resulting database, the file will be considered resolved.

    Use local, discard remote…​

    Perform the “resolve actions” prolog, then just consider that our local version of the file is the correct one.

    Use remote, discard local…​

    Perform the “resolve actions” prolog, then replace the local version of the file with the other one.

    Diff against the local file

    Retrieve the specified file(s) from the server (and store them in a temporary location), then launch the associated “Diff” application to compare them against their local versions.

    Find in vault…​

    Prompt the user for a pattern/substring to be looking for, and queries the server.

    If a match is found, it will be selected in the vault files widget. It is then possible to move forward/backward in the search results.

    Next search result

    Move forward in the result set of a find operation.

    Previous search result

    Move backward in the result set of a find operation.

    Refresh

    Clears the local caches of all the data that was retrieved from the local filesystem & the Hex-Rays Vault server, and force a refresh of all widgets.

    Show in Vault files/Show in Local files

    Find the corresponding selection in the other view, select it, and give focus to that view.

    This is helpful to navigate between vault files and local files.

    Show deleted files

    Toggle the visibility of files that have been deleted.

    When a file is deleted in revision #N, its revisions up to #N-1 are still kept on the server (but not visible by default.)

    This offers the opportunity to view (and possibly resurrect) such deleted files.

    Add new site…​

    Create a new site.

    While logged in as a non-administrator, you won’t have the choice but to associate the site to the current user. However, when logged in as an administrator, it is necessary to provide the user’s name as well.

    Edit site…​

    Offers the ability to modify the following properties of a site:

    • Its root directory
    • The client’s host
    • Optional site filters

    Delete site…​

    Delete the selected site (after prompting for confirmation.)

    Naturally, deleting a site will also delete the worklists that were associated with that site. The commits that were made from that site will not be deleted.

    Use this site…​

    Have hvui switch to the selected site.

    This can be useful if you have more than one site on your machine.

    Switching to a site requires that the client host matches that of the current machine, and that the site belongs to the user who’s currently logged-in.

    Add new user…​

    Prompts the administrator for various bits of information about the user: login, real name, license ID, password, …​ and registers that information on the server.

    Edit user…​

    Lets an administrator change all information about a particular user, with the exception of their login (immutable) and password (use the dedicated action to do that.)

    Delete user…​

    Asks the administrator for confirmation, then deletes the user from the server.

    Deleting a user also deletes the worklists that belonged to the user. The commits made by that user won’t be impacted.

    Set password…​

    Prompts for a new password (and its confirmation), and applies the changes on the server.

    Add new worklist…​

    Prompts the user for a brief worklist description (which can remain empty at this point), and create a new, empty worklist.

    Edit worklist…​

    Shows worklist details, and offers to edit its description.

    This action can only be performed on worklists that belong to the current user.

    View worklist…​

    Shows other users’ worklists details, in read-only mode.

    Delete worklist…​

    Prompts for confirmation, and deletes the worklist.

    All modifications (including additions & deletions of files), will be abandoned/reverted.

    Migrate to another worklist…​

    Lets the user pick another one of his pending worklists (or, alternatively, create a new one), then moves the files to that worklist.

    Show other users’ worklists

    Toggle between the two following states:

    1. show this user’s worklists on this site,
    2. show all worklists (from all users, and on all sites)

    Miscellaneous information

    Simplified site creation on first connection

    In order to do any meaningful work in hvui, a user must be using a site.

    To make it easier to get started using hvui, the first time a user connects to the Hex-Rays Vault server, the application will propose a a simplified site creation dialog, that will query only the “root directory”.

    The rest of the site attributes will be guessed (or generated):

    • the host name will be retrieved automatically from the system
    • the user name is known since the user just logged in
    • the site name will be generated from the user name + host name

    It is of course still possible to alter that site later, through the “Sites” widget.

    Technical information

    HVUI stores certain bits of information in the registry:

    • On Windows, this will be located under \HKEY_CURRENT_USER\Software\Hex-Rays\HVUI
    • On Unix systems, HVUI will use a file-backed registry, located at $HOME/.idapro/hvui.reg

    Teams

    lc command reference manual

    Introduction

    The lc executable provides a command-line interface to interact with a Lumina server and its contents.

    NOTE: virtually all the commands described in this document, require administrator rights; “regular” users will typically not have the necessary privileges.

    Command-line options

    -h, –host HOSTNAME[:PORT]
    Lumina host name and port (if port is omitted, it defaults to 443)

    -u USERNAME
    specify username

    -p PASSWORD
    specify password

    -v, –verbose
    verbose output

    In order to connect to a Lumina server, lc must at least be provided with a hostname and a valid user-password pair.

    In order to keep the various commands’ syntax as clear as possible, we will omit the login options from commands for the rest of this manual.

    Other options exists, specific to each lc command (see Commands).

    Commands

    The following commands are accepted by lc:

    Operating with metadata

    Commands in this section let users view metadata stored in the Lumina server and their history.

    hist show

    hist show [OPTION]

    Queries history of changes for function(s).

    The following informations will be displayed for each change:

    • The ID of the change
    • The timestamp of the change
    • The ID of the push that contains the change
    • The name of the function at that change (+ (*) if it has been modified past this change)
    • optional: The username of the user that pushed this change
    • optional: The name of the license associated with the push for this change
    • optional: The email of the license associated with the push for this change
    • optional: The ID of the license associated with the push for this change
    • optional: The ID of the function
    • optional: The effective address (EA) of the function in the input file for the change
    • optional: The hash of the function
    • optional: The path of the idb file where the change came from
    • optional: The hash of the file where the change came from
    • optional: The path of the file where the change came from

    TIP: Wildcards can be used to facilitate the usage of options that take strings as input. See the appendix.

    Options:

    Short formLong formDescription
    -a--additional-fields LISTComma-delimited list of additional info to display (username, license_name, license_email, license_id, func_id, func_ea, calcrel_hash, idb_path, input_hash, input_path, all)
    -d--detailsShow details (diff-like) for each change
    None--chronologicalDisplay entries in chronological order (defaults to reverse-chronological).
    -m--max-entries NUMBERmaximum number of entries to fetch (defaults to 100)
    -l--license-id LICENSElicense ID (XX-XXXX-XXXX-XX format) to operate on
    -r--history-id-range RANGEhistory ID range(s) to operate on (start0..end0 [...])
    -t--time-range RANGEtime range to operate on (start..end) see the appendix
    -i--idb IDBIDB name(s) to operate on
    -f--input FILEinput file(s) to operate on
    -u--username USERNAMEusername(s) to operate on
    -n--func NAMEfunction name(s) to operate on
    -h--input-hash HASHinput file hash(es) to operate on
    -p--pushes-id-range RANGEPushes ID range(s) to operate on (start0..end0 [...])
    -c--calcrel-hash HASHfunction hash(es) to operate on
    None--last-changeSelect only the last change for a function (which speeds up execution)

    Examples:

    # Example: List the last 8 changes ("-m 8" specifies the number of changes to show; the default order is reverse-chronological)
    alice@alice_PC$ lc hist show -m 8
    	Change Time                Push Func name                  
    	------ ------------------- ---- ---------------------------
    	507    2022-09-15 14:48:18 5    math_things                
    	506    2022-09-15 14:48:17 4    calc_things (*)            
    	505    2022-09-15 14:48:17 4    start                      
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a
    	503    2022-09-15 14:48:16 3    display_keygen_window      
    	502    2022-09-15 14:48:15 2    fstat                      
    	501    2022-09-15 14:48:15 2    __umoddi3                  
    	500    2022-09-15 14:48:15 2    __udivdi3                  
    	# Shown 8 results (more are available...)
    
    
    # Example: List changes from id 9 up to (but excluding) id 14
    alice@alice_PC$ lc hist show -r9..14
    	Change Time                Push Func name            
    	------ ------------------- ---- ---------------------
    	13     2022-09-15 14:48:05 2    AllocateBucketGroup  
    	12     2022-09-15 14:48:05 2    addr_map_find        
    	11     2022-09-15 14:48:05 2    addr_map_insert      
    	10     2022-09-15 14:48:05 2    addr_map_compare_func
    	9      2022-09-15 14:48:05 2    addr_map_free_func   
    	# Shown 5 results
    
    
    # Example: List changes using multiple ranges (9..14,505..515; in this case, there were no changes after 507 in the database)
    alice@alice_PC$ lc hist show -r9..14,505..515
    	Change Time                Push Func name            
    	------ ------------------- ---- ---------------------
    	507    2022-09-15 14:48:18 5    math_things          
    	506    2022-09-15 14:48:17 4    calc_things (*)      
    	505    2022-09-15 14:48:17 4    start                
    	13     2022-09-15 14:48:05 2    AllocateBucketGroup  
    	12     2022-09-15 14:48:05 2    addr_map_find        
    	11     2022-09-15 14:48:05 2    addr_map_insert      
    	10     2022-09-15 14:48:05 2    addr_map_compare_func
    	9      2022-09-15 14:48:05 2    addr_map_free_func   
    	# Shown 8 results
    
    
    # Example: Find changes from a specific idb file ("-i"), showing the function hash and ea ("-a" adds additional columns to the output)
    alice@alice_PC$ lc hist show -i C:\malware\apts\pc_keygenme_3.pe.idb -a calcrel_hash,func_ea
    	Change Time                Push Func name                   Func EA Func hash                       
    	------ ------------------- ---- --------------------------- ------- --------------------------------
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a 4011e2  420A0485EDB7C6774E1822953FB785D4
    	503    2022-09-15 14:48:16 3    display_keygen_window       401099  ACA673D198FBC0DF24C20A15FF7F25CE
    	# Shown 2 results
    
    
    # Example: Show the first 4 changes ("-m4") with their input file(s) (in "--chronological" order; "-a" adds an additional column)
    alice@alice_PC$ lc hist show --chronological -m 4 -a input_path
    	Change Time                Push Func name             Input path                          
    	------ ------------------- ---- --------------------- ------------------------------------
    	1      2022-09-15 14:47:44 1    .init_proc            /home/alice/work/pc_dwarf_arrays.elf
    	2      2022-09-15 14:47:44 1    _start                /home/alice/work/pc_dwarf_arrays.elf
    	3      2022-09-15 14:47:44 1    __do_global_dtors_aux /home/alice/work/pc_dwarf_arrays.elf
    	4      2022-09-15 14:47:44 1    frame_dummy           /home/alice/work/pc_dwarf_arrays.elf
    	# Shown 4 results (more are available...)
    
    
    # Example: Show the last change by a user ("-u" indicates the user, "-m1" means show 1 change only, "-a" adds an additional column)
    alice@alice_PC$ lc hist show -ubob -m1 -a username
    	Change Time                Push Func name Username
    	------ ------------------- ---- --------- --------
    	502    2022-09-15 14:48:15 2    fstat     bob     
    	# Shown 1 results (more are available...)
    
    
    # Example: Show up to 4 changes ("-m4") between two dates ("-t" indicates a range of "YYYY-MM-DD" dates)
    alice@alice_PC$ lc hist show -m4 -t2022-09-02..2022-12-03
    	Change Time                Push Func name                  
    	------ ------------------- ---- ---------------------------
    	507    2022-09-15 14:48:18 5    math_things                
    	506    2022-09-15 14:48:17 4    calc_things (*)            
    	505    2022-09-15 14:48:17 4    start                      
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a
    	# Shown 4 results (more are available...)
    
    
    # Example: Show up to 4 changes ("-m4") between two "now"-relative dates ("-t", from 2 weeks ago to 5 minutes ago) ("-a" adds an additional column)
    alice@alice_PC$ lc hist show -m4 -t-2w..-5M -a func_id
    	Change Time                Push Func name                   Func ID
    	------ ------------------- ---- --------------------------- -------
    	507    2022-09-15 14:48:18 5    math_things                 506    
    	506    2022-09-15 14:48:17 4    calc_things (*)             506    
    	505    2022-09-15 14:48:17 4    start                       505    
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a 504    
    	# Shown 4 results (more are available...)
    
    
    # Example: Show up to 4 changes ("-m4") between two "now"-relative dates ("-t", from 2 weeks ago to 5 minutes ago) ("-a" adds an additional column), only select the last change for each function
    alice@alice_PC$ lc hist show -m4 -t-2w..-5M -a func_id --last-change
    	Change Time                Push Func name                   Func ID
    	------ ------------------- ---- --------------------------- -------
    	507    2022-09-15 14:48:18 5    math_things                 506    
    	505    2022-09-15 14:48:17 4    start                       505    
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a 504    
    	503    2022-09-15 14:48:16 3    display_keygen_window       503    
    	# Shown 4 results (more are available...)
    
    
    # Example: Show up to 4 changes ("-m4"), occurring after a "now"-relative date ("-t", from 6 hours ago up to now)
    alice@alice_PC$ lc hist show -m4 -t-6H
    	Change Time                Push Func name                  
    	------ ------------------- ---- ---------------------------
    	507    2022-09-15 14:48:18 5    math_things                
    	506    2022-09-15 14:48:17 4    calc_things (*)            
    	505    2022-09-15 14:48:17 4    start                      
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a
    	# Shown 4 results (more are available...)
    
    
    # Example: Show changes about a specific function name ("-n")
    alice@alice_PC$ lc hist show -n print_relocinfo
    	Change Time                Push Func name      
    	------ ------------------- ---- ---------------
    	175    2022-09-15 14:48:08 2    print_relocinfo
    	# Shown 1 results
    
    
    # Example: Show changes about a function name ("-n") searched by wildcard ("like:...")
    alice@alice_PC$ lc hist show -n "like:%reloc%info%"
    	Change Time                Push Func name                 
    	------ ------------------- ---- --------------------------
    	179    2022-09-15 14:48:08 2    print_reloc_information_32
    	178    2022-09-15 14:48:08 2    print_reloc_information_64
    	177    2022-09-15 14:48:08 2    print_relocinfo_32        
    	176    2022-09-15 14:48:08 2    print_relocinfo_64        
    	175    2022-09-15 14:48:08 2    print_relocinfo           
    	# Shown 5 results
    
    
    # Example: Show metadata details ("--details") in changes for a function ("-n"); this particular change added a new function
    alice@alice_PC$ lc hist show -n is_location_form --details
    	Change Time                Push Func name       
    	------ ------------------- ---- ----------------
    	126    2022-09-15 14:48:07 2    is_location_form
    	      >> Score
    	      >>     - 0
    	      >>     + 1445
    	      >> Name
    	      >>     - None
    	      >>     + is_location_form
    	      >> Prototype
    	      >>     - 
    	      >>     + 0C303D08626F6F6C65616E0207
    	      >> Member @ 0x8
    	      >>     .type
    	      >>         - None
    	      >>         + 07
    	      >>     .cmt
    	      >>         - None
    	      >>         + 
    	      >>     .rptcmt
    	      >>         - None
    	      >>         + 
    	      >> Insn operands @ 0+0x3
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	      >> Insn operands @ 0+0x9
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	      >> Insn operands @ 0+0xf
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	      >> Insn operands @ 0+0x15
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	      >> Insn operands @ 0+0x1b
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	      >> Insn operands @ 0+0x21
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	      >> Insn operands @ 0+0x27
    	      >>     - [<no ops repr>]
    	      >>     + [op0=0xb, op1=0x0, op2=0x0, op3=0x0, op4=0x0, op5=0x0, op6=0x0, op7=0x0]
    	# Shown 1 results
    

    hist pushes

    hist pushes [OPTION]

    Shows pushes to the Lumina server.

    Options:

    Short formLong formDescription
    -a--additional-fields LISTComma-delimited list of additional info to display (license_name, license_email, license_id, all)
    -t--time-range TIMESTAMPtimestamp
    -u--username USERNAMEusername(s) to operate on
    -l--license-id LICENSElicense ID (XX-XXXX-XXXX-XX format) to operate on
    -m--max-entries NUMBERmaximum number of entries to operate on (defaults to 100)
    None--chronologicalDisplay entries in chronological order (defaults to reverse-chronological).

    Examples:

    alice@alice_PC$ lc hist pushes 
    	Push ID Time                User name IDB path                                
    	------- ------------------- --------- ----------------------------------------
    	5       2022-09-15 14:48:18 alice     /home/alice/work/pc_math_b_64.elf.i64   
    	4       2022-09-15 14:48:17 alice     /home/alice/work/pc_math_a_64.elf.i64   
    	3       2022-09-15 14:48:16 damian    C:\malware\apts\pc_keygenme_3.pe.idb    
    	2       2022-09-15 14:48:05 bob       /Users/bob/idbs/pc_dwarfdump.elf.idb    
    	1       2022-09-15 14:47:44 alice     /home/alice/work/pc_dwarf_arrays.elf.idb
    	# Shown 5 results
    
    
    # Example: List all pushes from a specific license ID
    alice@alice_PC$ lc hist pushes -l BB-0B0B-AC8E-01 -a license_email
    	Push ID Time                User name License email IDB path                            
    	------- ------------------- --------- ------------- ------------------------------------
    	2       2022-09-15 14:48:05 bob       [email protected]  /Users/bob/idbs/pc_dwarfdump.elf.idb
    	# Shown 1 results
    
    
    # Example: List all pushes from licenses with IDs matching a pattern ("-a" adds an additional column)
    alice@alice_PC$ lc hist pushes -l like:AA-% -a license_id
    	Push ID Time                User name License ID      IDB path                                
    	------- ------------------- --------- --------------- ----------------------------------------
    	5       2022-09-15 14:48:18 alice     AA-A11C-AC8E-01 /home/alice/work/pc_math_b_64.elf.i64   
    	4       2022-09-15 14:48:17 alice     AA-A11C-AC8E-01 /home/alice/work/pc_math_a_64.elf.i64   
    	1       2022-09-15 14:47:44 alice     AA-A11C-AC8E-01 /home/alice/work/pc_dwarf_arrays.elf.idb
    	# Shown 3 results
    
    
    # Example: Show the first push
    alice@alice_PC$ lc hist pushes --chronological -m 1
    	Push ID Time                User name IDB path                                
    	------- ------------------- --------- ----------------------------------------
    	1       2022-09-15 14:47:44 alice     /home/alice/work/pc_dwarf_arrays.elf.idb
    	# Shown 1 results (more are available...)
    
    
    # Example: List all pushes between two timestamps
    alice@alice_PC$ lc hist pushes -t"2022-09-07 10:20:00..2022-12-31"
    	Push ID Time                User name IDB path                                
    	------- ------------------- --------- ----------------------------------------
    	5       2022-09-15 14:48:18 alice     /home/alice/work/pc_math_b_64.elf.i64   
    	4       2022-09-15 14:48:17 alice     /home/alice/work/pc_math_a_64.elf.i64   
    	3       2022-09-15 14:48:16 damian    C:\malware\apts\pc_keygenme_3.pe.idb    
    	2       2022-09-15 14:48:05 bob       /Users/bob/idbs/pc_dwarfdump.elf.idb    
    	1       2022-09-15 14:47:44 alice     /home/alice/work/pc_dwarf_arrays.elf.idb
    	# Shown 5 results
    
    
    # Example: List all pushes from two users ("-a" adds an additional column)
    alice@alice_PC$ lc hist pushes -u"bob damian" -a"license_name license_id"
    	Push ID Time                User name License name License ID      IDB path                            
    	------- ------------------- --------- ------------ --------------- ------------------------------------
    	3       2022-09-15 14:48:16 damian    Damian       DD-DA81-A000-01 C:\malware\apts\pc_keygenme_3.pe.idb
    	2       2022-09-15 14:48:05 bob       Bob          BB-0B0B-AC8E-01 /Users/bob/idbs/pc_dwarfdump.elf.idb
    	# Shown 2 results
    

    hist del

    hist del [OPTION]

    Deletes history and metadata for functions.

    Options:

    Short formLong formDescription
    -s--silentDo not ask for confirmation before deleting history
    -l--license-id LICENSElicense ID (XX-XXXX-XXXX-XX format) to operate on
    -r--history-id-range RANGEhistory ID range(s) to operate on (start0..end0 [...])
    -t--time-range RANGEtime range to operate on (start..end) see the appendix
    -i--idb IDBIDB name(s) to operate on
    -f--input FILEinput file(s) to operate on
    -u--username USERNAMEusername(s) to operate on
    -n--func NAMEfunction name(s) to operate on
    -h--input-hash HASHinput file hash(es) to operate on
    -p--pushes-id-range RANGEPushes ID range(s) to operate on (start0..end0 [...])
    -c--calcrel-hash HASHfunction hash(es) to operate on
    None--last-changeSelect only the last change for a function (which speeds up execution)

    Examples:

    # Example: Display the last 10 changes, with their input file(s) and function ID(s)
    alice@alice_PC$ show -m10 -a input_path
    	Change Time                Push Func name                   Func ID Input path                       
    	------ ------------------- ---- --------------------------- ------- ---------------------------------
    	507    2022-09-15 14:48:18 5    math_things                 506     /home/alice/work/pc_math_b_64.elf
    	506    2022-09-15 14:48:17 4    calc_things (*)             506     /home/alice/work/pc_math_a_64.elf
    	505    2022-09-15 14:48:17 4    start                       505     /home/alice/work/pc_math_a_64.elf
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a 504     C:\malware\apts\pc_keygenme_3.pe 
    	503    2022-09-15 14:48:16 3    display_keygen_window       503     C:\malware\apts\pc_keygenme_3.pe 
    	502    2022-09-15 14:48:15 2    fstat                       502     /Users/bob/idbs/pc_dwarfdump.elf 
    	501    2022-09-15 14:48:15 2    __umoddi3                   501     /Users/bob/idbs/pc_dwarfdump.elf 
    	500    2022-09-15 14:48:15 2    __udivdi3                   500     /Users/bob/idbs/pc_dwarfdump.elf 
    	499    2022-09-15 14:48:14 2    dwarf_get_ADDR_name         499     /Users/bob/idbs/pc_dwarfdump.elf 
    	498    2022-09-15 14:48:14 2    dwarf_get_FRAME_name        498     /Users/bob/idbs/pc_dwarfdump.elf 
    	# Shown 10 results (more are available...)
    
    
    # Example: Delete all changes for functions matching a pattern
    alice@alice_PC$ lc hist del -s -n like:%dwarf%
    	267 entries deleted from history
    
    alice@alice_PC$ hist show -m10 -a input_path,func_id
    	Change Time                Push Func name                   Func ID Input path                       
    	------ ------------------- ---- --------------------------- ------- ---------------------------------
    	507    2022-09-15 14:48:18 5    math_things                 506     /home/alice/work/pc_math_b_64.elf
    	506    2022-09-15 14:48:17 4    calc_things (*)             506     /home/alice/work/pc_math_a_64.elf
    	505    2022-09-15 14:48:17 4    start                       505     /home/alice/work/pc_math_a_64.elf
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a 504     C:\malware\apts\pc_keygenme_3.pe 
    	503    2022-09-15 14:48:16 3    display_keygen_window       503     C:\malware\apts\pc_keygenme_3.pe 
    	502    2022-09-15 14:48:15 2    fstat                       502     /Users/bob/idbs/pc_dwarfdump.elf 
    	501    2022-09-15 14:48:15 2    __umoddi3                   501     /Users/bob/idbs/pc_dwarfdump.elf 
    	500    2022-09-15 14:48:15 2    __udivdi3                   500     /Users/bob/idbs/pc_dwarfdump.elf 
    	474    2022-09-15 14:48:14 2    free_macro_stack            474     /Users/bob/idbs/pc_dwarfdump.elf 
    	468    2022-09-15 14:48:14 2    print_line_detail           468     /Users/bob/idbs/pc_dwarfdump.elf 
    	# Shown 10 results (more are available...)
    
    
    # Example: Delete all changes stemming from a specific file
    alice@alice_PC$ lc hist del -s -f/Users/bob/idbs/pc_dwarfdump.elf
    	228 entries deleted from history
    
    
    # Example: List the changes from pushes 1 to 5 (not included), showing their input file(s)
    alice@alice_PC$ lc show -p1..5 -a input_path
    	Change Time                Push Func name                   Input path                          
    	------ ------------------- ---- --------------------------- ------------------------------------
    	506    2022-09-15 14:48:17 4    math_things                 /home/alice/work/pc_math_a_64.elf   
    	505    2022-09-15 14:48:17 4    start                       /home/alice/work/pc_math_a_64.elf   
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a C:\malware\apts\pc_keygenme_3.pe    
    	503    2022-09-15 14:48:16 3    display_keygen_window       C:\malware\apts\pc_keygenme_3.pe    
    	7      2022-09-15 14:47:44 1    __do_global_ctors_aux       /home/alice/work/pc_dwarf_arrays.elf
    	6      2022-09-15 14:47:44 1    __libc_csu_init             /home/alice/work/pc_dwarf_arrays.elf
    	5      2022-09-15 14:47:44 1    main                        /home/alice/work/pc_dwarf_arrays.elf
    	4      2022-09-15 14:47:44 1    frame_dummy                 /home/alice/work/pc_dwarf_arrays.elf
    	3      2022-09-15 14:47:44 1    __do_global_dtors_aux       /home/alice/work/pc_dwarf_arrays.elf
    	2      2022-09-15 14:47:44 1    _start                      /home/alice/work/pc_dwarf_arrays.elf
    	1      2022-09-15 14:47:44 1    .init_proc                  /home/alice/work/pc_dwarf_arrays.elf
    	# Shown 11 results
    
    
    # Example: Delete one single change
    alice@alice_PC$ lc hist del -s -r505..506
    	1 entries deleted from history
    
    
    # Example: Delete all the changes from push 1
    alice@alice_PC$ lc hist del -s -p 1..2
    	7 entries deleted from history
    
    alice@alice_PC$ hist show -a username
    	Change Time                Push Func name                   Username
    	------ ------------------- ---- --------------------------- --------
    	507    2022-09-15 14:48:18 5    math_things                 alice   
    	506    2022-09-15 14:48:17 4    calc_things (*)             alice   
    	504    2022-09-15 14:48:16 3    keygen_window_dialog_proc_a damian  
    	503    2022-09-15 14:48:16 3    display_keygen_window       damian  
    	# Shown 4 results
    
    
    # Example: Delete all changes by a user
    alice@alice_PC$ lc hist del -s -udamian
    	2 entries deleted from history
    
    alice@alice_PC$ hist show -a func_id
    	Change Time                Push Func name       Func ID
    	------ ------------------- ---- --------------- -------
    	507    2022-09-15 14:48:18 5    math_things     506    
    	506    2022-09-15 14:48:17 4    calc_things (*) 506    
    	# Shown 2 results
    
    
    # Example: Delete the last change for a function
    alice@alice_PC$ lc hist del -s --func math_things --last-change
    	1 entries deleted from history
    
    alice@alice_PC$ hist show -a func_id
    	Change Time                Push Func name   Func ID
    	------ ------------------- ---- ----------- -------
    	506    2022-09-15 14:48:17 4    calc_things 506    
    	# Shown 1 results
    
    
    # Example: Delete all remaining changes for a function by name
    alice@alice_PC$ lc hist del -s --func calc_things
    	1 entries deleted from history
    
    alice@alice_PC$ hist show
    	# Shown 0 results
    

    Various information

    info

    info

    Shows lumina connection information.

    Example:

    alice@alice_PC$ lc info 
    Hex-Rays Lumina Server v8.0
    Lumina time: 2022-08-29 10:13:37, up since 2022-08-21 21:00:05
    MAC address: FF:32:67:FF:D3:00
    Client name: alice *ADMIN*
    Client host: 127.0.0.1
    

    users

    users

    Shows users.

    Example:

    alice@alice_PC$ lc users 
    LastActive Adm Login  License         User name                   Email             
    ---------- --- ------ --------------- --------------------------- ------------------
    2022-08-29 *   bob    XX-XXXX-XXXX-XX bob                         [email protected]
    2022-08-29 *   alice  XX-XXXX-XXXX-XX alice                       [email protected]
    2022-08-27     damian XX-XXXX-XXXX-XX damian                      [email protected]
    

    stats

    stats [OPTION]

    Shows the numbers of functions, pushes, history records, IDBs and input files stored in the Lumina server database.

    Options:

    Short formLong formDescription
    -u--username USERNAMEusername(s) to operate on

    Examples:

    alice@alice_PC$ lc stats 
    	Consolidated statistics from lumina_server:
    	Number of functions: 4
    	Number of pushes: 5
    	Number of history records: 6
    	Number of IDBs: 3
    	Number of input files: 3
    	---------------------------------------------
    
    
    # Example: Retrieve the statistics for a list of users
    alice@alice_PC$ lc stats -ualice,bob,russ
    	Statistics for alice:
    	Number of functions: 2
    	Number of pushes: 3
    	Number of history records: 4
    	Number of IDBs: 1
    	Number of input files: 1
    	---------------------------------------------
    	Statistics for bob:
    	Number of functions: 1
    	Number of pushes: 1
    	Number of history records: 1
    	Number of IDBs: 1
    	Number of input files: 1
    	---------------------------------------------
    

    Administrative commands

    These commands require that the user executing them has admin privileges.

    Managing users

    User management will depend whether the Lumina server is configured to work with its own set of users, or delegating user management to the Teams server.

    In the latter case, you should use the hv command-line tool to administer the Teams server.

    Locally managing users

    The following commands allow the administrator to manipulate users known to the Lumina server (provided of course the Lumina server doesn’t delegate users management to the Teams server)

    user add

    user add USERNAME EMAIL IS_ADMIN LICENSE_ID

    Adds a user.

    The passwd command must be used after creating a user; otherwise the new user will not be able to login to the Lumina server and use it.

    USERNAMEThe username of the user.
    EMAILThe email address of the user.
    IS_ADMINShould be 1 if the user is admin, otherwise 0.
    LICENSE_IDThe license of the user.

    Example:

    alice@alice_PC$ lc user add damiank [email protected] 0 XX-XXXX-XXXX-XX
    

    user edit

    user edit USERNAME EMAIL IS_ADMIN LICENSE_ID

    Edits a user definition.

    USERNAMEThe username of the user to modify.
    EMAILThe email address of the user.
    IS_ADMINShould be 1 if the user is admin, otherwise 0.
    LICENSE_IDThe license of the user.

    Example:

    # Example: For the given username, set the email, admin flag and license ID
    alice@alice_PC$ lc user edit damiank [email protected] 0 XX-XXXX-XXXX-XX
    

    user del

    user del USERNAME EMAIL LICENSE_ID

    Deletes a user.

    USERNAMEThe name of the user to delete.
    EMAILThe email address of the user.
    LICENSE_IDThe license of the user.

    Example:

    alice@alice_PC$ lc user del damiank [email protected] XX-XXXX-XXXX-XX
    

    passwd

    passwd PASS USER

    Modifies the password for a user.

    PASSThe new password.
    USERThe username whose password should be changed Only admins can change other users’ passwords.

    Example:

    alice@alice_PC$ lc passwd secret_password john
    

    Managing sessions

    session list

    session list

    Lists the current connections to the Lumina server. For each connection, the currently executed query (if any) is shown. For each connection, the currently executed query (if any) is shown.

    Example:

    alice@alice_PC$ lc session list 
    id=1642 peer="127.0.0.1", user="...", license="...", e-mail="...", established="2022-08-16 17:13:21"
    current_query="INSERT INTO pushes (fk_idb, fk_user) VALUES (?, ?)" (0msec)
    

    session kill

    session kill ID

    Kills an existing connection to the Lumina server.

    IDThe connection to kill, as shown by the <<cmd_session-list>> command

    Example:

    alice@alice_PC$ lc session list
    id=1 peer="127.0.0.1", user="...", license="...", e-mail="...", established="2022-09-20 16:47:07" current_query="" (0msec)
    alice@alice_PC$ lc session kill 1
    Connection killed
    alice@alice_PC$ lc session list
    No connections.
    

    Concepts

    What is the Lumina server

    The Lumina server is a “functions metadata” repository.

    It is a place where IDA users can push, and pull such metadata, to ease their reverse-engineering work: metadata can be extracted from existing projects, and re-applied effortlessly to new projects, thereby reducing (sometimes dramatically) the amount of time needed to analyze binaries.

    Functions metadata

    The Lumina server associates “function metadata” to functions, by means of a (md5) hash of those functions: whenever it wants to push information to, or pull information from the server, IDA will first have to compute hashes of the functions it wants to retrieve metadata for, and send those hashes to the Lumina server.

    Similarly, when IDA pushes information to the Lumina server, it will first compute hashes for the corresponding functions, extract the metadata corresponding to those from the .idb file, and send those hash+metadata pairs to the server.

    Metadata contents

    Metadata about functions can include:

    • function name
    • function address
    • function size
    • function prototype
    • function [repeatable] comments
    • instruction-specific [repeatable] comments
    • anterior/posterior (i.e., “extra”) comments
    • user-defined “stack points” in the function’s frame
    • the function frame description and stack variables
    • instructions operands representations

    Pushing & overriding metadata

    When a user pushes metadata about a function whose md5 hash isn’t present in the database, the Lumina server will simply create a new record for it.

    However, when a user pushes metadata about a function whose md5 hash (and associated metadata) is already present in the database, the Lumina server will attempt to “score” the quality of the old metadata and the quality of the new metadata. If the score of the new metadata is higher, the new function metadata will override the previous one.

    {% hint style=“info” %} When a user asks IDA to push all functions to the Lumina server, IDA will automatically skip some functions: those that still have a “dummy” name (e.g., sub_XXXX), or that are below a certain size threshold (i.e., 32 bytes) will be ignored. {% endhint %}

    Metadata history

    The Lumina server retains a history of the metadata associated to functions. Using the lc utility, it is possible to dig into that history, and view changes (detailed diffs, too.)

    File contents

    It’s worth pointing out that when pushing metadata to the Lumina server, IDA will not push the binary file itself. Only the following metadata about the file itself will be sent:

    • the name of the input file
    • the name of the IDB file
    • a md5 hash of the input file

    The Lumina server cannot therefore be used as a backup/repository for binary files & IDBs (that is the role of the vault_server)

    Commands

    String patterns

    Options that take strings as inputs can be enhanced through wildcards. The following wildcards are available:

    %
    represents zero, one or multiple characters.

    _
    represents one character.

    To use wildcards in a string, it must be prefixed with like: e.g. -n like:%main%.

    Timerange formats

    For timeranges, the following syntaxes are supported:

    • <ts>..<ts> (from timestamp to (but not including) timestamp)
    • <ts> (only one timestamp)

    Where <ts> can be of the form:

    • yyyy-mm-dd HH:MM:SS: e.g., 2022-09-12 11:38:22
    • yyyy-mm-dd: e.g., 2020-03-12
    • +|-<count><unit>: this is a “now-relative” timestamp, where <unit> must be one of w, d, H, M, S for weeks, days, hours, minutes or seconds respectively. E.g., -4d, +5w, -8H, +1H, …​

    when using the <ts> syntax (i.e., only 1 timestamp is provided, not an actual range), the final range will be either “from now to <ts>”, or “from <ts> to now”, depending on whether <ts> is before, or after, the present time.

    Speed of retrieving changes

    Although it may seem like a simple operation, lc hist show is actually a very demanding one: by default it will have to fetch bits of information from multiple tables (e.g., in order to provide information about which change was superseded by a later one.)

    This can be significantly sped up through the use of --last-change: this option lets the server issue a much simpler query, resulting in significantly reduced processing time.

    Plugins

    IDA’s capabilities can be significantly extended through programmable plugins. These plugins can automate routine tasks, for example, enhance the analysis of hostile code or add a specific functionality to our disassembler.

    Plugins can be developed using:

    • C++ using the IDA SDK, or
    • Python via the IDAPython API.

    Key capabilities:

    • Integration with hotkeys: plugins can be linked to specific hotkeys or menu items for quick access
    • Access to the IDB: they have full access to the IDA database, allowing them to examine or modify the program or use Input/Output functions.

    Where to find plugins

    Development resources

    • Examples included with IDA C++ SDK: Our SDK contains +60 sample plugins, including decompiler plugins (you can find them all inside the SDK directory, in the plugins folder), as well as source code to processor modules, loaders, and header files. You can download the latest version of IDA SDK from HexRaysSA/ida-sdk repository on GitHub.

    Built-in plugins

    • Plugins shipped with your IDA instance: Explore the plugins directory in your IDA installation folder for plugins shipped out-of-the-box. You can run them through Edit -> Plugins submenu or via hotkeys.

    Community plugins

    • Hex-Rays plugins repository: To access a vast collection of community-developed plugins, visit plugins.hex-rays.com.

    HCLI & Plugin Manager

    • You can easily search for, install, and upgrade plugins using the Plugin Manager. During installation, HCLI automatically places plugins in the correct locations, installs required Python dependencies, and handles additional setup tasks.

    Creating your own plugins

    Getting started: Domain API

    If you’re new to IDA and plugin development, the high-level Domain API is the best place to begin. It provides a broad coverage for common tasks and simplifies scripting, helping you get up and running quickly.

    General Domain API Documentation Resources

    Advanced development: C++ and IDAPython SDK

    Do you want to create advanced custom plugins and need more low-level control? Check our tutorials based on the language of your choice:

    Getting Startedhttps://ida-domain.docs.hex-rays.com/getting_started/
    Exampleshttps://ida-domain.docs.hex-rays.com/examples/
    Referencehttps://ida-domain.docs.hex-rays.com/usage/
    Create plugins with C++how-to-create-a-plugin.md
    Create plugins with IDAPythonhow-to-create-a-plugin.md

    Automating Plugin Development with HCLI and GitHub Action

    Use HCLI - the Hex-Rays Command Line Interface to automate your plugin development workflow. Set up a CI workflow for your plugins using the HCLI IDA GitHub Action to download and install IDA Pro automatically and test your plugin across different environments.

    What you can achieve:

    • Cross-platform testing: Test your plugins on Linux, Windows, and macOS
    • Multi-version compatibility: Validate against different IDA Pro versions
    • All dependencies handled: No need for separate Python or uv setup

    What’s next?

    Configure how plugins are loaded with plugins.cfg

    The plugin modules reside in the plugins subdirectory of IDA. IDA is able to find and load all the plugins from this directory automatically. However, you can write a configuration file and tell IDA how to load plugins. To do so, you need to modify the plugins.cfg file in the plugins subdirectory, as described below.

    The plugins.cfg file is needed to customize the plugins, including:

    • appearance of the plugin in the menu
    • the hotkey used to call the plugin
    • the optional argument passed to the plugin

    The format of the plugins.cfg file is simple:

    • Empty lines and lines starting with ‘;’ are comment lines

    • Other lines must have the following structure and fields:

               menu_name filename hotkey arg flags
      

      Example:

               Undefine undef    Alt-U  0
      
    FieldsDescription
    menu_nameA visible name of the plugin. This name will be used in the Edit → Plugins menu. Underscore symbols will be replaced by spaces here.
    filenameThe plugin file name. If the filename doesn’t include the file extension or the directory, IDA will add them.

    Default extensions:
    - Windows: .dll
    - Linux: .so
    - macOS: .dylib

    Note: Plugins compiled with support for 64-bit address space use a 64 suffix before the extension (e.g., pdb64.dll).
    hotkeyA hotkey to activate the plugin
    argAn optional integer argument which will be passed to the run() function of the plugin
    flagsOptional flags. The following values are available:
    - DEBUG: Debugger plugin
    - WIN: Enable plugin for MS Windows
    - MAC: Enable plugin for Mac
    - LINUX: Enable plugin for Linux
    - GUI: Plugin can only be used with GUI version of IDA
    - SILENT: Silently skip nonexisting plugin

    Share your plugin with Hex-Rays community

    Make your plugin compatible with Plugin Manager to improve its discoverability and provide users with seamless installation and management.

    Plugin options

    Plugin options

    The -O command line switch allows the user to pass options to the plugins. A plugin which uses options should call the get_plugin_options() function to get them.

    Since there may be many plugins written by independent programmers, each options will have a prefix -O in front of the plugin name.

    For example, a plugin named "decomp" should expect its parameters to be in the following format:

            -Odecomp:option1:option2:option3
    

    In this case, get_plugin_options("decomp") will return the "option1:option2:option3" part of the options string.

    If there are several -O options in the command line, they will be concatenated with ':' between them.

    List of plugins recognizing '-O' switch

    This switch is not available in the IDA Home edition.

    Plugins Shipped with IDA

    IDA is natively shipped with repository of pre-installed plugins, that are inside plugins directory in your IDA installation folder. Some of these plugins provide essential features such as debugging or decompiler capabilities. These internal plugins are integrated into the IDA environment and cannot be accessed or executed in the same manner as standard built-in plugins.

    Accessing built-in plugins

    Built-in plugins can be accessed through:

    • Menu entries under Edit → Plugins
    • Keyboard shortcuts assigned to specific plugins
    • Specialized submenus

    Plugin tutorials

    Although some of the built-in plugins are quite simple and straightforward in their functionality, the following guides provide detailed instructions for using more advanced plugins:

    Swift plugin

    Demangling

    The swift plugin uses libSwiftDemangle to demangle Swift names. Note that IDA already had a built-in swift demangler, but it was becoming difficult to maintain. In the long-term we hope to fully deprecate IDA’s custom swift demangler in favor of libSwiftDemangle.

    However, the new approach still hasn’t been fully integrated into IDA, so there may be times when IDA’s old swift demangler produces more desirable results.

    ‘cfg/swift.cfg’ file presents all the options

    ‘-Oswift’ command line switches can be used to enable or disable some plugin options.

    List of options

      - <demangler_path> : use specific libSwiftDemangle library
      - -d : use the built-in IDA swift demangler (legacy)
      - +d : use libSwiftDemangle swift demangler
      - -m : don't present metadata in nice way
      - +m : present metadata in nice way
      - -e : don't import enumeration types
      - +e : import enumeration types
      - -s : don't import structure types
      - +s : import structure types
      - -v : don't set variable type based on mangled names
      - +v : set variable type based on mangled names
      - -f : don't set function prototype based on mangled names
      - +f : set function prototype based on mangled names
      - -g : don't group functions in folders corresponding to modules
      - +g : group functions in folders corresponding to modules
    

    Examples

      -Oswift:-g
    

    Do not group functions into folders.

      -Oswift:/tmp/libSwiftDemangle_custom.dylib
    

    Golang plugin

    Golang binaries are by default statically linked and full of metadata therefore a lot can be gained from annotating a Golang binary’s contents using recovered metadata.

    Detection

    The golang plugin’s analysis only happens by default if the input file is detected as a Golang file. There are multiple mechanisms in place to detect that:

     - if a Golang startup signature matches the entry point (PC-only)
     - if the Golang plugin detects a Golang-specific segment name
     - if the elf loader finds a "Go" note in the input file
     - on PE files: if certain Golang symbol names or a Go build id signature is found
    

    Analysis

    The metadata parsed by the golang plugin falls under two main categories:

     - function information (e.g. name, package, range) retrieved from the pclntab
     - type information (e.g. name, package, layout, size) retrieved from the typelinks table
    

    The package paths of functions and types are used to create folders. This analysis will occur upon `ev_newfile` (when a new file has been loaded) if Golang has been detected.

    Actions

      `golang:detect_and_parse` (Edit>Other)
    

    This action is useful to force a full search of the binary for Golang metadata. It will first attempt to parse a pclntab at the current address, if this is unsuccessful it will perform a full search of the binary for the pclntab’s signature and parse it if found. In addition, it will also attempt to locate and parse the type information.

    Calling Conventions

    Golang has its own calling convention(s), denoted in IDA as `__golang`. In fact, Golang has two different calling conventions: a stack-based CC (abi0) and a newer register-based CC (abiinternal). The version of Golang and thus which calling convention to use will be automatically inferred from metadata structures; It is also controllable through the `force_regabi` command line option.

    List of `-Ogolang` options

    Command line options take precedence over config file options.

      force                         try to force the analysis
                                    (no detection step needed)
      off                           disable the plugin
      no_rtypes                     do not import any types
      rname_len2                    force the reflect type name format to go1.17
                                    and later (varint encoding: 1-10 bytes)
      rname_len1                    force the reflect type name format to before
                                    go1.17 (2 bytes)
      import_lnnums                 recover file names & line numbers from pclntab
      no_func_end_from_pcval_tabs   do not derive a function's end from pclntab
                                    metadata
      force_regabi[=on|=off]        override calling convention version
                                     `=off`: will force the stack-based CC
                                     `=on`/no value: will force
                                     the register-based CC
    

    See cfg/golang.cfg for available configuration options.

    Examples

    forcing analysis and register-based calling convention

      -Ogolang:force:force_regabi
    

    disabling the plugin

      -Ogolang:off
    

    Rust plugin

    The binaries produced by the Rust compiler have some peculiarities which make them difficult to analyze, such as:

      - non-standard calling conventions
      - non-terminated string literals
      - unusual name mangling scheme
    

    By default, Rust plugin is enabled if one of the following condition is true

      - one address is named 'rust_begin_unwind'
      - the string 'rustc-' can be found somewhere in the program
        If the segment '.rodata' exists, the search is limited to this segment
    

    String literal analysis

    Rust plugin walks to all addresses in segment with name ending in “__const”, “.rodata” or “.rdata” and creates string literals on xref

      - on dref, the string literal is set up to the next dref
      - on cref, Rust tries to retrieve length from nearby instructions
        Arm, Risc-V and pc proc module benefit from this
    

    To force the string literal detection:

      idaapi.load_and_run_plugin("rust", 1)
    

    Demangling name

    Rust plugin also offers the possibility to configure a demangler library for rust. By default the plugin will use the librustdemangle library that is shipped with IDA. You can disable this feature in ‘Edit>Plugin>Rust language helper’ or specify another library to use.

    See cfg/rust.cfg for the possible options

    List of ‘-Orust’ options

      - on  : enable rust plugin for this session of IDA
      - off : disable rust plugin for this session of IDA
    

    Example

      -Orust:off
    

    This disable the plugin for this session of IDA.

    picture_search

    picture_search is a plugin that allows you to search for, and inspect pictures that are embedded in the binary.

    The key feature of the plugin is the "Search for pictures" action, available in the "Search" menu, that will scan the entire binary (or the selection if there is one) for so-called "magic" numbers of well-known image types (PNG, JPEG, ...), and present the results in a tabular fashion:

                     [Address]         |[Format]
            .noptrdata:0000000000511620|GIF89a
            .noptrdata:00000000005133E0|PNG
            .noptrdata:0000000000517460|JPEG
            .noptrdata:000000000051ADA0|BMP
    

    Note: at this point, pictures have not been decoded yet; the plugin has merely spotted what looks like the start of pictures. Decoding will only happen when triggering any of the following actions.

    Double-clicking any row of that list will show the picture directly in IDA. Opening the context menu will reveal even more possibilities: open the picture in the OS's default viewer, save it, jump to its start address...

    In addition to this very handy scanning feature, the plugin will add the "Open picture" action to the disassembly listing's context menu when the current position happens to be near data that matches the well-known image types' magic numbers.

    Objective-C Analysis Plugin

    The objc plugin performs Objective-C specific analysis on the database.

    For an overview of what the plugin can do, see the menu options in Edit>Other>Objective-C, or the config options in objc.cfg.

    Type Information

    The bulk of the plugin’s work is done at file load time, when it will parse all Objective-C type information embedded in the binary, and use this to create tinfo_t structures for all known classes and construct prototypes for all known methods.

    This analysis can be invoked manually at any time with:

      Edit>Other>Objective-C>Reload Objective-C info
    

    Or:

      idaapi.load_and_run_plugin("objc", 1)
    

    You can also disable objc analysis at load time with command line option:

      -Oobjc:+l
    

    Or check the “Lazy mode” option in:

      Edit>Other>Objective-C>Objective-C Options...
    

    Decompilation

    The plugin will also perform Objective-C analysis during decompilation.

    When a function is decompiled, the plugin will analyze any calls to objc_msgSend, and use the arguments to determine if objc_msgSend will ultimately invoke one of the methods in the current database.

    If such a situation is detected, the plugin will replace the call to objc_msgSend with a call to the target method, and add an xref to the method. This is done in the hopes that continued use of the decompiler will improve call graphs for Objective-C binaries.

    If the target method has type information, then the return type can be used to refine the types of local variables in the pseudocode, which in turn could lead to more method calls being detected, and so on.

    You can disable objc analysis in the pseudocode with command line option:

      -Oobjc:-h
    

    Or uncheck the “Enable decompiler plugin for Objective-C” option in:

      Edit>Other>Objective-C>Objective-C Options...
    

    Debugging

    objc also provides tools for dynamic analysis.

    During debugging, you can analyze objc info for a specific library by right-clicking in the Modules window and selecting “Load debug info”.

    This operation can also be performed programmatically with:

      n = idaapi.netnode()
      n.create("$ objc")
      n.supset(1, "/module/path", 'R')
      idaapi.load_and_run_plugin("objc", 3)
    

    If you prefer that objc does not perform analysis during “Load debug info”, (say if DWARF information is available for a module and you prefer that), you can disable this functionality with command line option:

      -Oobjc:-s
    

    Or by unchecking the “Enable SIP for Objective-C” option in:

      Edit>Other>Objective-C>Objective-C Options...
    

    Step Into Message

    The plugin also implements a “step into” debugger action for Objective-C.

    If you use this action before a call to objc_msgSend, objc will try to calculate the address of method that is being invoked, and break at the method address rather than step into the objc_msgSend function itself.

    You can perform this action with shortcut:

      Shift+O
    

    Or via the menu option:

      Debugger>Run until message received
    

    Or programmatically with:

      idaapi.load_and_run_plugin("objc", 2)
    

    This action can be very useful, but you must be careful. When invoked, the action will automatically run to the address of objc_msgSend, analyze its arguments, then continue to the target method.

    If there is no subsequent call to objc_msgSend in the program, you will lose control of the process. It is best to use this action only when you are sure that IP is in the vicinity of an objc_msgSend call.

    NSConcreteStackBlock

    The objc plugin can also be used to analyze Apple binaries that make heavy use of blocks: https://clang.llvm.org/docs/Block-ABI-Apple.html

    The analysis involves identifying NSConcreteStackBlock instances on the stack, and creating a specialized Block_layout structure to apply to the function’s stack frame.

    The end result transforms the following sequence of statements:

      loc_BF60:                                 Block_layout_BF60 v1;
        v1 = _NSConcreteStackBlock;             v1.isa        = _NSConcreteStackBlock;
        v2 = 0x...;                             v1.flags      = 0x...;
        v3 = 0;                                 v1.reserved   = 0;
        v4 = __block_invoke;             =>     v1.invoke     = __block_invoke;
        v5 = &__block_descriptor_tmp;           v1.descriptor = &__block_descriptor_tmp;
        v6 = ...                                v1.lvar1      = ...
        v7 = ...                                v1.lvar2      = ...
        ...                                     ...
        func(&v1);                              func(&v1);
    

    Already this cleans up the analysis quite a lot, but more importantly this new Block_layout_BF60 structure will be applied to the prototype of __block_invoke, which can heavily improve the pseudocode.

    Block analysis can be performed on the database with:

      Edit>Other>Objective-C>Analyze stack-allocated blocks (entire database)
    

    Or programmatically with:

      idaapi.load_and_run_plugin("objc", 5)
    

    You can also perform block analysis on a specific function:

      Edit>Other>Objective-C>Analyze stack-allocated blocks (current function)
    

    Or with shortcut:

      Ctrl+Shift+S
    

    Or programmatically:

      n = idaapi.netnode()
      n.create("$ objc")
      n.altset(1, 0xBF60, 'R') # the address can be any address within the function
      idaapi.load_and_run_plugin("objc", 5)
    

    These actions work in both the disassembly and pseudocode windows, but note that you must refresh the pseudocode with F5 for the changes to take full effect.

    Also, please note that this feature makes use of the microcode in the hexrays SDK, so you must have the decompiler in order to use it.

    NSConcreteGlobalBlock

    Global blocks (i.e. blocks that don’t make use of local variables) are much easier to analyze, and simply involve identifying references to NSConcreteGlobalBlock in the __const segment.

    Global blocks are analyzed automatically at load time, but the analysis can be performed manually at any time with:

      Edit>Other>Objective-C>Re-analyze global block functions
    

    Or:

      idaapi.load_and_run_plugin("objc", 4)
    

    Command Line

    Here’s a summary of the command-line arguments that can be passed to objc:

    objc features can be enabled or disabled using ‘+’ or ‘-’, followed by one of the following characters:

      v: verbose mode
      s: source info provider
      h: hexrays decompiler analysis
      l: lazy mode
    

    For example, -Oobjc:+v:+l:-s will enable verbose and lazy mode, and will disable the objc SIP.

    See also

    DYLD Shared Cache Utils

    This plugin (nicknamed “dscu” for brevity) is essentially just an extension of the Mach-O loader. It allows you to manually load modules from a dyldcache that were not loaded when first opening the cache in IDA (the plugin is only activated after using the “single module” option for a dyldcache).

    For a quick overview of the dscu functionality, see menu File>Load file>DYLD Shared Cache Utils.

    Loading Modules

    There are a few ways to manually load a module from the cache:

    1) Use File>Load file>DYLD Shared Cache Utils>Load module… and choose which module to load

    2) Right-click on an unmapped address in the disassembly, and select ‘Load module <module name>’

    3) Programatically:

      n = idaapi.netnode()
      n.create("$ dscu")
      n.supset(2, "/usr/lib/libobjc.A.dylib")
      idaapi.load_and_run_plugin("dscu", 1)
    

    Loading Sections

    dscu also allows you to load a subset of a given module.

    Any section from any of the dyldcache’s submodules can be loaded individually. This is especially useful when analyzing Objective-C code, since often times it is convenient to only load Objective-C info from a given module without loading all of its code.

    For example, if you see a pointer to a selector string that has not been loaded:

      ADRP  X8, #0x1AECFF7F9@PAGE
      ADD   X1, X8, #0x1AECFF7F9@PAGEOFF ; SEL
      MOV   X0, X21 ; id
      BL    _objc_msgSend_0
    

    Right-click on “0x1AECFF7F9” and dscu will provide you with two options:

      Load UIKitCore:__objc_methname
      Load UIKitCore
    

    The UIKitCore module is huge, so perhaps you don’t want to load the entire thing, but still want to clean up the disassembly. If you choose “Load UIKitCore:__objc_methname”, dscu will load only these selector strings into the database:

      ADRP  X8, #sel_alloc@PAGE ; "alloc"
      ADD   X1, X8, #sel_alloc@PAGEOFF ; SEL
      MOV   X0, X21 ; id
      BL    _objc_msgSend_0
    

    This operation is much faster, and still provides a lot of benefit to the analysis.

    Sections can also be loaded via:

      File>Load file>DYLD Shared Cache Utils>Load section...
    

    or programmatically with:

      node = idaapi.netnode()
      node.create("$ dscu")
      node.altset(3, 0x1AECFF7F9) # address can be any address in the section
      idaapi.load_and_run_plugin("dscu", 2)
    

    See also

    Borland RTTI descriptors plugin

    Borland RTTI descriptors plugin

    This plugin allows you to create/delete/view Borland RTTI descriptors.

    These descriptors appear in programs written on BCC++ or Borland C++ Builder or Borland Delphi.

    The plugin is available for 32 bits binaries for PE or OMF format.

    Dialog box

      - List RTTI descriptors      : Displays the list of recognized RTTI
                                     descriptors. IDA automatically recognizes
                                     most descriptors. The list will include only
                                     the descriptors specified by the 'RTTI type'
                                     radiobuttons. You can also delete any
                                     descriptor from list.
      - List RTTI problems        :  Displays the list of problematic RTTI
                                     descriptors. The list will include only the
                                     descriptors specified by the 'RTTI type'
                                     radiobuttons. You can also delete any
                                     descriptor from list.
      - Delete list of descriptors : Delete the whole list of RTTI descriptors.
      - Delete list of problems    : Delete the whole list of problematic RTTI
                                     descriptors.
      - Create C++ descriptor      : Manually invoke creation of a C++ descriptor
                                     at the current cursor location.
      - Create Pascal descriptor   : Manually invoke creation of a Pascal
                                     descriptor at the current cursor location.
      - Create Pascal or C++ descriptor : Manually invoke creation of a Pascal or
                                          C++ descriptor at the current cursor
                                          location. This action tries to create a
                                          Pascal descriptor. If it fails, then it
                                          tries to create a C++ descriptor.
    
      - RTTI type radiobutton group : Controls which descriptors will appear in
                                      the displayed lists.
                                      Options are :
                                        * Include C++
                                        * Include Pascal
                                        * Include both
    
       - Create recursive : If this option is set, then IDA tries to create
                            descriptors recursively: if a created descriptor
                            refers to another unknown descriptor, then it will be
                            created and so on.
    

    Configuration

    DWARF plugin

    DWARF plugin

    The DWARF plugin will search for DWARF-encoded debug information either in the input file, or a “companion” file (using a strategy similar to that of GDB), when some is found, will extract the following:

      - type information
      - function names, prototypes, local variables
      - global variables names & types
    

    In addition, the DWARF plugin provides source-level debugging.

    Dialog box

      Global name               : create global names based on DWARF informations
      Functions                 : Create functions based on DWARF informations
      Use function bounds       : Uses DWARF to determine functions boundaries
      Types (uncheck for speed) : Create types, needed for Apply calling
                                  convention or Function prototype are definitive
      Apply calling convention  : DWARF will try and guess the calling convention
                                  instead of using platform default calling
                                  convention. Needed for Allow __usercall
      Allow __usercall          : If DWARF detects __usercall, allow to use it. If
                                  not allowed, the default calling convention for
                                  the platform will be used
      Function prototypes are definitive: Decompiler will not try to change the
                                         prototype if set. Use this with caution
      Import file names/line numbers: Import all information
    

    ‘cfg/dwarf.cfg’ file presents in details all the options

    List of ‘-Odwarf’ options

     - off : disable the plugin for the current session
     - import_lnnums=1 : import file name and line number into idb
    

    Patfind plugin

    Patfind plugin

    Patfind plugin makes it possible to automatically find functions in binary files.

    It relies on bit pattern definitions for typical function starts and function ends.

    Those bit patterns are defined in XML files, based on Ghidra’s function patterns format. A collection of bit pattern files is provided for the commonly used CPU architectures.

    It is possible to add new architectures by simply adding a new XML file, just like the other XML files.

    It’s also possible to add, remove or change existing patterns for better matching.

    Configuration

    ‘cfg/patfind.cfg’ file presents all the options

    The config file also contains the documentation on how to use or change the XML pattern files.

    If desired, new XML files can be added to the ‘cfg/ghidra_patterns/’ directory.

    ‘-Opatfind’ command line switches can be used to select the type of run differently for this session of IDA.

    List of options

      autorun=0 : don't automatically search for bit pattern
      autorun=1 : search for bit pattern only on binary like files
      autorun=2 : search for bit pattern on any input file
    

    Examples

      -Opatfind:autorun=0
    

    IDA Feeds

    IDA Feeds

    {% hint style=“info” %}

    Version Availability

    This feature is available only in IDA Pro, as it depends on idalib for full functionality. {% endhint %}

    Starting with IDA 9.0, we introduced IDA Feeds (aka FLIRT Signature Manager), the tool designed to ease the application of new signatures through updatable libraries (known as IDA FLIRT Signature Bundles), shipped alongside other IDA plugins out-of-the-box. You can run IDA Feeds directly through the IDA Pro UI by navigating to Edit → Plugins → IDA Feeds. All related IDA Feeds files are located in the plugins/ida_feeds directory within your IDA installation folder.

    What is IDA Feeds?

    IDA Feeds helps you identify which signatures to apply when analyzing binary files, especially when you don’t know which static libraries were linked to them. Rather than manually applying signatures, IDA Feeds automatically scans and applies many signatures in seconds. Just open the signature folder, allow IDA to scan and find the possible matches, and then bulk apply the suggested signatures.

    IDA Feeds uses the FLIRT Signature Bundles, which are going to be regularly updated and released to keep you up to date with the newest recognizable signatures.

    Besides managing FLIRT signatures, IDA Feeds can generate Rust signatures on demand.

    IDA Feeds configuration and setup

    You can download the latest IDA FLIRT Signature Bundle from our Download Center in My Hex-Rays portal under SDK and utilities.

    Although IDA Feeds plugin basic options works out-of-the-box, to experience it full functionality, you may need to install some dependencies.

    Requirements and dependencies

    • idalib configured properly (check idalib installation and activation steps) if you want to use fully functional IDA Feeds plugin (including parallel probing and generating Rust signatures) or run IDA Feeds as a standalone app
    • RPyc 5.x for parallel probing
    • Rust installed, if you want to generate Rust signatures
    • Path to flair Correctly settled in the config.json file inside your ida_feeds folder

    Check readme file inside ida_feeds folder for detailed info.

    Installing requirements/dependencies (optional)

    Install requirements for Python modules in the interpreter that IDA is using or from within your virtual environment (venv).

    1. Navigate to the plugin/ida_feeds folder within the IDA Pro installation directory and install the requirements.
    python3 -m pip install -r requirements.txt
    
    1. Create symbolic link (optional)

    Linux & OSX

    ln -s $(pwd) $HOME/.idapro/plugins/ida_feeds
    

    Windows

    mklink /D "%APPDATA%\Hex-Rays\IDA Pro\plugins\ida_feeds" "%cd%"
    

    How to use IDA Feeds plugin?

    1. Go to the Edit -> Plugins -> IDA Feeds. IDA Feeds will open in a new IDA Feeds subview.
    2. In the Signature Tools window, click Open signatures folder and select the folder with the downloaded FLIRT signature bundle (1), or leave the preloaded signatures already provided with your IDA instance.

    1. Select chosen signature files, pick the type of probing from the dropdown menu: Parallel probing or Sequential probing (2), and then click Run probe (3) to match functions in the binary against a specific selected signature file(s).

    {% hint style=“info” %}

    Parallel vs Sequential Probing

    Parallel probing runs multiple probing processes on the copies of IDB, and although is faster, it’s also more resource intensive. It requires idalib, idapro module and RPyC 5.x to work. Parallel type is available only when all prerequisites and dependencies are correctly installed. If any are missing, you can still use Sequential probing as a slower alternative. {% endhint %}

    1. Check the results and click Apply signatures to bulk apply (4) correct matches to selected signatures.

    Creating Rust signatures

    Dependencies

    • idalib with idapro module installed
    • Correctly settled a path to flair in the config.json file inside your ida_feeds folder
    1. Go to the Edit -> Plugins -> IDA Feeds. In the IDA Feeds subview, navigate to the folder tree view (Signatures panel) on the left and find FLIRT for Rust libraries at the bottom of the view.
    2. Click Create and apply signature.

    1. After generation:

    you can find the .sig file in your .idapro/cache/rust folder.

    FAQ

    Signature bundles versus standard IDA sig files

    • Q: What’s the difference between signatures shipped with IDA installer (in the sig folder) and FLIRT signatures bundle?

    IDA comes with a set of standard FLIRT signatures, which you can find in the sig folder in the IDA installation directory.

    The signature bundles for IDA FEEDS (downloadable from My Hex-Rays portal) provide additional signatures to improve function recognition for various libraries and frameworks. What’s more, these bundles are available with additional metadata files that may enhance your analysis.

    • Q: Should I place the additional signatures, like these from the FLIRT signature bundles, always in the sig folder?

    It’s up to you whether to keep some signatures separate or store them in the sig folder inside IDA installation directory.
    Placing them in the sig folder makes them available globally for all IDBs opened in IDA and pre-loaded whenever you run the IDA Feeds plugin. It can be convenient if you usually work with the same set of libraries, but it can clutter the space if you don’t need all signatures handy all the time.

    Signature bundles types

    • Q: What is the difference between signature bundle with metadata and the one without?

    The signature bundle with metadata contains a txt file for each signature (.sig file) that explains in details what is inside that particular signature (listing libraries and versions). If this information is useful for your analysis, opting for bundles with metadata can be beneficial. However, if you don’t require these details for your regular reverse engineering tasks, you may prefer a more lightweight bundle without metadata.

    Troubleshooting

    Creating Rust signatures is unavailable

    Check the rust compiler version

    Your binary/executable may be compiled with a rust compiler that is not known by IDA Feeds, meaning that it is not included in the rust-git-tags.json file in ida-feeds folder. Before you proceed, verify that the rust compiler version is present in rust-git-tags.json.

    Debugging other issues

    When you encounter unexpected errors, set IDA_FEEDS_LOG_LEVEL environment variable to DEBUG, and then restart IDA and try again to obtain additional information from the Output Window.

    FLIRT Signature Bundle

    With FLIRT Signature Bundle, designed to be used with IDA Feeds (aka FLIRT Signature Manager), you can analyze thousands of signatures and bulk apply them to your binary.

    The bundle contains signatures for modern languages like Golang and Rust, as well as updates for classic compilers. The latest version of the FLIRT Signature Bundle can be downloaded from My Hex-Rays portal under SDK and utilities.

    Flirt Signature Bundles will be regularly updated and released independently whenever there is a new compiler, language, or library release.

    Released versions

    FLIRT Signature Bundle 9.1

    The packages are updated with the latest language versions.

    FLIRT Signature Bundle 9.0sp1

    Since 9.0SP1, alongside standard bundles, we have released FLIRT Signature Bundles with metadata. The packages are updated with the latest language versions.

    2024/09/12 FLIRT Signature Bundle 9.0

    Packages

    Golang

    • Versions: stable versions from 1.10.0 to 1.23
    • Operating Systems: Linux, Windows, MacOS
    • Architectures: arm64 (Windows, Linux, MacOS), arm (Windows, Linux, MacOS), x86 (Windows, Linux) , x86-64 (Windows, Linux)

    C/C++

    • Windows (MSVC):
      • Architectures: arm, arm64, i386, amd64
      • Packages: ATL, CTL, MFC, Windows SDK 10, Windows SDK 11
    • Linux:
      • Distribution: Ubuntu & Debian
      • Architectures: i386, amd64, arm64, armhf, armel, arm, s390x, mips64el, mipsel, mips, ppc64el
      • Packages: libc6, libselinux1, libpcre2, libidn2, libssl, zlib1g, lib32z1, libunistring, libcurl4-gnutls, libcurl4-nss, libcurl4-openssl, libnghttp2, libidn2, librtmp, libssh, libssh-gcrypt, libpsl, libldap, libzstd, libbrotli, libgnutls28, nettle, libgmp, comerr, libsasl2, libbrotli, libtasn1-6, libkeyutils, libffi, uuid, libprotobuf, heimdal-multidev, musl, libplib, libsdl1.2-bundle (libsdl-console, libsdl-sge, libsdl1.2, libsdl-ocaml, libsdl-image1.2, libsdl-kitchensink, libsdl-mixer1.2, libsdl-net1.2, libsdl-sound1.2, libsdl-ttf2.0, libsdl1.2-compat, libsdl-gfx1.2, libsdl-pango), libsdl2-bundle (libsdl2, libsdl2-gfx, libsdl2-image, libsdl2-mixer, libsdl2-net, libsdl2-ttf)

    Rust

    • Versions 1.77 to 1.81
      • Architectures: arm64, arm, x86, x86-64
      • Operating Systems: Linux, Windows, MacOS
      • Compilers: GCC, LLVM, MSVC

    Publishing your plugins

    {% hint style=“success” %}

    Introducing IDA Plugin Manager - Goodbye Manual Submissions

    With the introduction of HCLI and the IDA Plugin Manager, we’ve built a new ecosystem for discovering, installing, and managing IDA plugins — all distributed through a central index in the IDA Plugin Repository. The plugins.hex-rays.com remains available for browsing and showcasing plugins, but the previous manual submission process via the My Hex-Rays portal has been retired. {% endhint %}

    Make Your Plugin Compatible with HCLI & Plugin Manager

    The key points to make your IDA plugin available via IDA Plugin Manager are:

    • Update/create ida-plugin.json
    • Package your plugin into a ZIP archive
    • Publish releases on GitHub

    Refer to the HCLI Plugin Manager Publication Guide for detailed steps, examples and process description.

    Plugin Manager & HCLI Basic Documentation Resources

    New to HCLI or the Plugin Manager? Start here to get up and running quickly. These resources are perfect for IDA users who want to browse, install, and manage plugins efficiently.

    Getting Started with HCLIhttps://hcli.docs.hex-rays.com/getting-started/installation/
    Plugin Manager Overviewhttps://hcli.docs.hex-rays.com/user-guide/plugin-manager/

    Plugin Development Documentation Resources

    Are you a plugin author looking to make your plugin compatible with HCLI and the Plugin Manager? Explore these detailed guides to learn how to prepare, package, and publish your plugin in the new ecosystem.

    Repository Architecturehttps://hcli.docs.hex-rays.com/reference/plugin-repository-architecture/
    Plugin Packaging Formathttps://hcli.docs.hex-rays.com/reference/plugin-packaging-and-format/
    Publishing Your Pluginhttps://hcli.docs.hex-rays.com/reference/packaging-your-existing-plugin/

    Pre-submission checklist

    Before publishing your plugin to the IDA Plugin Repository, make sure it’s fully compatible with HCLI and the Plugin Manager - read the testing guide.

    Define plugin metadata with ida-plugin.json

    {% hint style=“info” %}

    Updated fields

    We’ve added new required and optional fields to ensure compatibility with HCLI and IDA Plugin Manager. See the details and examples here. {% endhint %}

    The ida-plugin.json it’s essential to ensure your plugin will be available in the IDA Plugin Repository and discoverable through Plugin Manager.

    To work properly, the ida-plugin.json file must contain at the very least the IDAMetadataDescriptorVersion field as well as a plugin object containing the fields described below.

    Example of the minimal ida-plugin.json file:

    {
      "IDAMetadataDescriptorVersion": 1,
      "plugin": {
        "name": "plugin1",
        "version": "1.0.0",
        "entryPoint": "plugin1.py",
        "urls": {
          "repository": "https://github.com/your-org/your-plugin"
        },
        "authors": [{
          "name": "John Smith",
          "email": "[email protected]"
        }]
      }
    }
    
    

    Check further examples in the HCLI Plugin Manager Docs.

    Required Fields Description

    FieldDescription
    .plugin.nameThe name will be used to identify the plugin and also generate a namespace name for it if necessary (e.g., an IDAPython plugin). The namespace name is generated by converting all non alphanumeric characters of the plugin name to underscores (_) and prepending __plugins__ to it. For example “my plugin” would become __plugins__my_plugin.
    .plugin.entryPointThe filename of the “main” file for the plugin. It should be stored in the same directory as its ida-plugin.json file. If the entryPoint has no file extension, IDA will assume it is a native plugin and append the appropriate file extension for dynamic shared objects for the host platform (.dll, .so, .dylib). For IDAPython plugins, this should typically be a .py file (e.g., my-first-plugin.py).
    .plugin.versionSpecify the version of your plugin. It must follow the x.y.z format (e.g., 1.0.0).
    .plugin.descriptionSummarize your plugin functionality.
    .plugin.urls.repositoryLink to your plugin’s public GitHub repository
    plugin.authors and/or plugin.maintainers- At least one must be provided. Each entry requires name and email.

    Optional Fields Description

    FieldDescription
    plugin.descriptionSummarize your plugin functionality.
    plugin.idaVersionsDeclare which versions of IDA your plugin supports. You can specify a single version (e.g., 9.0) or a version range (e.g., >=9.0) using the semantic versioning scheme.
    plugin.platformsSupported platforms. Defaults to all if not specified. Values: windows-x86_64, linux-x86_64, macos-x86_64, macos-aarch64
    plugin.licenseSPDX license identifier (e.g., “MIT”, “GPL-3.0”, “Apache-2.0”)
    plugin.logoPathInclude an image to visually represent your plugin on its page at plugins.hex-rays.com. This should be a relative path to an image file within your plugin’s repository. The recommended aspect ratio for the image is 16:9.
    plugin.categoriesSelect at least one category to improve your plugin’s discoverability: disassembly-and-processor-modules, file-parsers-and-loaders, decompilation, debugging-and-tracing, deobfuscation, collaboration-and-productivity, integration-with-third-parties-interoperability,api-scripting-and-automation, ui-ux-and-visualization, malware-analysis, vulnerability-research-and-exploit-development, other
    plugin.keywordsSearch terms to improve discoverability.
    plugin.pythonDependenciesPyPI packages to install (e.g., ["requests>=2.28.0", "package-name"]).
    plugin.settingsConfiguration options as a list of descriptors of settings.

    FAQ

    Make your plugin HCLI and Plugin Manager ready - check out our FAQ for guidance and practical tips.

    Migrating PyQt5 Code to PySide6

    Starting from version 9.2, IDA has moved from Qt5 to Qt6. For more details, see the IDA 9.2 Release Notes

    IDA VersionQt VersionPython Qt Bindings
    ≤ 9.1Qt5PyQt5
    9.2Qt6PySide6

    PyQt5 vs PySide6

    • Different module names; from PyQt5 import QtWidgets will no longer work in PySide6.
    • Differences in Qt libraries themselves

    As a result, some existing user scripts may require adjustments. That’s why we prepare PyQt5 shims to ease your transition.

    PyQt5 Shims

    We have introduced a compatibility layer, called “PyQt5 shims, to support a smooth transition for existing scripts relying on PyQt5.

    These shims:

    • provide PyQt5.* Python modules
    • behind the scenes, re-route calls to PySide6 (Qt6) and perform additional handling to ensure compatibility

    The goal is to let your existing PyQt5-based code continue running as it should.

    {% hint style=“info” %} Although these shims aim to ease the transition, please note that they have limitations. We recommend porting existing code to PySide6, or using an abstraction layer such as QtPy. {% endhint %}

    Enabling/Disabling the Shims

    On the first attempt to import PyQt5 (either directly or through a plugin), IDA will display a popup dialog asking whether to enable/disable PyQt5 shims.

    Shims confirmation dialog

    No manual editing is required - simply respond to the prompt.

    Your choice will be saved in the configuration file:

    • Windows: %APPDATA%\Hex-Rays\IDA Pro\cfg\idapython.cfg
    • Linux/macOS: ~/.idapro/cfg/idapython.cfg

    The paths depend on IDAUSR.

    After making a choice, IDA will:

    • Print a message in the Output Window
    • Inform you of the updated configuration path
    • Remember your choice and not prompt you again

    Changing the Shims Preferences

    You can edit cfg/idapython.cfg at any time to change the configuration.

    To enable PyQt5 shims:

    #if __IDAVER__ >= 920
    IDAPYTHON_USE_PYQT5_SHIM = 1
    #endif
    

    To disable PyQt5 shims:

    #if __IDAVER__ >= 920
    IDAPYTHON_USE_PYQT5_SHIM = 0
    #endif
    

    {% hint style=“info” %} The #if __IDAVER__ >= 920 directive ensures that the configuration is ignored by older versions of IDA. However, this is unnecessary if you update idapython.cfg directly within the IDA installation directory. {% endhint %}

    Additional Resources

    Known Limitations

    • QRegExp:

      • PyQt5.QtCore.QRegExp is deprecated in Qt6
      • There has already been a replacement - PyQt5.QtCore.QRegularExpression
      • QRegExp and QRegularExpression are incompatible. They differ in methods and the pattern syntax. See Qt porting guide for more details.
    • QFontDatabase:

      • PyQt5.QtGui.QFontDatabase and PySide6.QtGui.QFontDatabase differ in the declaration of static methods and in derived methods available on QFontDatabase instances
      • It is marked as deprecated in Qt6

    Helper Tools

    Helper tools, also known as utilities, are small programs designed to enhance your IDA functionality. Since IDA 9.1, most of these utilities are shipped alongside IDA and included with the IDA installation.

    Built-in tools

    You can find these tools in the tools folder inside the main IDA installation directory:

    • Flair: allows to add your own compiler libraries to the FLIRT engine
    • IDAClang: a command line version of IDAClang plugin
    • idsutils: helps create/maintain IDS files from DLLs
    • loadint: creates your own disassembler comment databases
    • Tilib: creates type libraries (til files) for IDA

    idat tools

    In addition to the tools listed above, IDA includes utilities used by idat, such as TVision.

    Additional tools in the Download Center

    The IDA PIN tool is available for download in the My Hex-Rays Portal.

    Additionally, the Download Center provides utilities for older IDA versions (prior to 9.1).

    How to use these tools?

    For detailed usage instructions and tips, refer to the README files located in each tool’s folder.

    idalib

    IDA as a library (idalib) allows you to use the C++ and IDA Python APIs outside IDA as standalone applications. That way, IDA’s engine is used inside your app, which simplifies development with the IDA APIs, which can be done now from your IDE of choice.

    Prerequisites

    • IDA Pro 9.0 or newer installed and running

    Installation for C++

    To use the ida library from the C++, please refer to the idalib.hpp header file shipped with C++ SDK where you will find the relevant information.

    Installation for Python

    To use the ida library Python module, you need to install and configure idapro package by following these steps:

    Install ida library Python module

    1. Navigate to the idalib/python folder within the IDA Pro installation directory
    2. Run the command: pip install .

    {% hint style=“info” %} When setting up idalib to work with IDA Feeds and your virtual environment (venv), make sure to run the above command from within your activated venv. {% endhint %}

    Setting up the ida library Python module

    Run the Activation Script

    1. You need to inform the idapro Python module of your IDA Pro installation. To do this, run the py-activate-idalib.py script located in your IDA Pro installation folder, or inside the idalib/python folder (depends on the system version you use):

      python /path/to/IDA/installation/py-activate-idalib.py [-d /path/to/active/IDA/installation]
      

      If the -d option is omitted, the script will automatically select the IDA installation folder from which it was executed.

    Using the ida library Python module

    Import idapro in your script

    1. Make sure to import the idapro package as the first import in your Python script
      • After importing, you can utilize the existing ida Python APIs

    Example script

    For a reference on how to use the ida module, check the idalib/examples folder in your IDA Pro installation directory or look at the sample script provided below.

    #!/usr/bin/env python3
    import argparse
    import os
    import json
    import idapro
    from pathlib import Path
    import ida_segment
    import ida_idaapi
    import ida_funcs
    import ida_idp
    import ida_auto
    import ida_undo
    
    
    
    class sig_hooks_t(ida_idp.IDB_Hooks):
    
        def __init__(self):
            ida_idp.IDB_Hooks.__init__(self)
            self.matched_funcs = set()
    
        def func_added(self, pfn):
            self.matched_funcs.add(pfn.start_ea)
    
        def func_deleted(self, func_ea):
            try:
                self.matched_funcs.remove(func_ea)
            except:
                pass
    
        def func_updated(self, pfn):
            self.matched_funcs.add(pfn.start_ea)
    
        def idasgn_loaded(self, sig_name):
            return print(f"Sig {sig_name} loaded")
    
        def dump_matches(self):
            for fea in self.matched_funcs:
                print(f"Matched function {ida_funcs.get_func_name(fea)}")
    
    
    ### List the segments for the loaded binary
    def list_segments():
        nb_items = ida_segment.get_segm_qty()
        print("Segments number:",  nb_items)
        for i in range(0, nb_items):
            seg_src = ida_segment.getnseg(i)
            print(str(i+1) + ".")
            print("\tname:", ida_segment.get_segm_name(seg_src))
            print("\tstart_address:", hex(seg_src.start_ea))
            print("\tend_address", hex(seg_src.end_ea))
            print("\tis_data_segment:", ida_segment.get_segm_class(seg_src) == ida_segment.SEG_DATA)
            print("\tbitness:", seg_src.bitness)
            print("\tpermissions:",  seg_src.perm, "\n")
    
    ### Just call an existing python script
    def run_script(script_file_name:str):
        if not os.path.isfile(script_file_name):
            print(f"The specified script file {script_file_name} is not a valid python script")
            return
        ida_idaapi.IDAPython_ExecScript(script_file_name, globals())
    
    
    ### Apply provided sig file name
    def apply_sig_file(database_file_name:str, sig_file_name:str, sig_res_file:str):
        if not os.path.isfile(sig_file_name):
            print(f"The specified value {sig_file_name} is not a valid file name")
            return
    
        root, extension = os.path.splitext(sig_file_name)
        if extension != ".sig":
            print(f"The specified value {sig_file_name} is not a valid sig file")
            return
    
        # Install hook on IDB to collect matches
        sig_hook = sig_hooks_t()
        sig_hook.hook()
    
        # Start apply process and wait for it
        ida_funcs.plan_to_apply_idasgn(sig_file_name)
        ida_auto.auto_wait()
    
        matches_no = 0
        for index in range(0, ida_funcs.get_idasgn_qty()):
            fname, _, fmatches = ida_funcs.get_idasgn_desc_with_matches(index)
            if fname in sig_file_name:
                matches_no = fmatches
                break
    
        matches = {
            "total_matches": matches_no,
            "matched_functions": []
        }
    
        for fea in sig_hook.matched_funcs:
            matches['matched_functions'].append({ "func_name": ida_funcs.get_func_name(fea), "start_ea": hex(fea) })
    
    
        with open(sig_res_file, 'w') as jsonfile:
            json.dump(matches, jsonfile, indent=2)
    
        print(f"Total matches {matches_no} while applying {sig_file_name} on {database_file_name}, saved results to {sig_res_file}")
    
    ### Internal string to bool converter used for command line arguments
    def str_to_bool(value:str):
        if isinstance(value, bool):
            return value
        if value.lower() in {'false', 'f', '0', 'no', 'n'}:
            return False
        elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
            return True
        raise ValueError(f'{value} is not a valid boolean value')
    
    # Parse input arguments
    parser=argparse.ArgumentParser(description="IDA Python Library Demo")
    parser.add_argument("-f", "--file", help="File to be analyzed with IDA", type=str, required=True)
    parser.add_argument("-l", "--list-segments", help="List segmentes", type=str_to_bool, nargs='?', const=True, default=False)
    parser.add_argument("-s", "--script-file-name", help="Execute an existing python script file", type=str, required=False)
    parser.add_argument("-g", "--sig-file-name", help="Provide a signature file to be applied, requires also -o", type=str, required=False)
    parser.add_argument("-o", "--sig-res-file", help="Signature file applying result json file, works only together with -g", type=str, required=False)
    parser.add_argument("-p", "--persist-changes", help="Persist database changes", type=str_to_bool, nargs='?', const=True, default=True)
    
    args=parser.parse_args()
    
    if (args.sig_file_name is not None and args.sig_res_file is None) or (args.sig_file_name is None and args.sig_res_file is not None):
        print("error: '-g/--sig-file-name' and '-o/--sig-res-file' arguments must be specified together or none of them.\n")
        parser.print_help()
        exit(-1)
    
    # Run auto analysis on the input file
    print(f"Opening database {args.file}...")
    idapro.open_database(args.file, True)
    
    # Create an undo point
    if ida_undo.create_undo_point(b"Initial state, auto analysis"):
        print(f"Successfully created an undo point...")
    else:
        print(f"Failed to created an undo point...")
    
    # List segments if required so
    if args.list_segments:
        print("Listing segments...")
        list_segments()
    
    # Run a script if one provided
    if args.script_file_name is not None:
        print(f"Running script {args.script_file_name}...")
        run_script(script_file_name=args.script_file_name)
    
    # Apply signature file if one provided
    if args.sig_file_name is not None:
        print(f"Applying sig file {args.sig_file_name}...")
        apply_sig_file(database_file_name=args.file, sig_file_name=args.sig_file_name, sig_res_file=args.sig_res_file)
    
    # Revert any changes if specified so
    if not args.persist_changes:
        if ida_undo.perform_undo():
            print(f"Successfully reverted database changes...")
        else:
            print(f"Failed to revert database changes...")
    
    # Let the idb in a consistent state, explicitly terminate the database
    print("Closing database...")
    idapro.close_database()
    print("Done, thanks for using IDA!")
    

    Third-Party Licenses

    Apache License for Ghidra

    Apache License for LLVM

    Common Public License Version 1.0

    APPLE PUBLIC SOURCE LICENSE

    PCRE2 LICENCE

    GNU Lesser General Public License v2.1 for libiberty

    Floating licenses

    Introduction to IDA floating licenses

    Floating licenses allow organizations with multiple IDA users to install IDA across many different machines while limiting the number of concurrent IDA active sessions. One floating license (or one floating license seat, if multiple seats are available) permits one concurrent use of IDA Pro. The licenses are managed by a Hex-Rays license server.

    {% hint style=“info” %} To use floating licenses, IDA needs to maintain a permanent connection to your organization’s license server, but you can borrow licenses to work offline. {% endhint %}

    Users don’t need to store license files locally on their machines while using floating licenses.

    Core concepts

    One server, different IDA licenses

    You can have several IDA Pro licenses available on the same license server, each with a different set of decompilers assigned.
    You can switch between those licenses depending on your needs (e.g. the architecture of the file you’re working on).

    Seats and seat allocation

    A “seat” represents an active session of IDA for the user+machine pair.
    If your IDA Pro license has 3 seats available, it means that up to 3 different users or machines can run IDA at the same time.
    When you open IDA, the License Manager displays all available licenses and their number of seats.
    One seat is taken (checked out) from the pool when you start working with a file in IDA.
    When you close IDA, the seat is released back to the pool for others to use.

    {% hint style=“info” %} When you run multiple instances of IDA on the same computer, only one seat is used up from the license pool on the server. {% endhint %}

    License check-out

    Checking out the license allows the user to work with IDA (maintaining an active IDA session), while keeping a connection to the license server. IDA Pro checks out a license when launched and returns it when closed.

    License borrowing

    Borrowing allows the user to check out the license for a fixed period and work offline (without connection to the license server). At the end of the borrow period, the license is released automatically by the server and returned to the common license pool.

    Activation, installation and setup

    What steps are required to enable floating licenses?

    Admin level:

    1. Activate your license server license and your IDA instance at My Hex-Rays Portal. Download your license files locally, as well as the server installer -> check Licensing Guide
    2. Install and set up your license server -> see Admin Guide.
    3. Install IDA Pro on your workstations -> read how to install IDA
    4. Provide your users with a license server hostname

    User level:

    1. Run IDA on your machine and check out one of the available license to start working

    How to check out a license?

    1. Connect to the network where your license server is available and run IDA.
    2. Navigate to Help -> License manager.
    3. In the License manager dialog, select the option Use floating license server and then type the license server hostname provided by your administrator. Click Connect (1).

    Check out a license

    1. Check out one of the licenses: select a license visible under the available licenses list and click OK (2). You can continue working with IDA now.
    2. When you exit IDA, the license will be automatically checked in (returned to the server) and becomes free to use for another user/session.

    Offline usage and license borrowing

    Floating licenses can function in air-gapped environments, as long as the license server is placed inside that isolated network.
    This setup is ideal for users working on-site in a specific physical location. For offsite use, you must borrow a license in advance to access it offline or in a different, remote location.

    How to borrow a license?

    Borrow a license to temporarily “check it out” and use IDA without connection to the license server for a fixed period of time.

    If your selected IDA license has multiple seats available, borrowing the license temporarily check-out only one of the available seats.

    1. Connect workstation to the network with your license server. Run IDA and go to Help -> License manager.
    2. In the License manager dialog, right click on the selected license to open a context menu and click Borrow license….

    Borrow a license

    1. In the Borrow or return a license dialog, specify the borrow period end date and click OK.

    Specify the end period\

    1. You should see the confirmation dialog that the license was successfully borrowed, as well as info in the Output window.

    Confirmation dialog\

    1. Right now, you can disconnect with the server and work offline.

    Once borrowed, the license remain checked out. That means it stays unavailable for others until the end of the borrow period or explicit manual return.

    Returning a borrowed license early

    Normally, there is no need to return the borrowed license explicitly as it will be returned to the server pool automatically at the end of the borrow period.
    However, you can return a borrowed license earlier than its declared end date to free it up for other users.

    1. Reconnect to the network with your license server.
    2. Go to Help -> License manager.
    3. In the License manager dialog, right-click on the selected license to open a context menu and click Return license.

    Return a license

    1. In the Output window, you should see the notification about successfully returned IDA license.

    You can seamlessly continue your work after returning a borrowed license, as it will automatically be checked out for online use from the server in the background.

    Key notes:

    • Borrowing reduces the number of available floating license seats.
    • After the borrowing period ends, the license automatically returns to the server.
    • Be mindful of the borrowing duration, as it locks that license/seat for the entire period, even if you no longer need it.
    • You can return the license manually before the fixed period but only while connected to the network with the license server.

    FAQ

    How can I know who’s occupying the seats?

    If all seats are occupied, regular users cannot directly see who is using them. To get details about active users, your administrator can use the lsadm tool shipped with the server.

    Developer Guide

    Welcome to the Hex-Rays Developer Guide, where you can learn how to enhance IDA’s capabilities and extend its features.

    Whether you’re new to IDA development or an experienced reverse engineer, our tools and documentation are designed to help you extend IDA’s capabilities to match your needs.

    Beginner Development Path

    Domain API

    Our beginner-friendly Domain API is designed for faster scripting and offers an easy entry point, perfect for those who value simplicity over complexity.

    Advanced Development Path

    C++ and IDAPython SDK Fundamentals

    For advanced use cases requiring low-level control, explore our C++ and IDAPython SDK, open source and available on GitHub. Begin your journey by learning about core concepts and exploring common examples relevant to your language of choice.

    Getting Startedhttps://ida-domain.docs.hex-rays.com/getting_started/
    Exampleshttps://ida-domain.docs.hex-rays.com/examples/
    Referencehttps://ida-domain.docs.hex-rays.com/usage/
    Start using C++ SDKC++c++
    Start using IDAPython SDKPythonIDAPython

    C++ and IDAPython SDK Reference Documentation

    Refer to our detailed C++ and IDAPython SDK documentation for a complete overview of available modules and functions.

    C++ referencehttps://cpp.docs.hex-rays.com
    IDAPython referencehttps://python.docs.hex-rays.com/

    Domain API

    A beginner-friendly, open-source Domain API that simplifies scripting and plugin development, making it approachable like never before — in a Pythonic way.

    {% hint style=“success” %}

    v0.1.0 Released

    This initial release focuses on core reversing concepts and provides a foundation for future evolution and collaboration with the community. {% endhint %}

    General Documentation Resources

    Getting Startedhttps://ida-domain.docs.hex-rays.com/getting_started/
    Exampleshttps://ida-domain.docs.hex-rays.com/examples/
    Referencehttps://ida-domain.docs.hex-rays.com/usage/

    Additional Resources

    PyPI Packagehttps://pypi.org/project/ida-domain/
    Source Code on GitHubhttps://github.com/HexRaysSA/ida-domain

    Is the Domain API Right for You?

    Just getting started with IDA?

    Great! The Domain API was specifically designed to flatten the learning curve. We made this high-level Domain API more Pythonic, easy to install and simpler to learn so you can start scripting and building IDA plugins without getting overwhelmed by complexity.

    As an open-source project designed to complement IDAPython SDK, it benefits from a faster release cycle driven by community feedback.

    Experienced with C++ or/and IDAPython SDK?

    If you’re a seasoned reverser familiar with C++ and/or IDAPython SDK usage, there’s no need to change your workflow or adopt “another” API. The Domain API is not intended to replace the existing C++ and IDAPython SDK. It offers a high-level alternative for those who prefer it.

    Need low-level control?

    If you need full control, stick with IDAPython or the C++ SDK. The high-level Domain API prioritizes ease of use and community-driven evolution over complete coverage from day one. It will continue to evolve rapidly and expand over time.

    Benefits of using Domain API

    • Clean and Pythonic design. The Domain API is built on top of the existing IDAPython SDK, providing a higher-level Domain Model for interacting with IDA.
    • Domain-focused design. Developed by reverse engineers for reverse engineers, matching how they think about binary analysis.
    • Community-driven updates, versioned independently. Open-source from the start and developed outside of official IDA release cycles, enabling flexible evolution.

    Scripting and Development with the Domain API

    Is it possible to develop plugins with the Domain API?

    Yes. You can dive right away into plugin development with the Domain API, that has been built on top of the IDAPython SDK. For everything that needs more low-level control, you can use it alongside the IDAPython SDK. They are fully compatible with each other.

    Is the Domain API Equivalent to the IDAPython SDK?

    The Domain API currently provides coverage for common tasks such as function manipulation, type management, cross-references handling, and more. For a full overview of available capabilities, see the Domain API Reference. As an open-source project, built with an independent release cycle, the Domain API is designed to evolve quickly. You can expect frequent updates that expand its functionality and have a chance to shape the future of its evolution.

    If you need access to features not yet available through the Domain API, you can combine the IDAPython alongside your Domain API snippets.

    Feedback and contributions

    The Domain API has been open source from the start. We welcome not only contributions, but also your honest feedback — from early impressions to insights that help shape its growth toward maturity.

    {% hint style=“info” %}

    How to contribute? | Visit the Domain API GitHub Repository

    Spotted a bug or want to propose a change to the Domain API? Here’s how to get involved:

    • Read the Contribution Guidelines to understand the process
    • To report bugs or unexpected behavior, open an Issue on GitHub
    • To propose changes, submit a Pull Request (PR) with your improvements {% endhint %}

    {% hint style=“info” %}

    How to share your feedback?

    We welcome your early insights, feature requests, and ideas for possible use cases of the Domain API. Join the conversation in our community forum. {% endhint %}

    FAQ

    Do I need to update my existing plugins or scripts?

    No. You do not need to port your plugins nor update them. The Domain API doesn’t affect existing plugins or scripts in any way. If you are familiar and feel completely confident in developing with IDAPython or C++, you can continue to do so without changing your habits or workflow.

    Is the Domain API a replacement for IDAPython SDK?

    No. The Domain API is not going to replace the IDAPython SDK, but complement it. The high-level Domain API serves as an entry point for developing scripts and plugins in IDA, particularly for newcomers looking for an accessible Pythonic interface.

    Getting Started

    Reference

    Examples

    C++ SDK

    Our IDA SDK exposes API in the form of C++ libraries and header files, allowing you to create custom processor modules and plugins, automate tasks, or integrate new features directly into IDA. Our IDA API is defined and organized by the contents of the header files, that you can browse in our IDA C++ SDK Reference.

    Resources

    IDA C++ SDK Referencehttps://cpp.docs.hex-rays.com/
    IDA SDK Source Code on GitHub https://github.com/HexRaysSA/ida-sdk

    Typical use cases

    With IDA SDK, you can develop loaders for unsupported binary formats or custom processors modules to disassemble and analyze non-standard files. What’s more, you can write plugins to perform complex, automated tasks and more, allowing you to go far beyong the basic IDC scripting.

    What to check next?

    C++ SDK Getting StartedExplore this guide to introduce yourself to the core capabilities of IDA SDK.c++-sdk-getting-started.md
    C++ SDK ExamplesTry complex examples that show the full power and and flexibility of our SDK.c++-sdk-examples.md
    C++ SDK ReferenceCheck in-depth overview of header files with extensive description of data structures and functions.https://cpp.docs.hex-rays.com/
    Writing Plugins in C++Learn the best practices for creating plugins with IDA SDKhow-to-create-a-plugin.md

    SDK Porting Guide

    Check out our Porting Guide, which is prepared to help you migrate and adapt your existing modules and plugins from IDA 8.x to IDA 9.0.

    Getting started with C++ SDK

    Intro

    The IDA C++ SDK provides set of tools to interact with IDA Pro’s disassembler, allowing you to navigate, analyze, and manipulate various elements such as functions, instructions, and data. This guide is designed to accelerate your learning curve with the IDA C++ SDK and kickstart your development journey, assuming you are already familiar with IDA Pro and its basic usage.

    Our IDA SDK is open source and available on GitHub.

    How This Guide is Structured

    First, check Basics for core concepts and commonly used variables. Next, explore our Code Snippets to see examples of commonly used functions. Once you’re comfortable with these, you can delve into more complex Examples that showcase advanced usage of the SDK.

    C++ SDK Installation

    Download the latest version of the SDK directly from IDA SDK GitHub and follow the setup instructions provided in the README.

    Basics

    Common Types and Constants

    One of the most extensivly used type is ea_t, commonly used to represent an effective address (EA) within a binary.

    Common header files and namespaces

    The IDA C++ SDK is organized into header files containing various classes and functions. Below is a short description of commonly used IDA SDK header files:

    • pro.h: This is the first header included in the IDA project. It defines the most common types, functions, and data. It also contains compiler- and platform-related definitions.

    • ida.hpp: In this file the ‘inf’ structure is defined: it keeps all parameters of the disassembled file.

    • idp.hpp: The ‘main’ header file for IDP modules. Contains definition of the interface to IDP modules. The interface consists of 2 structures: processor_t - description of processor
      asm_t - description of assembler
      Each IDP has one processor_t and several asm_t structures.

    • loader.hpp: Definitions of IDP, LDR, and PLUGIN module interfaces. This file also contains:

      • functions to load files into the database
      • functions to generate output files
      • high level functions to work with the database (open, save, close)
    • ua.hpp: Functions that deal with the disassembling of program instructions. Disassembly of an instruction is made in three steps:

      • analysis
      • emulation
      • conversion to text
    • kernwin.hpp: Defines the interface between the kernel and the UI. Some string processing functions are also kept in this header.

    • idd.hpp: Debugger plugin API for debugger module writers. Contains definition of the interface to IDD modules.

    • bytes.hpp: Functions and definitions used to describe and manipulate each byte of the disassembled program. Information about the byte includes associated features (comments, names, references, etc), data types (dword, qword, string literal, etc), instruction operands, status (mapped, loaded, patched, etc), among others.

    • netnode.hpp: Functions that provide the lowest level public interface to the database. Modules can use this to keep some private information in the database. A description of the concept is available in the header file itself.

    • allins.hpp: List of instructions available from all processor modules.

    • auto.hpp: Auto-analysis related functions.

    • compress.hpp: Data compression functions.

    • config.hpp: Functions that deal with configuration options and files.

    • dbg.hpp: Contains functions to control the debugging of a process.

    • diskio.hpp: File I/O functions for IDA. You should not use standard C file I/O functions in modules. Use functions from this header, pro.h, and fpro.h instead.

    • entry.hpp: Functions that deal with entry points to the program being disassembled.

    • enum.hpp: Enumeration type management (assembly level types).

    • err.h: Thread safe functions that deal with error codes.

    • expr.hpp: Functions that deal with C-like expressions, external languages, and the built-in IDC language.

    • fixup.hpp: Functions that deal with fixup (relocation) information.

    • fpro.h: System independent counterparts of file I/O functions. These functions do check errors but never exit even if an error occurs. They return extended error code in qerrno variable. NOTE: You must use these functions instead of the C standard I/O functions.

    • frame.hpp: Routines to manipulate function stack frames, stack variables, register variables and local labels.

    • funcs.hpp: Routines for working with functions within the disassembled program. This file also contains routines for working with library signatures (e.g. FLIRT).

    • gdl.hpp: Low level graph drawing operations.

    • graph.hpp: Graph view management.

    • help.h: Help subsystem. This subsystem is not used in IDP files. We put it just in case.

    • ieee.h: IEEE floating point functions.

    • intel.hpp: Header file from the IBM PC module. For information only. It will not compile because it contains references to internal files!

    • lex.hpp: Tools for parsing C-like input.

    • lines.hpp: High level functions that deal with the generation of the disassembled text lines.

    • nalt.hpp: Definitions of various information kept in netnodes. These functions should not be used directly since they are very low level.

    • moves.hpp: Functions and classes related to location history.

    • name.hpp: Functions that deal with names (setting, deleting, getting, validating, etc).

    • offset.hpp: Functions that deal with offsets.

    • problems.hpp: Functions that deal with the list of problems.

    • prodir.h: Low level functions to find files in the file system. It is better to use enumerate_files2() from diskio.hpp.

    • pronet.h: Network related functions.

    • range.hpp: Contains the definition of the ‘range_t’ class. This is a base class used by many parts of IDA, such as the ‘segment_t’ and ‘segreg_range_t’ (segment register) classes.

    • registry.hpp: Registry related functions. IDA uses the registry to store global configuration options that must persist after IDA has been closed.

    • segment.hpp: Functions that deal with program segmentation.

    • segregs.hpp: Functions that deal with the segment registers. If your processor doesn’t use segment registers, then you don’t need this file.

    • strlist.hpp: Functions that deal with the strings list.

    • struct.hpp: Structure type management (assembly level types).

    • typeinf.hpp: Describes the type information records in IDA.

    • xref.hpp: Functions that deal with cross-references.

    {% hint style=“info” %} All functions usable in the modules are marked by the “ida_export” keyword. {% endhint %}

    Here are the most common namespaces to start with:

    idc: This namespace provides access to IDC scripting functions via C++ SDK. It is often used for common tasks like setting comments or modifying bytes.

    idati: This namespace is used for interacting with type information, such as function signatures and type definitions.

    idaapi: This namespace contains core classes and functions for interacting with IDA’s API, including functions for handling UI elements, plugins, and database access.

    idamisc: This namespace includes utility functions for various tasks, such as working with the address space and disassembly.

    Code Snippets

    Here are common functions and examples grouped by topics:

    Part 1: Addresses and Names

    Get the Current Address

    ea_t ea = get_screen_ea();  // Get the current address
    printf("Current address: %llx\n", ea);
    

    Jump to the address

    jumpto(0x401000);  // Jump to address 0x401000
    

    Get the Minimum and Maximum Address in IDB

    ea_t min_ea = get_inf_attr(INF_MIN_EA);
    ea_t max_ea = get_inf_attr(INF_MAX_EA);
    

    List All Instruction Addresses

    for (ea_t ea = get_segm_by_name("CODE"); ea != BADADDR; ea = get_next_head(ea, badaddr)) {
        printf("Instruction address: %llx\n", ea);
    }
    

    Get the Name Associated with a Given Address

    const char* name = get_name(0x100000da0);
    printf("Name: %s\n", name);
    

    Get the Address Associated with a Given Name

    ea_t address = get_name_ea(0, "_main");
    printf("Address: %llx\n", address);
    

    Part 2: Reading and Writing Data

    Reading Bytes and Words

    u8 byte_value = get_byte(0x401000);  // Read a byte at address 0x401000
    u16 word_value = get_word(0x401002);  // Read a word (2 bytes) at address 0x401002
    u32 dword_value = get_dword(0x401004);  // Read a double word (4 bytes) at address 0x401004
    
    printf("Byte: %x, Word: %x, Dword: %x\n", byte_value, word_value, dword_value);
    

    Writing Bytes and Words

    patch_byte(0x401000, 0x90);  // Write a byte (0x90) at address 0x401000
    patch_word(0x401002, 0x9090);  // Write a word (0x9090) at address 0x401002
    patch_dword(0x401004, 0x90909090);  // Write a double word (0x90909090) at address 0x401004
    

    Part 3: Comments

    Add a Regular or Repeatable Comment

    set_cmt(0x401000, "This is a comment", false);  // Add a regular comment at address 0x401000
    set_cmt(0x401000, "This is a repeatable comment", true);  // Add a repeatable comment at address 0x401000
    

    Get a Regular Comment

    const char* comment = get_cmt(0x401000, false);  // Get a regular comment at address 0x401000
    printf("Comment: %s\n", comment);
    

    Part 4: Segments

    Get a Segment Name

    const char* seg_name = get_segm_name(ea);
    printf("Segment name: %s\n", seg_name);
    

    Iterate Through All Segments

    for (seg_t* seg = get_first_seg(); seg != nullptr; seg = get_next_seg(seg)) {
        printf("Segment name: %s\n", get_segm_name(seg->start_ea));
    }
    

    Part 5: Functions

    Create and Delete Function

    add_func(0x401000, 0x401050);  // Create a function starting at 0x401000 and ending at 0x401050
    del_func(0x401000);  // Delete the function at 0x401000
    

    Get the Name of the Function

    const char* func_name = get_func_name(0x401000);
    printf("Function name: %s\n", func_name);
    

    Iterate Through All Functions

    for (func_t* func = get_first_func(); func != nullptr; func = get_next_func(func)) {
        printf("Function address: %llx, name: %s\n", func->start_ea, get_func_name(func->start_ea));
    }
    

    Part 6: Navigating Cross-References (Xrefs)

    List Cross-References to an Address

    for (xref_t* xref = get_first_xref_to(0x401000); xref != nullptr; xref = get_next_xref_to(xref)) {
        printf("Xref to 0x401000 from %llx\n", xref->from);
    }
    

    List Cross-References from an Address

    for (xref_t* xref = get_first_xref_from(0x401000); xref != nullptr; xref = get_next_xref_from(xref)) {
        printf("Xref from 0x401000 to %llx\n", xref->to);
    }
    

    Part 7: UI

    Set Background Color of a Function

    set_color(0x401000, CIC_FUNC, 0x007fff);  // Set background color for the function starting at address 0x401000
    

    Display a Custom Dialog

    msg("This is a custom message dialog. Good luck with learning the IDA C++ SDK!\n");
    

    Complex Script Examples

    If you’re comfortable with the basics, explore advanced examples included in the SDK itself. These examples often leverage multiple modules to accomplish more sophisticated tasks.

    What’s Next?

    Explore our tutorial on how to create your first custom plugin in IDA using C++.

    Reference

    Using the Decompiler SDK: Decompiler Plug-In

    Below is the full source code of a sample plugin. It performs a quite useful transformation of the pseudocode: replaces zeroes in pointer contexts with NULLs. A NULL immediately conveys the idea that the current expression is pointer-related. This is especially useful for unknown function arguments.

    The plugin is fully automatic. It hooks to the decompiler events and waits for the pseudocode to be ready. At that moment it takes control and modifies the ctree.

    The conversion is performed by the convert_zeroes() function. It visits all expressions of the ctree and checks for pointer contexts. If a expression has a pointer type, then the make_null_if_zero() function is called for it. This function checks if the expression is a zero constant and converts it if necessary.

    The plugin can be turned on or off by its menu item in the Plugins submenu.

    The code is short and straightforward. Use it as a template for your plugins.

    \

    /*
     *      Hex-Rays Decompiler project
     *      Copyright (c) 2007-2019 by Hex-Rays, [email protected]
     *      ALL RIGHTS RESERVED.
     *
     *      Sample plugin for Hex-Rays Decompiler.
     *      It automatically replaces zeroes in pointer contexts with NULLs.
     *      For example, expression like
     *
     *              funcptr = 0;
     *
     *      will be displayed as
     *
     *              funcptr = NULL;
     *
     *      Due to highly dynamic nature of the decompier output, we must
     *      use the decompiler events to accomplish the task. The plugin will
     *      wait for the ctree structure to be ready in the memory and will
     *      replace zeroes in pointer contexts with NULLs.
     *
     */
    
    #include <hexrays.hpp>
    
    // Hex-Rays API pointer
    hexdsp_t *hexdsp = NULL;
    
    static bool inited = false;
    
    static const char nodename[] = “$ hexrays NULLs”;
    static const char null_type[] = “MACRO_NULL”;
    //————————————————————————–
    // Is the plugin enabled?
    // The user can disable it. The plugin will save the on/off switch in the
    // current database.
    static bool is_enabled(void)
    {
      netnode n(nodename); // use a netnode to save the state
      return n.altval(0) == 0; // if the long value is positive, then disabled
    }
    
    //————————————————————————–
    // If the expression is zero, convert it to NULL
    static void make_null_if_zero(cexpr_t *e)
    {
      if ( e->is_zero_const() && !e->type.is_ptr() )
      { // this is plain zero, convert it
        number_format_t &nf = e->n->nf;
        nf.flags = enum_flag();
        nf.serial = 0;
        nf.type_name = null_type;
        e->type = tinfo_t::get_stock(STI_PVOID);
      }
    }
    
    //————————————————————————–
    // Convert zeroes of the ctree to NULLs
    static void convert_zeroes(cfunc_t *cfunc)
    {
      // To represent NULLs, we will use the MACRO_NULL enumeration
      // Normally it is present in the loaded tils but let’s verify it
      if ( !get_named_type(NULL, null_type, NTF_TYPE) )
      {
        msg(“%s type is missing, cannot convert zeroes to NULLs\n”, null_type);
        return;
      }
    
      // We derive a helper class from ctree_visitor_t
      // The ctree_visitor_t is a base class to derive
      // ctree walker classes.
      // You have to redefine some virtual functions
      // to do the real job. Here we redefine visit_expr() since we want
      // to examine and modify expressions.
      struct ida_local zero_converter_t : public ctree_visitor_t
      {
        zero_converter_t(void) : ctree_visitor_t(CV_FAST) {}
        int idaapi visit_expr(cexpr_t *e)
        {
          // verify if the current expression has pointer expressions
          // we handle the following patterns:
          //  A. ptr = 0;
          //  B. func(0); where argument is a pointer
          //  C. ptr op 0 where op is a comparison
          switch ( e->op )
          {
            case cot_asg:   // A
              if ( e->x->type.is_ptr() )
                make_null_if_zero(e->y);
              break;
    
            case cot_call:  // B
              {
                carglist_t &args = *e->a;
                for ( int i=0; i < args.size(); i++ ) // check all arguments
                {
                  carg_t &a = args[i];
                  if ( a.formal_type.is_ptr_or_array() )
                    make_null_if_zero(&a);
                }
              }
              break;
    
            case cot_eq:    // C
            case cot_ne:
            case cot_sge:
            case cot_uge:
            case cot_sle:
            case cot_ule:
            case cot_sgt:
            case cot_ugt:
            case cot_slt:
            case cot_ult:
              // check both sides for zeroes
              if ( e->y->type.is_ptr() )
                make_null_if_zero(e->x);
              if ( e->x->type.is_ptr() )
                make_null_if_zero(e->y);
              break;
    
            default:
              break;
    
          }
          return 0; // continue walking the tree
        }
      };
      zero_converter_t zc;
      // walk the whole function body
      zc.apply_to(&cfunc->body, NULL);
    }
    
    //————————————————————————–
    // This callback will detect when the ctree is ready to be displayed
    // and call convert_zeroes() to create NULLs
    static ssize_t idaapi callback(void *, hexrays_event_t event, va_list va)
    {
      if ( event == hxe_maturity )
      {
        cfunc_t *cfunc = va_arg(va, cfunc_t*);
        ctree_maturity_t mat = va_argi(va, ctree_maturity_t);
        if ( mat == CMAT_FINAL ) // ctree is ready, time to convert zeroes to NULLs
          convert_zeroes(cfunc);
      }
      return 0;
    }
    
    //————————————————————————–
    // Initialize the plugin.
    int idaapi init(void)
    {
      if ( !init_hexrays_plugin() )
        return PLUGIN_SKIP; // no decompiler
      if ( is_enabled() ) // null plugin is enabled?
      {
        install_hexrays_callback(callback, NULL);
        const char *hxver = get_hexrays_version();
        msg(“Hex-rays version %s has been detected, %s ready to use\n”, hxver, PLUGIN.wanted_name);
      }
      inited = true;
      return PLUGIN_KEEP;
    }
    
    //————————————————————————–
    void idaapi term(void)
    {
      if ( inited )
      {
        // clean up
        remove_hexrays_callback(callback, NULL);
        term_hexrays_plugin();
      }
    }
    
    //————————————————————————–
    bool idaapi run(size_t)
    {
      // since all real work is done in the callbacks, use the main plugin entry
      // to turn it on and off.
      // display a message explaining the purpose of the plugin:
      int code = askbuttons(
           “~E~nable”,
           “~D~isable”,
           “~C~lose”,
           –1,
           “AUTOHIDE NONE\n”
           “Sample plugin for Hex-Rays decompiler.\n”
           “\n”
           “This plugin is fully automatic.\n”
           “It detects zeroes in pointer contexts and converts them into NULLs.\n”
           “\n”
           “The current state of the plugin is: %s\n”,
           is_enabled() ? “ENABLED” : “DISABLED”);
      switch ( code )
      {
        case –1:    // close
          break;
        case 0:     // disable
        case 1:     // enable
          netnode n;
          n.create(nodename);
          n.altset(0, code == 0);
          if ( code )
            install_hexrays_callback(callback, NULL);
          else
            remove_hexrays_callback(callback, NULL);
          info(“The %s plugin has been %s.”, PLUGIN.wanted_name, code ? “ENABLED” : “DISABLED”);
          break;
      }
      return true;
    }
    
    //————————————————————————–
    static char comment[] = “Sample2 plugin for Hex-Rays decompiler”;
    
    //————————————————————————–
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //————————————————————————–
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      0,                    // plugin flags
      init,                 // initialize
      term,                 // terminate. this pointer may be NULL.
      run,                  // invoke plugin
      comment,              // long comment about the plugin
                            // it could appear in the status line
                            // or as a hint
      “”,                   // multiline help about the plugin
      “Hex-Rays NULL converter”, // the preferred short name of the plugin
      “”                    // the preferred hotkey to run the plugin
    };
    
    
    

    Examples

    {% hint style=“info” %} This page is currently a stub. We’re working on additional examples tailored for beginners, so expect more samples soon. {% endhint %}

    The IDA SDK, that can be accessed directly from our GitHub repository, provides sample code in addition to necessary libraries and headers. These exemplary plugins, processor modules, or file loaders are designed to help you create your own plugins, modules, and more.

    Where can I find all the examples?

    The IDA SDK is shipped with plenty of samples (including, for example, sample processor modules or loaders) and exemplary plugins that you can find in the IDA SDK GitHub repository. To kickstart your journey with the IDA SDK, we encourage you to check out the included samples, compile them, and run them.

    Sample plugins

    The plugins folder contains sample plugins written in C++. Usually, the subfolders contains at minimum the cpp file(s) and a makefile.

    Below, we present only a selection of samples to familiarize yourself with the possibilities of the C++ SDK. All of these samples and their corresponding makefiles can be found in your plugins folder inside the SDK directory.

    hello

    Simple hello word plugin ideal to get started with IDA SDK.

    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      virtual bool idaapi run(size_t) override;
    };
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      msg("Hello, world! (cpp)\n");
      return true;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_UNL            // Unload the plugin immediately after calling 'run'
      | PLUGIN_MULTI,       // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      nullptr,              // long comment about the plugin
      nullptr,              // multiline help about the plugin
      "Hello, world",       // the preferred short name of the plugin
      nullptr,              // the preferred hotkey to run the plugin
    };
    

    vcsample

    Sample plugin, ideal to get familiar with plugins structure.

    /*
     *  This is a sample plugin module
     *
     *  It can be compiled by any of the supported compilers:
     *
     *      - Visual C++
     *      - GCC
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <expr.hpp>
    #include <bytes.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //#define INSTALL_SAMPLE_CALLBACK
    //#define HAS_USER_DEFINED_PREFIX
    
    //--------------------------------------------------------------------------
    //lint -e754 struct member not referenced
    struct plugin_data_t : public plugmod_t, public event_listener_t
    {
      ea_t old_ea = BADADDR;
      int old_lnnum = -1;
      virtual ssize_t idaapi on_event(ssize_t event_id, va_list) override;
      virtual bool idaapi run(size_t arg) override;
    
      idaapi ~plugin_data_t();
    };
    
    //--------------------------------------------------------------------------
    // Example of a user-defined IDC function in C++
    
    //#define DEFINE_IDC_FUNC
    #ifdef DEFINE_IDC_FUNC
    static error_t idaapi myfunc5(idc_value_t *argv, idc_value_t *res)
    {
      msg("myfunc is called with arg0=%x and arg1=%s\n", argv[0].num, argv[1].c_str());
      res->num = 5;     // let's return 5
      return eOk;
    }
    static const char myfunc5_args[] = { VT_LONG, VT_STR, 0 };
    static const ext_idcfunc_t myfunc5_desc =
    {
      { "MyFunc5", myfunc5, myfunc5_args, nullptr, 0, 0 }
    };
    #endif // DEFINE_IDC_FUNC
    
    //--------------------------------------------------------------------------
    // This callback is called for UI notification events
    ssize_t idaapi plugin_data_t::on_event(ssize_t event_id, va_list)
    {
      if ( event_id != ui_msg     // avoid recursion
        && event_id != ui_refreshmarked ) // ignore uninteresting events
      {
        msg("ui_callback %" FMT_ZS "\n", event_id);
      }
      return 0; // 0 means "continue processing the event"
                // otherwise the event is considered as processed
    }
    
    //--------------------------------------------------------------------------
    // A sample how to generate user-defined line prefixes
    #ifdef HAS_USER_DEFINED_PREFIX
    static const int prefix_width = 8;
    
    struct sample_prefix_t : public user_defined_prefix_t
    {
      plugin_data_t *pd;
      sample_prefix_t(plugin_data_t *d) :
        user_defined_prefix_t(prefix_width, d), pd(d) {}
      virtual void idaapi get_user_defined_prefix(
            qstring *out,
            ea_t ea,
            const insn_t & /*insn*/,
            int lnnum,
            int indent,
            const char *line) override
      {
        out->qclear();        // empty prefix by default
    
        // We want to display the prefix only the lines which
        // contain the instruction itself
    
        if ( indent != -1 )           // a directive
          return;
    
        if ( line[0] == '\0' )        // empty line
          return;
    
        if ( tag_advance(line,1)[-1] == ash.cmnt[0] ) // comment line...
          return;
    
        // We don't want the prefix to be printed again for other lines of the
        // same instruction/data. For that we remember the line number
        // and compare it before generating the prefix
    
        if ( pd->old_ea == ea && pd->old_lnnum == lnnum )
          return;
    
        // Ok, seems that we found an instruction line.
    
        // Let's display the size of the current item as the user-defined prefix
        asize_t our_size = get_item_size(ea);
    
        // We don't bother about the width of the prefix
        // because it will be padded with spaces by the kernel
    
        out->sprnt(" %" FMT_64 "d", our_size);
    
        // Remember the address and line number we produced the line prefix for:
        pd->old_ea = ea;
        pd->old_lnnum = lnnum;
      }
    };
    #endif // HAS_USER_DEFINED_PREFIX
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      if ( inf_get_filetype() == f_ELF )
        return nullptr; // we do not want to work with this idb
    
      plugin_data_t *pd = new plugin_data_t;
    
      // notifications
    #ifdef INSTALL_SAMPLE_CALLBACK
      hook_event_listener(HT_UI, pd, pd);
    #endif // INSTALL_SAMPLE_CALLBACK
    
      // user-defined prefix. will be automatically uninstalled by the kernel
      // when our plugin gets unloaded.
    #ifdef HAS_USER_DEFINED_PREFIX
      new sample_prefix_t(pd);
    #endif // HAS_USER_DEFINED_PREFIX
    
      // custom IDC function
    #ifdef DEFINE_IDC_FUNC
      add_idc_func(myfunc5_desc);
    #endif // DEFINE_IDC_FUNC
    
      // an example how to retrieve plugin options
      const char *options = get_plugin_options("vcsample");
      if ( options != nullptr )
        warning("command line options: %s", options);
    
      return pd;
    }
    
    //--------------------------------------------------------------------------
    plugin_data_t::~plugin_data_t()
    {
    #ifdef DEFINE_IDC_FUNC
      del_idc_func(myfunc5_desc.name);
    #endif
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_data_t::run(size_t arg)
    {
      warning("vcsample plugin has been called with arg %" FMT_Z, arg);
      // msg("just fyi: the current screen address is: %a\n", get_screen_ea());
      return true;
    }
    
    //--------------------------------------------------------------------------
    static const char comment[] = "This is a sample plugin. It does nothing useful";
    
    static const char help[] =
      "A sample plugin module\n"
      "\n"
      "This module shows you how to create plugin modules.\n"
      "\n"
      "It does nothing useful - just prints a message that is was called\n"
      "and shows the current address.\n";
    
    //--------------------------------------------------------------------------
    // This is the preferred name of the plugin module in the menu system
    // The preferred name may be overridden in plugins.cfg file
    
    static const char wanted_name[] = "Sample plugin";
    
    
    // This is the preferred hotkey for the plugin module
    // The preferred hotkey may be overridden in plugins.cfg file
    
    static const char wanted_hotkey[] = "";
    
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // plugin flags
      init,                 // initialize
    
      nullptr,              // terminate. this pointer may be nullptr.
    
      nullptr,              // invoke plugin
    
      comment,              // long comment about the plugin
                            // it could appear in the status line
                            // or as a hint
    
      help,                 // multiline help about the plugin
    
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey         // the preferred hotkey to run the plugin
    };
    

    calle

    Sample plugin that allows the user to change the address of the called function.

    /*
     *  Change the callee address for constructions like
     *
     *  call esi    ; LocalFree
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    #include <bytes.hpp>
    #include <auto.hpp>
    #include <segregs.hpp>
    #define T 20
    
    struct callee_vars_t : public plugmod_t
    {
      processor_t &ph;
      callee_vars_t(processor_t &_ph) : ph(_ph) {}
      virtual bool idaapi run(size_t arg) override;
    };
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      processor_t &ph = PH;
      if ( ph.id != PLFM_386 && ph.id != PLFM_MIPS && ph.id != PLFM_ARM )
        return nullptr; // only for x86, MIPS and ARM
      return new callee_vars_t(ph);
    }
    
    //--------------------------------------------------------------------------
    static const char comment[] = "Change the callee address";
    static const char help[] =
      "This plugin allows the user to change the address of the called function\n"
      "in constructs like\n"
      "\n"
      "       call esi\n"
      "\n"
      "You can enter a function name instead of its address\n";
    
    //--------------------------------------------------------------------------
    static const char *const form =
      "HELP\n"
      "%s\n"
      "ENDHELP\n"
      "Enter the callee address\n"
      "\n"
      "  <~C~allee:$::40:::>\n"
      "\n"
      "\n";
    
    bool idaapi callee_vars_t::run(size_t)
    {
      const char *nname;
      if ( ph.id == PLFM_MIPS )
        nname = "$ mips";
      else if ( ph.id == PLFM_ARM )
        nname = " $arm";
      else
        nname = "$ vmm functions";
      netnode n(nname);
      ea_t ea = get_screen_ea();    // get current address
      if ( !is_code(get_flags(ea)) )
        return false; // not an instruction
      // get the callee address from the database
      ea_t callee = node2ea(n.altval_ea(ea)-1);
      // remove thumb bit for arm
      if ( ph.id == PLFM_ARM )
        callee &= ~1;
      char buf[MAXSTR];
      qsnprintf(buf, sizeof(buf), form, help);
      if ( ask_form(buf, &callee) )
      {
        if ( callee == BADADDR )
        {
          n.altdel_ea(ea);
        }
        else
        {
          if ( ph.id == PLFM_ARM && (callee & 1) == 0 )
          {
            // if we're calling a thumb function, set bit 0
            sel_t tbit = get_sreg(callee, T);
            if ( tbit != 0 && tbit != BADSEL )
              callee |= 1;
          }
          // save the new address
          n.altset_ea(ea, ea2node(callee)+1);
        }
        gen_idb_event(idb_event::callee_addr_changed, ea, callee);
        plan_ea(ea);                 // reanalyze the current instruction
      }
      return true;
    }
    
    //--------------------------------------------------------------------------
    static const char wanted_name[] = "Change the callee address";
    static const char wanted_hotkey[] = "Alt-F11";
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // plugin flags
      init,                 // initialize
    
      nullptr,              // terminate. this pointer may be nullptr.
      nullptr,              // invoke plugin
    
      comment,              // long comment about the plugin
                            // it could appear in the status line
                            // or as a hint
    
      help,                 // multiline help about the plugin
    
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey         // the preferred hotkey to run the plugin
    };
    

    choose

    Sample plugin module that demonstrates the use of the choose() function.

    /*
     *  This is a sample plugin module
     *
     *  It demonstrates the use of the choose() function
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <bytes.hpp>
    #include <kernwin.hpp>
    
    struct plugin_ctx_t : public plugmod_t
    {
      virtual bool idaapi run(size_t arg) override;
    };
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //-------------------------------------------------------------------------
    // non-modal call instruction chooser
    struct calls_chooser_t : public chooser_t
    {
    protected:
      static const int widths_[];
      static const char *const header_[];
    
    public:
      // remember the call instruction addresses in this qvector
      eavec_t list;
    
      // this object must be allocated using `new`
      calls_chooser_t(const char *title, bool ok, func_item_iterator_t *fii);
    
      // function that is used to decide whether a new chooser should be opened
      // or we can use the existing one.
      // The contents of the window are completely determined by its title
      virtual const void *get_obj_id(size_t *len) const override
      {
        *len = strlen(title);
        return title;
      }
    
      // function that returns number of lines in the list
      virtual size_t idaapi get_count() const override { return list.size(); }
    
      // function that generates the list line
      virtual void idaapi get_row(
            qstrvec_t *cols,
            int *icon_,
            chooser_item_attrs_t *attrs,
            size_t n) const override;
    
      // function that is called when the user hits Enter
      virtual cbret_t idaapi enter(size_t n) override
      {
        if ( n < list.size() )
          jumpto(list[n]);
        return cbret_t(); // nothing changed
      }
    
    protected:
      void build_list(bool ok, func_item_iterator_t *fii)
      {
        insn_t insn;
        while ( ok )
        {
          ea_t ea = fii->current();
          if ( decode_insn(&insn, ea) > 0 && is_call_insn(insn) ) // a call instruction is found
            list.push_back(ea);
          ok = fii->next_code();
        }
      }
    };
    
    // column widths
    const int calls_chooser_t::widths_[] =
    {
      CHCOL_HEX | 8,  // Address
      32,             // Instruction
    };
    // column headers
    const char *const calls_chooser_t::header_[] =
    {
      "Address",      // 0
      "Instruction",  // 1
    };
    
    inline calls_chooser_t::calls_chooser_t(
            const char *title_,
            bool ok,
            func_item_iterator_t *fii)
      : chooser_t(0, qnumber(widths_), widths_, header_, title_),
        list()
    {
      CASSERT(qnumber(widths_) == qnumber(header_));
    
      // build the list of calls
      build_list(ok, fii);
    }
    
    void idaapi calls_chooser_t::get_row(
            qstrvec_t *cols_,
            int *,
            chooser_item_attrs_t *,
            size_t n) const
    {
      // assert: n < list.size()
      ea_t ea = list[n];
    
      // generate the line
      qstrvec_t &cols = *cols_;
      cols[0].sprnt("%08a", ea);
      generate_disasm_line(&cols[1], ea, GENDSM_REMOVE_TAGS);
      CASSERT(qnumber(header_) == 2);
    }
    
    
    //--------------------------------------------------------------------------
    // The plugin method
    // This is the main function of the plugin.
    bool idaapi plugin_ctx_t::run(size_t)
    {
      qstring title;
      // Let's display the functions called from the current one
      // or from the selected area
    
      // First we determine the working area
      func_item_iterator_t fii;
      bool ok;
      ea_t ea1, ea2;
      if ( read_range_selection(nullptr, &ea1, &ea2) ) // the selection is present?
      {
        callui(ui_unmarksel);                       // unmark selection
        title.sprnt("Functions called from %08a..%08a", ea1, ea2);
        ok = fii.set_range(ea1, ea2);
      }
      else                                          // nothing is selected
      {
        func_t *pfn = get_func(get_screen_ea());    // try the current function
        if ( pfn == nullptr )
        {
          warning("Please position the cursor on a function or select an area");
          return true;
        }
        ok = fii.set(pfn);
        get_func_name(&title, pfn->start_ea);
        title.insert("Functions called from ");
      }
    
      // now open the window
      calls_chooser_t *ch = new calls_chooser_t(title.c_str(), ok, &fii);
      ch->choose(); // the default cursor position is 0 (first row)
      return true; //-V773
    }
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      // plugin flags
      PLUGIN_MULTI,
      // initialize
      init,
      nullptr,
      nullptr,
      // long comment about the plugin
      // it could appear in the status line
      // or as a hint
      "This is a sample plugin. It displays the chooser window",
      // multiline help about the plugin
      "A sample plugin module\n"
      "\n"
      "This module shows you how to use choose() function.\n",
    
      // the preferred short name of the plugin
      "Called functions",
      // the preferred hotkey to run the plugin
      ""
    };
    

    custdata

    This sample plugin demonstates how to install a custom data type and a custom data format.

    custview

    This sample plugin demonstates how to create and manipulate a simple custom viewer, that allows you to create a view which displays colored lines.

    cvt64_sample

    Plugin with CVT64 examples.

    dwarf

    The source code of the dwarf plugin

    ex_debidc

    This sample Debugger IDC Helper executes IDC script when the process is launched and allows to hook IDC scripts to various debugger events.

    // Debugger IDC Helper
    // Executes IDC script when the process is launched
    // In fact, this approach can be used to hook IDC scripts to various debugger
    // events.
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <dbg.hpp>
    #include <expr.hpp>
    #include <loader.hpp>
    
    int data_id;
    
    //--------------------------------------------------------------------------
    // The plugin stores the IDC file name in the database
    // It will create a node for this purpose
    static const char node_name[] = "$ debugger idc file";
    
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t;
    
    DECLARE_LISTENER(dbg_listener_t, plugin_ctx_t, ctx);
    DECLARE_LISTENER(idp_listener_t, plugin_ctx_t, ctx);
    
    struct plugin_ctx_t : public plugmod_t
    {
      dbg_listener_t dbg_listener = dbg_listener_t(*this);
      idp_listener_t idp_listener = idp_listener_t(*this);
      plugin_ctx_t()
      {
        hook_event_listener(HT_DBG, &dbg_listener);
    #ifdef ENABLE_MERGE
        hook_event_listener(HT_IDP, &idp_listener);
    #endif
        set_module_data(&data_id, this);
      }
      ~plugin_ctx_t()
      {
        clr_module_data(data_id);
        // listeners are uninstalled automatically
        // when the owner module is unloaded
      }
    
      virtual bool idaapi run(size_t) override;
    };
    
    //--------------------------------------------------------------------------
    // Get the IDC file name from the database
    static bool get_idc_name(char *buf, size_t bufsize)
    {
      // access the node
      netnode mynode(node_name);
      // retrieve the value
      return mynode.valstr(buf, bufsize) > 0;
    }
    
    //--------------------------------------------------------------------------
    // Store the IDC file name in the database
    static void set_idc_name(const char *idc)
    {
      // access the node
      netnode mynode;
      // if it doesn't exist yet, create it
      // otherwise get its id
      mynode.create(node_name);
      // store the value
      mynode.set(idc, strlen(idc)+1);
    }
    
    //--------------------------------------------------------------------------
    ssize_t idaapi idp_listener_t::on_event(ssize_t code, va_list va)
    {
      return 0;
    }
    
    //--------------------------------------------------------------------------
    ssize_t idaapi dbg_listener_t::on_event(ssize_t code, va_list /*va*/)
    {
      switch ( code )
      {
        case dbg_process_start:
        case dbg_process_attach:
          // it is time to run the script
          char idc[QMAXPATH];
          if ( get_idc_name(idc, sizeof(idc)) )
          {
            qstring errbuf;
            if ( !exec_idc_script(nullptr, idc, "main", nullptr, 0, &errbuf) )
              warning("%s", errbuf.c_str());
          }
          break;
      }
      return 0;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      // retrieve the old IDC name from the database
      char idc[QMAXPATH];
      if ( !get_idc_name(idc, sizeof(idc)) )
        qstrncpy(idc, "*.idc", sizeof(idc));
    
      char *newidc = ask_file(false, idc, "Specify the script to run upon debugger launch");
      if ( newidc != nullptr )
      {
        // store it back in the database
        set_idc_name(newidc);
        msg("Script %s will be run when the debugger is launched\n", newidc);
      }
      return true;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      // Our plugin works only for x86 PE executables
      processor_t &ph = PH;
      if ( ph.id != PLFM_386 || inf_get_filetype() != f_PE )
        return nullptr;
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    static const char wanted_name[] = "Specify Debugger IDC Script";
    static const char wanted_hotkey[] = "";
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      wanted_name,          // long comment about the plugin
      wanted_name,          // multiline help about the plugin
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey         // the preferred hotkey to run the plugin
    };
    

    ex_events1

    Sample plugin illustrating analysis improvement; it checks branch targets for newly created instructions.

    /*
            This is a sample plugin.
    
            It illustrates how the analysis can be improved
    
            The plugin checks branch targets for newly created instructions.
            If the target does not exist in the program, the plugin
            forbids the instruction creation.
    
    */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    #include <allins.hpp>
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t, public event_listener_t
    {
      plugin_ctx_t()
      {
        hook_event_listener(HT_IDB, this);
      }
      ~plugin_ctx_t()
      {
        // listeners are uninstalled automatically
        // when the owner module is unloaded
      }
    
      virtual bool idaapi run(size_t) override;
      virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
    };
    
    //--------------------------------------------------------------------------
    // This callback is called by the kernel when database related events happen
    ssize_t idaapi plugin_ctx_t::on_event(ssize_t event_id, va_list va)
    {
      switch ( event_id )
      {
        case idb_event::make_code:  // An instruction is being created
                                    // args: insn_t *
                                    // returns: 1-ok, <=0-the kernel should stop
          insn_t *insn = va_arg(va, insn_t *);
          // we are interested in the branch instructions
          if ( insn->itype >= NN_ja && insn->itype <= NN_jmpshort )
          {
            // the first operand contains the jump target
            ea_t target = to_ea(insn->cs, insn->Op1.addr);
            if ( !is_mapped(target) )
              return -1;
          }
      }
      return 0; // event not processed
                // let other plugins handle it
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      // since the plugin is fully automatic, there is nothing to do
      warning("Branch checker is fully automatic");
      return true;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_HIDE           // Plugin should not appear in the Edit, Plugins menu
      | PLUGIN_MULTI,       // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      nullptr,              // long comment about the plugin
      nullptr,              // multiline help about the plugin
      "Branch checker",     // the preferred short name of the plugin
      nullptr,              // the preferred hotkey to run the plugin
    };
    

    extlang

    Sample plugin that illustrates how to register a thid party language interpreter.

    /*
            This is a sample plugin. It illustrates
    
              how to register a thid party language interpreter
    
    */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <expr.hpp>
    #include <kernwin.hpp>
    
    //--------------------------------------------------------------------------
    static bool idaapi compile_expr(// Compile an expression
            const char *name,       // in: name of the function which will
                                    //     hold the compiled expression
            ea_t current_ea,        // in: current address. if unknown then BADADDR
            const char *expr,       // in: expression to compile
            qstring *errbuf)        // out: error message if compilation fails
    {                               // Returns: success
      qnotused(name);
      qnotused(current_ea);
      qnotused(expr);
      // our toy interpreter doesn't support separate compilation/evaluation
      // some entry fields in ida won't be useable (bpt conditions, for example)
      if ( errbuf != nullptr )
        *errbuf = "compilation error";
      return false;
    }
    
    //--------------------------------------------------------------------------
    static bool idaapi call_func(   // Evaluate a previously compiled expression
            idc_value_t *result,    // out: function result
            const char *name,       // in: function to call
            const idc_value_t args[], // in: input arguments
            size_t nargs,           // in: number of input arguments
            qstring *errbuf)        // out: error message if compilation fails
    {                               // Returns: success
      qnotused(name);
      qnotused(nargs);
      qnotused(args);
      qnotused(result);
      if ( errbuf != nullptr )
        *errbuf = "evaluation error";
      return false;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi eval_expr(          // Compile and evaluate expression
            idc_value_t *rv,        // out: expression value
            ea_t current_ea,        // in: current address. if unknown then BADADDR
            const char *expr,       // in: expression to evaluation
            qstring *errbuf)        // out: error message if compilation fails
    {                               // Returns: success
      qnotused(current_ea);
      // we know to parse and decimal and hexadecimal numbers
      int radix = 10;
      const char *ptr = skip_spaces(expr);
      bool neg = false;
      if ( *ptr == '-' )
      {
        neg = true;
        ptr = skip_spaces(ptr+1);
      }
      if ( *ptr == '0' && *(ptr+1) == 'x' )
      {
        radix = 16;
        ptr += 2;
      }
      sval_t value = 0;
      while ( radix == 10 ? qisdigit(*ptr) : qisxdigit(*ptr) )
      {
        int d = *ptr <= '9' ? *ptr-'0' : qtolower(*ptr)-'a'+10;
        value *= radix;
        value += d;
        ptr++;
      }
      if ( neg )
        value = -value;
      ptr = skip_spaces(ptr);
      if ( *ptr != '\0' )
      {
        msg("EVAL FAILED: %s\n", expr);
        if ( errbuf != nullptr )
          *errbuf = "syntax error";
        return false;
      }
    
      // we have the result, store it in the return value
      if ( rv != nullptr )
      {
        rv->clear();
        rv->num = value;
      }
      msg("EVAL %" FMT_EA "d: %s\n", value, expr);
      return true;
    }
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      extlang_t my_extlang =
      {
        sizeof(extlang_t),            // Size of this structure
        0,                            // Language features, currently 0
        0,                            // refcnt
        "extlang sample",             // Language name
        nullptr,                      // fileext
        nullptr,                      // syntax highlighter
        compile_expr,
        nullptr,                      // compile_file
        call_func,
        eval_expr,
        nullptr,                      // create_object
        nullptr,                      // get_attr
        nullptr,                      // set_attr
        nullptr,                      // call_method
        nullptr,                      // eval_snippet
        nullptr,                      // load_procmod
        nullptr,                      // unload_procmod
      };
      bool installed = false;
    
      plugin_ctx_t()
      {
        installed = install_extlang(&my_extlang) >= 0;
      }
      ~plugin_ctx_t()
      {
        if ( installed )
          remove_extlang(&my_extlang);
      }
    
      virtual bool idaapi run(size_t) override { return false; }
    };
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      plugin_ctx_t *ctx = new plugin_ctx_t;
      if ( !ctx->installed )
      {
        msg("extlang: install_extlang() failed\n");
        delete ctx;
        ctx = nullptr;
      }
      return ctx;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_HIDE           // Plugin should not appear in the Edit, Plugins menu
      | PLUGIN_FIX          // Load plugin when IDA starts and keep it in the
                            // memory until IDA stops
      | PLUGIN_MULTI,       // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      nullptr,              // long comment about the plugin
      nullptr,              // multiline help about the plugin
      "Sample third party language", // the preferred short name of the plugin
      nullptr,              // the preferred hotkey to run the plugin
    };
    

    formsample

    This plugin demonstrates how to use complex forms.

    /*
     *  This plugin demonstrates how to use complex forms.
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      virtual bool idaapi run(size_t) override;
    };
    
    //--------------------------------------------------------------------------
    static int idaapi btn_cb(int, form_actions_t &)
    {
      warning("button pressed");
      return 0;
    }
    
    //--------------------------------------------------------------------------
    static int idaapi modcb(int fid, form_actions_t &fa)
    {
      switch ( fid )
      {
        case CB_INIT:
          msg("initializing\n");
          break;
        case CB_YES:
          msg("terminating\n");
          break;
        case 5:     // operand
          msg("changed operand\n");
          break;
        case 6:     // check
          msg("changed check\n");
          break;
        case 7:     // button
          msg("changed button\n");
          break;
        case 8:     // color button
          msg("changed color button\n");
          break;
        default:
          msg("unknown id %d\n", fid);
          break;
      }
    
      bool is_gui = is_idaq();
    
      qstring buf0;
      if ( !fa.get_string_value(5, &buf0) )
        INTERR(30145);
    
      if ( buf0 == "on" )
        fa.enable_field(12, true);
    
      if ( buf0 == "off" )
        fa.enable_field(12, false);
    
      ushort buf1;
      if ( !fa.get_cbgroup_value(12, &buf1) )
        INTERR(30146);
    
      fa.show_field(7, (buf1 & 1) != 0);
      fa.enable_field(8, (buf1 & 2) != 0);
    
    
      ushort c13;
      if ( !fa.get_checkbox_value(13, &c13) )
        INTERR(30147);
      fa.enable_field(10, c13 != 0);
    
      ushort c14;
      if ( !fa.get_checkbox_value(14, &c14) )
        INTERR(30148);
      fa.enable_field(5, c14 != 0);
    
      ushort c15;
      if ( !fa.get_checkbox_value(15, &c15) )
        INTERR(30149);
    
      if ( (buf1 & 8) != 0 )
      {
        sval_t x, y, w, h;
        fa.get_signed_value(4, &x);
        fa.get_signed_value(3, &y);
        fa.get_signed_value(2, &w);
        fa.get_signed_value(1, &h);
        fa.move_field(5, x, y, w, h);
        if ( x != -1 && c15 )
          fa.move_field(-5, x-7, y, w, h);
      }
    
      // get_field_value() for buttons must return false always
      if ( fa._get_field_value(7, nullptr) )
        INTERR(30150);
    
      bgcolor_t bgc = -1;
      if ( is_gui && !fa.get_color_value(8, &bgc) )
        INTERR(30151);
      msg("  op=%s change=%x color=%x\n", buf0.c_str(), buf1, bgc);
    
      fa.set_label_value(9, buf0.c_str());
      return 1;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      static const char form[] =
        "@0:477[]\n"
        "Manual operand\n"
        "\n"
        "%/Enter alternate string for the %9X operand\n"
        "\n"
        "  <~O~perand:q5:100:40::>\n"
        "  <~X~:D4:100:10::>\n"
        "  <~Y~:D3:100:10::>\n"
        "  <~W~:D2:100:10::>\n"
        "  <~H~:D1:100:10::>\n"
        "\n"
        "  <S~h~ow Button:C10>\n"
        "  <~E~nable color Button:C11>\n"
        "  <~E~nable C10:C13>\n"
        "  <~S~et operand bounds:C6>\n"
        "  <Enable operand:C14>\n"
        "  <Move label:C15>12>\n"
        "\n"
        " <~B~utton:B7:0:::> <~C~olor button:K8::::>\n"
        "\n"
        "\n";
      qstring buf("original");
      ushort check = 0x12;
      bgcolor_t bgc = 0x556677;
      uval_t x = -1;
      uval_t y = -1;
      uval_t w = -1;
      uval_t h = -1;
      CASSERT(IS_FORMCHGCB_T(modcb));
      CASSERT(IS_QSTRING(buf));
      if ( ask_form(form, modcb, buf.c_str(), &buf, &x, &y, &w, &h, &check, btn_cb, &bgc) > 0 )
      {
        msg("operand: %s\n", buf.c_str());
        msg("check = %d\n", check);
        msg("dim = %a %a %a %a\n", x, y, w, h);
        msg("bgc = %x\n", bgc);
      }
      return true;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    

    funclist

    This sample plugin demonstrates how to get the the entry point prototypes.

    /*
     *  This is a sample plugin module
     *
     *      It demonstrates how to get the the entry point prototypes
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <auto.hpp>
    #include <entry.hpp>
    #include <bytes.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    #include <typeinf.hpp>
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      virtual bool idaapi run(size_t) override;
    };
    
    //-------------------------------------------------------------------------
    // non-modal entry point chooser
    struct entry_chooser_t : public chooser_t
    {
    protected:
      struct item_t
      {
        ea_t ea;
        qstring decl;
        int ord;
        uint32 argsize;
      };
      // remember the information about an entry point in this qvector
      qvector<item_t> list;
    
      static const int widths_[];
      static const char *const header_[];
    
    public:
      // this object must be allocated using `new`
      entry_chooser_t();
    
      // function that is used to decide whether a new chooser should be opened
      // or we can use the existing one.
      // There should be the only window as the entry points data are static.
      virtual const void *get_obj_id(size_t *len) const override { *len = 1; return ""; }
    
      // function that returns number of lines in the list
      virtual size_t idaapi get_count() const override { return list.size(); }
    
      // function that generates the list line
      virtual void idaapi get_row(
            qstrvec_t *cols,
            int *icon_,
            chooser_item_attrs_t *attrs,
            size_t n) const override;
    
      // function that is called when the user hits Enter
      virtual cbret_t idaapi enter(size_t n) override
      {
        if ( n < list.size() )
          jumpto(list[n].ea);
        return cbret_t(); // nothing changed
      }
    
      // function that is called when the chooser is initialized
      virtual bool idaapi init() override
      {
        // rebuild the list
        list.clear();
        size_t n = get_entry_qty();
        // gather information about the entry points
        for ( size_t i = 0; i < n; ++i )
        {
          asize_t ord = get_entry_ordinal(int(i));
          ea_t ea = get_entry(ord);
          if ( ord == ea )
            continue;
          tinfo_t type;
          qstring decl;
          qstring long_name;
          qstring true_name;
          asize_t argsize = 0;
          qstring entry_name;
          get_entry_name(&entry_name, ord);
          if ( get_tinfo(&type, ea) && type.print(&decl, entry_name.c_str()) )
          {
            // found type info, calc the size of arguments
            func_type_data_t fi;
            if ( type.get_func_details(&fi) && !fi.empty() )
            {
              for ( int k=0; k < fi.size(); k++ )
              {
                int s1 = fi[k].type.get_size();
                uchar szi = inf_get_cc_size_i();
                s1 = qmax(s1, szi);
                argsize += s1;
              }
            }
          }
          else if ( get_long_name(&long_name, ea) > 0
                 && get_name(&true_name, ea, GN_NOT_DUMMY) > 0
                 && long_name != true_name )
          {
            // found mangled name
          }
          else
          {
            // found nothing, just show the name
            if ( get_visible_name(&decl, ea) <= 0 )
              continue;
          }
          if ( argsize == 0 )
          {
            func_t *pfn = get_func(ea);
            if ( pfn != nullptr )
              argsize = pfn->argsize;
          }
          item_t x;
          x.ord = ord;
          x.ea = ea;
          x.decl.swap(decl);
          x.argsize = uint32(argsize);
          list.push_back(x);
        }
        return true;
      }
    
      // function that is called when the user wants to refresh the chooser
      virtual cbret_t idaapi refresh(ssize_t n) override
      {
        init();
        if ( n < 0 )
          return NO_SELECTION;
        return adjust_last_item(n);  // try to preserve the cursor
      }
    };
    DECLARE_TYPE_AS_MOVABLE(entry_chooser_t::item_t);
    
    // column widths
    const int entry_chooser_t::widths_[] =
    {
      CHCOL_DEC | 4,  // Ordinal
      CHCOL_HEX | 8,  // Address
      CHCOL_HEX | 6,  // ArgSize
      70,             // Declaration
    };
    // column headers
    const char *const entry_chooser_t::header_[] =
    {
      "Ordinal",      // 0
      "Address",      // 1
      "ArgSize",      // 2
      "Declaration",  // 3
    };
    
    inline entry_chooser_t::entry_chooser_t()
      : chooser_t(CH_CAN_REFRESH, // user can refresh the chooser using Ctrl-U
                  qnumber(widths_), widths_, header_,
                  "Exported functions"),
        list()
    {
      CASSERT(qnumber(widths_) == qnumber(header_));
    }
    
    void idaapi entry_chooser_t::get_row(
            qstrvec_t *cols_,
            int *,
            chooser_item_attrs_t *,
            size_t n) const
    {
      // assert: n < list.size()
      const item_t &item = list[n];
    
      // generate the line
      qstrvec_t &cols = *cols_;
      cols[0].sprnt("%d", item.ord);
      cols[1].sprnt("%08a", item.ea);
      if ( item.argsize != 0 )
        cols[2].sprnt("%04x", item.argsize);
      cols[3] = item.decl;
      CASSERT(qnumber(header_) == 4);
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      if ( !auto_is_ok()
        && ask_yn(ASKBTN_NO,
                  "HIDECANCEL\n"
                  "The autoanalysis has not finished yet.\n"
                  "The result might be incomplete.\n"
                  "Do you want to continue?") < ASKBTN_YES )
      {
        return true;
      }
    
      // open the window
      entry_chooser_t *ch = new entry_chooser_t();
      ch->choose();
      return true; //-V773
    } //lint !e429 'ch' has not been freed or returned
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      if ( get_entry_qty() == 0 )
        return nullptr;
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      "Generate list of exported function prototypes",
      "Generate list of exported function prototypes",
      "List of exported functions",
      "Ctrl-F11",
    };
    

    getlines

    This sample plugin demonstrates how to get the disassembly lines for one address.

    /*
     *  This is a sample plugin module
     *
     *      It demonstrates how to get the disassembly lines for one address
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <bytes.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      virtual bool idaapi run(size_t) override;
    };
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      ea_t ea = get_screen_ea();
      if ( ask_addr(&ea, "Please enter the disassembly address")
        && is_mapped(ea) )                              // address belongs to disassembly
      {
        int flags = calc_default_idaplace_flags();
        linearray_t ln(&flags);
        idaplace_t pl;
        pl.ea = ea;
        pl.lnnum = 0;
        ln.set_place(&pl);
        msg("printing disassembly lines:\n");
        int n = ln.get_linecnt();                // how many lines for this address?
        for ( int i=0; i < n; i++ )              // process all of them
        {
          qstring buf;
          tag_remove(&buf, *ln.down());          // get line and remove color codes
          msg("%d: %s\n", i, buf.c_str());       // display it on the message window
        }
        msg("total %d lines\n", n);
      }
      return true;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    static const char comment[] = "Generate disassembly lines for one address";
    static const char help[] = "Generate disassembly lines for one address\n";
    
    
    //--------------------------------------------------------------------------
    // This is the preferred name of the plugin module in the menu system
    // The preferred name may be overridden in plugins.cfg file
    
    static const char wanted_name[] = "Disassembly lines sample";
    
    
    // This is the preferred hotkey for the plugin module
    // The preferred hotkey may be overridden in plugins.cfg file
    
    static const char wanted_hotkey[] = "";
    
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      comment,              // long comment about the plugin
      help,                 // multiline help about the plugin
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey         // the preferred hotkey to run the plugin
    };
    

    highlighter

    This plugin will display a colored box at the executed instructions.

    // Highlighter plugin v1.0
    // Highlights executed instructions
    
    // This plugin will display a colored box at the executed instructions.
    // It will take into account only the instructions where the application
    // has been suspended.
    
    // http://www.hexblog.com/2005/11/the_highlighter.html
    
    // Copyright 2005 Ilfak Guilfanov, <[email protected]>
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <dbg.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t;
    struct idd_post_events_t : public post_event_visitor_t
    {
      plugin_ctx_t &ctx;
      idd_post_events_t(plugin_ctx_t &_ctx) : ctx(_ctx) {}
      virtual ssize_t idaapi handle_post_event(
            ssize_t code,
            int notification_code,
            va_list va) override;
    };
    
    //--------------------------------------------------------------------------
    struct exec_prefix_t : public user_defined_prefix_t
    {
      static const int prefix_width = 1;
    
      plugin_ctx_t &ctx;
      exec_prefix_t(plugin_ctx_t &_ctx)
        : user_defined_prefix_t(prefix_width, &_ctx), ctx(_ctx) {}
    
      virtual void idaapi get_user_defined_prefix(
            qstring *out,
            ea_t ea,
            const insn_t &insn,
            int lnnum,
            int indent,
            const char *line) override;
    };
    
    //--------------------------------------------------------------------------
    typedef std::set<ea_t> easet_t;
    struct plugin_ctx_t : public plugmod_t, public event_listener_t
    {
      idd_post_events_t idd_post_events = idd_post_events_t(*this);
    
      exec_prefix_t *exec_prefix = nullptr;
    
      // List of executed addresses
      easet_t execset;
    
      ea_t old_ea = BADADDR;
      int old_lnnum = 0;
    
      plugin_ctx_t()
      {
        hook_event_listener(HT_DBG, this);
      }
      ~plugin_ctx_t()
      {
        // listeners are uninstalled automatically
        // when the owner module is unloaded
        exec_prefix = nullptr; // make lint happy
      }
    
      virtual bool idaapi run(size_t) override;
      virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
    };
    
    //--------------------------------------------------------------------------
    // A sample how to generate user-defined line prefixes
    static const char highlight_prefix[] = { COLOR_INV, ' ', COLOR_INV, 0 };
    void idaapi exec_prefix_t::get_user_defined_prefix(
            qstring *buf,
            ea_t ea,
            const insn_t &,
            int lnnum,
            int indent,
            const char *line)
    {
      buf->qclear();        // empty prefix by default
    
      // We want to display the prefix only the lines which
      // contain the instruction itself
    
      if ( indent != -1 )
        return;           // a directive
      if ( line[0] == '\0' )
        return;        // empty line
      if ( tag_advance(line,1)[-1] == ASH.cmnt[0] )
        return; // comment line...
    
      // We don't want the prefix to be printed again for other lines of the
      // same instruction/data. For that we remember the line number
      // and compare it before generating the prefix
    
      if ( ctx.old_ea == ea && ctx.old_lnnum == lnnum )
        return;
    
      if ( ctx.execset.find(ea) != ctx.execset.end() )
        *buf = highlight_prefix;
    
      // Remember the address and line number we produced the line prefix for:
      ctx.old_ea = ea;
      ctx.old_lnnum = lnnum;
    }
    
    //--------------------------------------------------------------------------
    ssize_t idaapi idd_post_events_t::handle_post_event(
            ssize_t retcode,
            int notification_code,
            va_list va)
    {
      switch ( notification_code )
      {
        case debugger_t::ev_get_debug_event:
          {
            gdecode_t *code = va_arg(va, gdecode_t *);
            debug_event_t *event = va_arg(va, debug_event_t *);
            if ( *code == GDE_ONE_EVENT )    // got an event?
              ctx.execset.insert(event->ea);
          }
          break;
      }
      return retcode;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      info("AUTOHIDE NONE\n"
           "This is the highlighter plugin.\n"
           "It highlights executed instructions if a debug event occurs at them.\n"
           "The plugins is fully automatic and has no parameters.\n");
      return true;
    }
    
    //--------------------------------------------------------------------------
    ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list /*va*/)
    {
      // We set our debug event handler at the beginning and remove it at the end
      // of a debug session
      switch ( code )
      {
        case dbg_process_start:
        case dbg_process_attach:
          exec_prefix = new exec_prefix_t(*this);
          register_post_event_visitor(HT_IDD, &idd_post_events, this);
          break;
        case dbg_process_exit:
          // do not unregister idd_post_events - it should be removed automatically
          delete exec_prefix;
          exec_prefix = nullptr;
          execset.clear();
          break;
      }
      return 0;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    static const char wanted_name[] = "Highlighter";
    static const char wanted_hotkey[] = "";
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      wanted_name,          // long comment about the plugin
      wanted_name,          // multiline help about the plugin
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey,        // the preferred hotkey to run the plugin
    };
    

    ht_output

    This sample plugin demonstrates receiving output window notification callbacks and usage of new output window functions.

    /*
     *  This is a sample plugin demonstrating receiving output window notification callbacks
     *  and using of new output window functions: get_output_curline, get_output_cursor,
     *  get_output_selected_text, add_output_popup
     *
     */
    
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //-------------------------------------------------------------------------
    struct ht_output_plugin_t : public plugmod_t, public event_listener_t
    {
      form_actions_t *fa = nullptr;
      qstring selected_data;
    
      virtual bool idaapi run(size_t arg) override;
      virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
    
      void desc_notification(
            const char *notification_name) const;
      ~ht_output_plugin_t();
    };
    
    //-------------------------------------------------------------------------
    AS_PRINTF(2, 3) static void form_msg(form_actions_t *fa, const char *format, ...)
    {
      textctrl_info_t ti;
      fa->get_text_value(1, &ti);
      va_list va;
      va_start(va, format);
      ti.text.cat_vsprnt(format, va);
      va_end(va);
      fa->set_text_value(1, &ti);
    }
    
    //---------------------------------------------------------------------------
    void ht_output_plugin_t::desc_notification(
            const char *notification_name) const
    {
      form_msg(fa, "Received notification from output window: \"%s\"\n",
               notification_name);
    }
    
    //-------------------------------------------------------------------------
    struct printsel_ah_t : public action_handler_t
    {
      ht_output_plugin_t *plugmod;
    
      printsel_ah_t(ht_output_plugin_t *_plgmod) : plugmod(_plgmod) {}
    
      virtual int idaapi activate(action_activation_ctx_t *) override
      {
        form_msg(plugmod->fa,
                 "User menu item is called for selection: \"%s\"\n",
                 plugmod->selected_data.c_str());
        return 1;
      }
    
      virtual action_state_t idaapi update(action_update_ctx_t *) override
      {
        return AST_ENABLE_ALWAYS;
      }
    };
    
    //---------------------------------------------------------------------------
    // Callback for ui notifications
    static ssize_t idaapi ui_callback(void *ud, int notification_code, va_list va)
    {
      switch ( notification_code )
      {
        // called when IDA is preparing a context menu for a view
        // Here dynamic context-depending user menu items can be added.
        case ui_populating_widget_popup:
          {
            TWidget *f = va_arg(va, TWidget *);
            if ( get_widget_type(f) == BWN_OUTPUT )
            {
              TPopupMenu *p = va_arg(va, TPopupMenu *);
              ht_output_plugin_t *plgmod = (ht_output_plugin_t *) ud;
              plgmod->selected_data.qclear();
              if ( get_output_selected_text(&plgmod->selected_data) )
              {
                action_desc_t desc = DYNACTION_DESC_LITERAL(
                        "Print selection",
                        new printsel_ah_t(plgmod),
                        nullptr, nullptr, -1);
                attach_dynamic_action_to_popup(nullptr, p, desc);
              }
              plgmod->desc_notification("msg_popup");
            }
          }
          break;
      }
      return 0;
    }
    
    //---------------------------------------------------------------------------
    ht_output_plugin_t::~ht_output_plugin_t()
    {
      unhook_from_notification_point(HT_UI, ui_callback, this);
    }
    
    //---------------------------------------------------------------------------
    // Callback for view notifications
    ssize_t idaapi ht_output_plugin_t::on_event(
            ssize_t notification_code,
            va_list va)
    {
      switch ( notification_code )
      {
        case msg_activated:
          desc_notification("msg_activated");
          break;
        case msg_deactivated:
          desc_notification("msg_deactivated");
          break;
        case msg_keydown:
          {
            desc_notification("msg_keydown");
            int key = va_arg(va, int);
            int state = va_arg(va, int);
            form_msg(fa, "Parameters: Key:%d(\'%c\') State:%d\n", key, key, state);
          }
          break;
        case msg_click:
        case msg_dblclick:
          {
            desc_notification(notification_code == msg_click ? "msg_click" : "msg_dblclick");
            int px = va_arg(va, int);
            int py = va_arg(va, int);
            int state = va_arg(va, int);
            qstring buf;
            if ( get_output_curline(&buf, false) )
              form_msg(fa, "Clicked string: %s\n", buf.c_str());
            int cx,cy;
            get_output_cursor(&cx, &cy);
            msg("Parameters: x:%d, y:%d, state:%d\n", px, py, state);
            msg("Cursor position:(%d, %d)\n", cx, cy);
          }
          break;
        case msg_closed:
          desc_notification("msg_closed");
      }
      return 0;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new ht_output_plugin_t;
    }
    
    //--------------------------------------------------------------------------
    // this callback is called when something happens in our editor form
    static int idaapi editor_modcb(int fid, form_actions_t &f_actions)
    {
      ht_output_plugin_t *plgmod = (ht_output_plugin_t *) f_actions.get_ud();
      if ( fid == CB_INIT ) // Initialization
      {
        /* set callback for output window notifications */
        hook_to_notification_point(HT_UI, ui_callback, plgmod);
        hook_event_listener(HT_OUTPUT, plgmod, plgmod);
        plgmod->fa = &f_actions;
      }
      else if ( fid == CB_CLOSE )
      {
        unhook_event_listener(HT_OUTPUT, plgmod);
        unhook_from_notification_point(HT_UI, ui_callback, plgmod);
      }
      return 1;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi ht_output_plugin_t::run(size_t)
    {
      static const char formdef[] =
        "BUTTON NO NONE\n"        // we do not want the standard buttons on the form
        "BUTTON YES NONE\n"
        "BUTTON CANCEL NONE\n"
        "Editor form\n"           // the form title. it is also used to refer to the form later
        "\n"
        "%/%*"                    // placeholder for the 'editor_modcb' callback, and its userdata
        "<Text:t1::40:::>\n"      // text edit control
        "\n";
    
      // structure for text edit control
      textctrl_info_t ti;
      ti.cb = sizeof(textctrl_info_t);
      ti.text = "";
    
      open_form(formdef, 0, editor_modcb, this, &ti);
      return true;
    }
    
    static const char wanted_name[] = "HT_OUTPUT notifications handling example";
    static const char wanted_hotkey[] = "Ctrl-Alt-F11";
    //--------------------------------------------------------------------------
    static const char comment[] = "HT_OUTPUT notifications handling";
    static const char help[] =
            "This pluging demonstrates handling of output window\n"
            "notifications: Activation/Desactivation, adding\n"
            "popup menus, keyboard and mouse events, changing of current\n"
            "cursor position and closing of view\n";
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // plugin flags
      init,                 // initialize
      nullptr,
      nullptr,
      comment,              // long comment about the plugin
                            // it could appear in the status line
                            // or as a hint
    
      help,                 // multiline help about the plugin
    
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey         // the preferred hotkey to run the plugin
    };
    

    ht_view

    This sample plugin demonstrates usage of the view callbacks and adding custom menu items to popup menus.

    /*
     *  This is a sample plugin demonstrating usage of the view callbacks
     *  and adding custom menu items to popup menus
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    #include <bytes.hpp>
    #include <graph.hpp>
    
    #define ACTION1_NAME "ht_view:Act1"
    #define ACTION2_NAME "ht_view:Act2"
    
    //-------------------------------------------------------------------------
    struct ht_view_plugin_t : public plugmod_t, public event_listener_t
    {
      bool hooked = false;
    
      ht_view_plugin_t();
      virtual ~ht_view_plugin_t();
      virtual bool idaapi run(size_t arg) override;
      virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
    
      void desc_notification(
            const char *notification_name,
            TWidget *view) const;
      void desc_mouse_event(
            const view_mouse_event_t *event) const;
    };
    
    //---------------------------------------------------------------------------
    // Callback for ui notifications
    static ssize_t idaapi ui_callback(void *ud, int notification_code, va_list va)
    {
      switch ( notification_code )
      {
        // called when IDA is preparing a context menu for a view
        // Here dynamic context-depending user menu items can be added.
        case ui_populating_widget_popup:
          {
            TWidget *view = va_arg(va, TWidget *);
            if ( get_widget_type(view) == BWN_DISASM )
            {
              TPopupMenu *p = va_arg(va, TPopupMenu *);
              ht_view_plugin_t *plgmod = (ht_view_plugin_t *) ud;
              plgmod->desc_notification("view_popup", view);
              attach_action_to_popup(view, p, ACTION1_NAME);
              attach_action_to_popup(view, p, ACTION2_NAME);
            }
          }
          break;
      }
      return 0;
    }
    
    //-------------------------------------------------------------------------
    struct ahandler_t : public action_handler_t
    {
      bool first;
      ahandler_t(bool _first) : first(_first) {}
      virtual int idaapi activate(action_activation_ctx_t *) override
      {
        msg("User %s menu item is called\n", first ? "first" : "second");
        return true;
      }
    
      virtual action_state_t idaapi update(action_update_ctx_t *) override
      {
        return AST_ENABLE_ALWAYS;
      }
    };
    static ahandler_t ah1(true);
    static ahandler_t ah2(false);
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new ht_view_plugin_t;
    }
    
    //-------------------------------------------------------------------------
    ht_view_plugin_t::ht_view_plugin_t()
    {
      // Register actions
      const action_desc_t actions[] =
      {
    #define ROW(name, label, handler) ACTION_DESC_LITERAL_PLUGMOD(name, label, handler, this, nullptr, nullptr, -1)
        ROW(ACTION1_NAME, "First ht_view's popup menu item", &ah1),
        ROW(ACTION2_NAME, "Second ht_view's popup menu item", &ah2),
    #undef ROW
      };
    
      for ( size_t i = 0, n = qnumber(actions); i < n; ++i )
        register_action(actions[i]);
    }
    
    //-------------------------------------------------------------------------
    ht_view_plugin_t::~ht_view_plugin_t()
    {
      unhook_from_notification_point(HT_UI, ui_callback, this);
    }
    
    //-------------------------------------------------------------------------
    bool idaapi ht_view_plugin_t::run(size_t)
    {
      /* set callback for view notifications */
      if ( !hooked )
      {
        hook_event_listener(HT_VIEW, this);
        hook_to_notification_point(HT_UI, ui_callback, this);
        hooked = true;
        msg("HT_VIEW: installed view notification hook.\n");
      }
    
      return true;
    }
    
    //---------------------------------------------------------------------------
    ssize_t idaapi ht_view_plugin_t::on_event(
            ssize_t notification_code,
            va_list va)
    {
      TWidget *view = va_arg(va, TWidget *);
      switch ( notification_code )
      {
        case view_activated:
          desc_notification("view_activated", view);
          break;
        case view_deactivated:
          desc_notification("view_deactivated", view);
          break;
        case view_keydown:
          {
            desc_notification("view_keydown", view);
            int key = va_arg(va, int);
            int state = va_arg(va, int);
            msg("Parameters: Key:%d(\'%c\') State:%d\n", key, key, state);
          }
          break;
        case view_click:
        case view_dblclick:
          {
            desc_notification(notification_code == view_click ? "view_click" : "view_dblclick", view);
            desc_mouse_event(va_arg(va, view_mouse_event_t*));
            int cx,cy;
            get_cursor(&cx, &cy);
            msg("Cursor position:(%d, %d)\n", cx, cy);
          }
          break;
        case view_curpos:
          {
            desc_notification("view_curpos", view);
            if ( is_idaview(view) )
            {
              char buf[MAXSTR];
              ea2str(buf, sizeof(buf), get_screen_ea());
              msg("New address: %s\n", buf);
            }
          }
          break;
        case view_mouse_over:
          {
            desc_notification("view_mouse_over", view);
            desc_mouse_event(va_arg(va, view_mouse_event_t*));
          }
          break;
        case view_close:
          desc_notification("view_close", view);
      }
      return 0;
    }
    
    //-------------------------------------------------------------------------
    void ht_view_plugin_t::desc_notification(
            const char *notification_name,
            TWidget *view) const
    {
      qstring buffer;
      get_widget_title(&buffer, view);
      msg("Received notification from view %s: \"%s\"\n",
          buffer.c_str(),
          notification_name);
    }
    
    //-------------------------------------------------------------------------
    void ht_view_plugin_t::desc_mouse_event(
            const view_mouse_event_t *event) const
    {
      int px = event->x;
      int py = event->y;
      int state = event->state;
      qstring over_txt;
      const selection_item_t *item = event->location.item;
      if ( event->rtype != TCCRT_FLAT && item != nullptr )
      {
        if ( item->is_node )
          over_txt.sprnt("node %d", item->node);
        else
          over_txt.sprnt("edge %d -> %d", item->elp.e.src, item->elp.e.dst);
      }
      else
      {
        over_txt = "(nothing)";
      }
      msg("Parameters: x:%d, y:%d, state:%d, over:%s\n", px, py, state, over_txt.c_str());
    }
    
    
    //-------------------------------------------------------------------------
    static const char wanted_name[] = "HT_VIEW notification handling example";
    static const char wanted_hotkey[] = "";
    //--------------------------------------------------------------------------
    static const char comment[] = "HT_VIEW notification Handling";
    static const char help[] =
            "This pluging demonstrates handling of custom and IdaView\n"
            "notifications: Activation/Desactivation of views, adding\n"
            "popup menus, keyboard and mouse events, changing of current\n"
            "address and closing of view\n";
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // plugin flags
      init,                 // initialize
      nullptr,
      nullptr,
      comment,              // long comment about the plugin
                            // it could appear in the status line
                            // or as a hint
    
      help,                 // multiline help about the plugin
    
      wanted_name,          // the preferred short name of the plugin
      wanted_hotkey         // the preferred hotkey to run the plugin
    };
    

    mtsample

    Sample multi-threaded plugin module.

    /*
     *  This is a sample multi-threaded plugin module
     *
     *  It creates 3 new threads. Each threads sleeps and prints a message in a loop
     *
     */
    
    #ifdef __NT__
    #include <windows.h>
    #endif
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    #ifdef __NT__
    #include <windows.h>
    #endif
    
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      qthread_t children[10] = { nullptr };
      int nchilds = 0;
    
      ~plugin_ctx_t() { term(); }
      void term()
      {
        if ( nchilds > 0 )
        {
          msg("Killing all threads\n");
          for ( int i=0; i < nchilds; i++ )
          {
            qthread_kill(children[i]);
            qthread_join(children[i]);
            // cancel all pending requests from the killed thread
            cancel_thread_exec_requests(children[i]);
            qthread_free(children[i]);
          }
          msg("Killed all threads\n");
          nchilds = 0;
        }
      }
      virtual bool idaapi run(size_t) override;
    };
    
    //--------------------------------------------------------------------------
    static void say_hello(size_t id, qthread_t tid, int cnt)
    {
      struct ida_local hello_t : public exec_request_t
      {
        uint64 nsecs;
        size_t id;
        qthread_t tid;
        int cnt;
        int idaapi execute(void) override
        {
          uint64 now = get_nsec_stamp();
          int64 delay = now - nsecs;
          msg("Hello %d from thread %" FMT_Z ". tid=%p. current tid=%p (delay=%" FMT_64 "d)\n",
              cnt, id, tid, qthread_self(), delay);
          return 0;
        }
        hello_t(size_t _id, qthread_t _tid, int _cnt) : id(_id), tid(_tid), cnt(_cnt)
        {
          nsecs = get_nsec_stamp();
        }
      };
      hello_t hi(id, tid, cnt);
    
      int mff;
      switch ( id % 3 )
      {
        case 0: mff = MFF_FAST;  break;
        case 1: mff = MFF_READ;  break;
        default:
        case 2: mff = MFF_WRITE; break;
      }
      execute_sync(hi, mff);
    }
    
    //--------------------------------------------------------------------------
    static int idaapi thread_func(void *ud)
    {
      size_t id = (size_t)ud;
      qthread_t tid = qthread_self();
      int cnt = 0;
      srand(id ^ (size_t)tid);
      while ( true )
      {
        say_hello(id, tid, cnt++);
        int r = rand() % 1000;
        qsleep(r);
      }
      return 0;
    }
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      if ( nchilds == 0 )
      {
        children[nchilds] = qthread_create(thread_func, (void *)(ssize_t)nchilds); nchilds++;
        children[nchilds] = qthread_create(thread_func, (void *)(ssize_t)nchilds); nchilds++;
        children[nchilds] = qthread_create(thread_func, (void *)(ssize_t)nchilds); nchilds++;
        msg("Three new threads have been created. Main thread id %p\n", qthread_self());
        for ( int i=0; i < 5; i++ )
          say_hello(-1, 0, 0);
      }
      else
      {
        term();
      }
      return true;
    }
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      nullptr,              // long comment about the plugin
      nullptr,              // multiline help about the plugin
      "Multi-threaded sample", // the preferred short name of the plugin
      nullptr,              // the preferred hotkey to run the plugin
    };
    

    This sample plugin demonstrates how to customize navigation band colors.

    /*
     *  This plugin demonstrates how to customize navigation band colors.
     *  Launch the plugin like so:
     *    - to install: ida_loader.load_and_run_plugin("navcolor", 1)
     *    - to uninstall: ida_loader.load_and_run_plugin("navcolor", 0)
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      nav_colorizer_t *old_col_fun = nullptr;
      void *old_col_ud = nullptr;
      bool installed = false;
    
      //lint -esym(1540, plugin_ctx_t::old_col_fun, plugin_ctx_t::old_col_ud)
      ~plugin_ctx_t()
      {
        // uninstall our callback for navigation band, otherwise ida will crash
        maybe_uninstall();
      }
      virtual bool idaapi run(size_t) override;
    
      bool maybe_install();
      bool maybe_uninstall();
    };
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t code)
    {
      return code == 1 ? maybe_install() : maybe_uninstall();
    }
    
    //--------------------------------------------------------------------------
    // Callback that calculates the pixel color given the address and the number of bytes
    static uint32 idaapi my_colorizer(ea_t ea, asize_t nbytes, void *ud)
    {
      plugin_ctx_t &ctx = *(plugin_ctx_t *)ud;
      // you are at your own here. just for the sake of illustrating how things work
      // we will invert all colors
      uint32 color = ctx.old_col_fun(ea, nbytes, ctx.old_col_ud);
      return ~color;
    }
    
    //-------------------------------------------------------------------------
    bool plugin_ctx_t::maybe_install()
    {
      bool ok = !installed;
      if ( ok )
      {
        set_nav_colorizer(&old_col_fun, &old_col_ud, my_colorizer, this);
        installed = true;
      }
      return ok;
    }
    
    //-------------------------------------------------------------------------
    bool plugin_ctx_t::maybe_uninstall()
    {
      bool ok = installed;
      if ( ok )
      {
        set_nav_colorizer(nullptr, nullptr, old_col_fun, old_col_ud);
        installed = false;
      }
      return ok;
    }
    
    //--------------------------------------------------------------------------
    // initialize the plugin
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      nullptr,              // long comment about the plugin
      nullptr,              // multiline help about the plugin
      "Modify navigation band colors",// the preferred short name of the plugin
      nullptr,              // the preferred hotkey to run the plugin
    };
    

    openform

    This plugin demonstrates how to use non modal forms.

    /*
     *  This plugin demonstrates how to use non modal forms.
     *  It creates 2 windows on the screen:
     *      - a window with 4 buttons: dock, undock, show, hide      (CONTROL FORM)
     *      - a window with a text edit control and a list control   (EDITOR FORM)
     *  The buttons of the first window can be used to manage the second window.
     *  We will call the first window 'CONTROL FORM' and the second window 'EDITOR
     *  FORM', just to be able to reference them easily.
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    //---------------------------------------------------------------------------
    // chooser (list view) items
    static const char *const names[] =
    {
      "Item one",
      "Item two",
      "Item three"
    };
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      // the editor form
      TWidget *editor_widget = nullptr;
    
      // contents of the text field for each item
      qstring txts[qnumber(names)] =
      {
        "Text one:\n This is text for item one",
        "Text two:\n And this is text for item two",
        "Text three:\n And finally text for the last item"
      };
    
      // Current index for chooser list view
      size_t curidx = 0;
      // Form actions for control dialog
      form_actions_t *control_fa = nullptr;
      // Defines where to place new/existing editor window
      bool dock = false;
    
      virtual bool idaapi run(size_t) override;
    
      int editor_modcb(int fid, form_actions_t &fa);
      void open_editor_form(int options = 0);
      void close_editor_form();
      int control_modcb(int fid, form_actions_t &fa);
      void update_buttons(form_actions_t &fa);
    };
    
    //---------------------------------------------------------------------------
    struct of_chooser_t : public chooser_t
    {
    public:
      // this object must be allocated using `new`
      // as it used in the non-modal form
      of_chooser_t() : chooser_t()
      {
        columns = 1;
        static const int widths_[] = { 12 };
        static const char *const header_[] = { "Name" };
        widths = widths_;
        header = header_;
      }
    
      virtual size_t idaapi get_count() const override { return qnumber(names); }
      virtual void idaapi get_row(
            qstrvec_t *cols,
            int *,
            chooser_item_attrs_t *,
            size_t n) const override
      {
        (*cols)[0] = names[n];
      }
    };
    
    // Form actions for editor window
    enum editor_form_actions
    {
      TEXT_CHANGED  = 1,
      ITEM_SELECTED = 2,
    };
    
    // Form actions for control window
    enum control_form_actions
    {
      BTN_DOCK   = 10,
      BTN_UNDOCK = 11,
      BTN_OPEN   = 12,
      BTN_CLOSE  = 13,
    };
    
    //--------------------------------------------------------------------------
    inline void enable_button(form_actions_t &fa, int fid, bool enabled)
    {
      fa.enable_field(fid, enabled);
    }
    
    //--------------------------------------------------------------------------
    // Update control window buttons state
    void plugin_ctx_t::update_buttons(form_actions_t &fa)
    {
      bool visible = editor_widget != nullptr;
      enable_button(fa, 10, !dock && visible);
      enable_button(fa, 11, dock && visible);
      enable_button(fa, 12, !visible);
      enable_button(fa, 13, visible);
    }
    
    //--------------------------------------------------------------------------
    // this callback is called when the user clicks on a button
    static int idaapi btn_cb(int, form_actions_t &)
    {
      msg("button has been pressed -> \n");
      return 0;
    }
    
    //--------------------------------------------------------------------------
    // this callback is called when something happens in our non-modal editor form
    static int idaapi editor_modcb_(int fid, form_actions_t &fa)
    {
      plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
      return ctx.editor_modcb(fid, fa);
    }
    int plugin_ctx_t::editor_modcb(int fid, form_actions_t &fa)
    {
      switch ( fid )
      {
        case CB_INIT:     // Initialization
          msg("init editor form\n");
          break;
        case CB_CLOSE:    // Closing the form
          msg("closing editor form\n");
          // mark the form as closed
          editor_widget = nullptr;
          // If control form exists then update buttons
          if ( control_fa != nullptr )
            update_buttons(*control_fa);
          break;
        case TEXT_CHANGED:     // Text changed
          {
            textctrl_info_t ti;
            fa.get_text_value(1, &ti);
            txts[curidx] = ti.text;
          }
          msg("text has been changed\n");
          break;
        case ITEM_SELECTED:    // list item selected
          {
            sizevec_t sel;
            if ( fa.get_chooser_value(2, &sel) )
            {
              curidx = sel[0];
              textctrl_info_t ti;
              ti.cb = sizeof(textctrl_info_t);
              ti.text = txts[curidx];
              fa.set_text_value(1, &ti);
            }
          }
          msg("selection has been changed\n");
          break;
        default:
          msg("unknown id %d\n", fid);
          break;
      }
      return 1;
    }
    //---------------------------------------------------------------------------
    // create and open the editor form
    void plugin_ctx_t::open_editor_form(int options)
    {
      static const char formdef[] =
        "BUTTON NO NONE\n"        // we do not want the standard buttons on the form
        "BUTTON YES NONE\n"
        "BUTTON CANCEL NONE\n"
        "Editor form\n"           // the form title. it is also used to refer to the form later
        "\n"
        "%/%*"                    // placeholder for the 'editor_modcb' callback
        "\n"
        "<List:E2::30:1::><|><Text:t1::60:::>\n" // text edit control and chooser control separated by splitter
        "\n";
      // structure for text edit control
      textctrl_info_t ti;
      ti.cb = sizeof(textctrl_info_t);
      ti.text = txts[0];
      // structure for chooser list view
      of_chooser_t *ofch = new of_chooser_t();
      // selection for chooser list view
      sizevec_t selected;
      selected.push_back(0);  // first item by default
      editor_widget = open_form(formdef,
                                options,
                                editor_modcb_, this,
                                ofch, &selected,
                                &ti);
    } //lint !e429 custodial pointer 'ofch' likely not freed nor returned
    
    
    //---------------------------------------------------------------------------
    void plugin_ctx_t::close_editor_form()
    {
      msg("closing editor widget\n");
      close_widget(editor_widget, WCLS_CLOSE_LATER);
      editor_widget = nullptr;
    }
    //--------------------------------------------------------------------------
    inline void dock_form(bool _dock)
    {
      set_dock_pos("Editor form",
                   "IDA View-A",
                   _dock ? DP_TAB : DP_FLOATING);
    }
    
    //--------------------------------------------------------------------------
    // this callback is called when something happens in our non-modal control form
    static int idaapi control_modcb_(int fid, form_actions_t &fa)
    {
      plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
      return ctx.control_modcb(fid, fa);
    }
    int plugin_ctx_t::control_modcb(int fid, form_actions_t &fa)
    {
      switch ( fid )
      {
        case CB_INIT:   // Initialization
          msg("init control form\n");
          dock = false;
          control_fa = &fa;   // remember the 'fa' for the future
          break;
        case CB_CLOSE:  // Closing
          msg("closing control form\n");
          control_fa = nullptr;
          return 1;
        case BTN_DOCK:
          msg("dock editor form\n");
          dock = true;
          dock_form(dock);
          break;
        case BTN_UNDOCK:
          msg("undock editor form\n");
          dock = false;
          dock_form(dock);
          break;
        case BTN_OPEN:
          msg("open editor form\n");
          open_editor_form(WOPN_DP_TAB|WOPN_RESTORE);
          dock_form(dock);
          break;
        case BTN_CLOSE:
          close_editor_form();
          break;
        default:
          msg("unknown id %d\n", fid);
          return 1;
      }
      update_buttons(fa);
      return 1;
    }
    
    //--------------------------------------------------------------------------
    // the main function of the plugin
    bool idaapi plugin_ctx_t::run(size_t)
    {
      // first open the editor form
      open_editor_form(WOPN_RESTORE);
    
      static const char control_form[] =
        "BUTTON NO NONE\n"          // do not display standard buttons at the bottom
        "BUTTON YES NONE\n"
        "BUTTON CANCEL NONE\n"
        "Control form\n"            // the title. it is used to refer to the form later
        "%/%*"                      // placeholder for control_modcb
        "<Dock:B10:30:::><Undock:B11:30:::><Show:B12:30:::><Hide:B13:30:::>\n"; // Create control buttons
    
      open_form(control_form,
                WOPN_RESTORE,
                control_modcb_, this,
                btn_cb, btn_cb, btn_cb, btn_cb);
      set_dock_pos("Control form", nullptr, DP_FLOATING, 0, 0, 300, 100);
      return true;
    }
    
    //--------------------------------------------------------------------------
    // initialize the plugin
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,
      nullptr,
      nullptr,
      nullptr,
      nullptr,
      "Open non-modal form sample",// the preferred short name of the plugin
      nullptr,
    };
    

    procext

    Sample plugin that extends the IBM PC processor module to disassemble some NEC V20 instructions.

    /*
     *  This is a sample plugin module
     *  It extends the IBM PC processor module to disassemble some NEC V20 instructions
     *  This is a sample file, it supports just two instructions!
     *
     */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <bytes.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    int data_id;
    
    //--------------------------------------------------------------------------
    // Context data for the plugin. This object is created by the init()
    // function and hold all local data.
    struct plugin_ctx_t : public plugmod_t, public event_listener_t
    {
      ea_t ea = 0; // current address within the instruction
    
      netnode nec_node;
      bool hooked = false;
    
      plugin_ctx_t();
      ~plugin_ctx_t();
    
      // This function is called when the user invokes the plugin.
      virtual bool idaapi run(size_t) override;
      // This function is called upon some events.
      virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
    
      size_t ana(insn_t &insn);
      void process_rm(insn_t &insn, op_t &x, uchar postbyte);
    };
    
    static const char node_name[] = "$ sample NEC processor extender parameters";
    
    
    // Some definitions from IBM PC:
    
    #define segrg specval_shorts.high  // IBM PC expects the segment address
                                       // to be here
    #define aux_short       0x0020  // short (byte) displacement used
    #define aux_basess      0x0200  // SS based instruction
    
    #define R_ss  18
    #define R_ds  19
    //--------------------------------------------------------------------------
    // This plugin supports just 2 instructions:
    // Feel free to add more...
    
    // 0FH 20H                      ADD4S       ; Addition for packed BCD strings
    // 0FH 12H Postbyte     CLEAR1  reg/mem8,CL ; Clear one bit
    
    enum nec_insn_type_t
    {
      NEC_add4s = CUSTOM_INSN_ITYPE,
      NEC_clear1,
    };
    
    //----------------------------------------------------------------------
    static int get_dataseg(insn_t &insn, int defseg)
    {
      if ( defseg == R_ss )
        insn.auxpref |= aux_basess;
      return defseg;
    }
    
    //--------------------------------------------------------------------------
    //
    //              process r/m byte of the instruction
    //
    void plugin_ctx_t::process_rm(insn_t &insn, op_t &x, uchar postbyte)
    {
      int Mod = (postbyte >> 6) & 3;
      x.reg = postbyte & 7;
      if ( Mod == 3 )               // register
      {
        if ( x.dtype == dt_byte )
          x.reg += 8;
        x.type = o_reg;
      }
      else                          // memory
      {
        if ( Mod == 0 && x.reg == 6 )
        {
          x.type = o_mem;
          x.offb = uchar(ea-insn.ea);
          x.addr = get_word(ea); ea+=2;
          x.segrg = (uint16)get_dataseg(insn, R_ds);
        }
        else
        {
          x.type = o_phrase;        // x.phrase contains the base register
          x.addr = 0;
          int reg = (x.phrase == 2 || x.phrase == 3 || x.phrase == 6) ? R_ss : R_ds;
          x.segrg = (uint16)get_dataseg(insn, reg);
                                    // [bp+si],[bp+di],[bp] by SS
          if ( Mod != 0 )
          {
            x.type = o_displ;       // i.e. phrase + offset
            x.offb = uchar(ea-insn.ea);
            if ( Mod == 1 )
            {
              x.addr = char(get_byte(ea++));
              insn.auxpref |= aux_short;
            }
            else
            {
              x.addr = get_word(ea); ea+=2;
            }
          }
        }
      }
    }
    
    //--------------------------------------------------------------------------
    // Analyze an instruction and fill the 'insn' structure
    size_t plugin_ctx_t::ana(insn_t &insn)
    {
      int code = get_byte(ea++);
      if ( code != 0x0F )
        return 0;
      code = get_byte(ea++);
      switch ( code )
      {
        case 0x20:
          insn.itype = NEC_add4s;
          return 2;
        case 0x12:
          insn.itype = NEC_clear1;
          {
            uchar postbyte = get_byte(ea++);
            process_rm(insn, insn.Op1, postbyte);
            insn.Op2.type = o_reg;
            insn.Op2.reg  = 9; // 9 is CL for IBM PC
            return size_t(ea - insn.ea);
          }
        default:
          return 0;
      }
    }
    
    //--------------------------------------------------------------------------
    // Return the instruction mnemonics
    const char *get_insn_mnem(const insn_t &insn)
    {
      if ( insn.itype == NEC_add4s )
        return "add4s";
      return "clear1";
    }
    
    //--------------------------------------------------------------------------
    // This function can be hooked to various kernel events.
    // In this particular plugin we hook to the HT_IDP group.
    // As soon the kernel needs to decode and print an instruction, it will
    // generate some events that we intercept and provide our own response.
    //
    // We extend the processor module to disassemble opcode 0x0F
    // (This is a hypothetical example)
    // There are 2 different possible approaches for the processor extensions:
    //  A. Quick & dirty
    //       Implement reaction to ev_ana_insn and ev_out_insn.
    //       The first checks if the instruction is valid.
    //       The second generates its text.
    //  B. Thourough and clean
    //       Implement all relevant callbacks.
    //       ev_ana_insn fills the 'insn' structure.
    //       ev_emu_insn creates all xrefs using ua_add_[cd]ref functions.
    //       ev_out_insn generates the textual representation of the instruction.
    //          It is required only if the instruction requires special processing
    //          or the processor module cannot handle the custom instruction for
    //          any reason.
    //       ev_out_operand generates the operand representation (only if the
    //          operand requires special processing).
    //       ev_out_mnem generates the instruction mnemonics.
    // The main difference between these 2 approaches is in the creation of
    // cross-references and the amount of special processing required by the
    // new instructions.
    
    // The quick & dirty approach.
    // We just produce the instruction mnemonics along with its operands.
    // No cross-references are created. No special processing.
    ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list va)
    {
      switch ( code )
      {
        case processor_t::ev_ana_insn:
          {
            insn_t *insn = va_arg(va, insn_t *);
            ea = insn->ea;
            size_t length = ana(*insn);
            if ( length )
            {
              insn->size = (uint16)length;
              return insn->size;       // event processed
            }
          }
          break;
        case processor_t::ev_out_mnem:
          {
            outctx_t *ctx = va_arg(va, outctx_t *);
            const insn_t &insn = ctx->insn;
            if ( insn.itype >= CUSTOM_INSN_ITYPE )
            {
              ctx->out_line(get_insn_mnem(insn), COLOR_INSN);
              return 1;
            }
          }
          break;
    #ifdef ENABLE_MERGE
    #endif
        case processor_t::ev_privrange_changed:
          // recreate node as it was migrated
          if ( nec_node != BADNODE )
            nec_node.create(node_name);
          break;
      }
      return 0;                     // event is not processed
    }
    
    //--------------------------------------------------------------------------
    // Initialize the plugin.
    // IDA will call this function only once.
    // If this function returns nullptr, IDA will unload the plugin.
    // Otherwise the plugin returns a pointer to a newly created context structure.
    //
    // In this example we check the processor type and make the decision.
    // You may or may not check any other conditions to decide what you do:
    // whether your plugin wants to work with the database or not.
    
    static plugmod_t *idaapi init()
    {
      processor_t &ph = PH;
      if ( ph.id != PLFM_386 )
        return nullptr;
      auto plugmod = new plugin_ctx_t;
      set_module_data(&data_id, plugmod);
      return plugmod;
    }
    
    //-------------------------------------------------------------------------
    plugin_ctx_t::plugin_ctx_t()
    {
      nec_node.create(node_name);
      hooked = nec_node.altval(0) != 0;
      if ( hooked )
      {
        hook_event_listener(HT_IDP, this);
        msg("NEC V20 processor extender is enabled\n");
      }
    }
    
    //--------------------------------------------------------------------------
    // Terminate the plugin.
    // This destructor will be called before unloading the plugin.
    plugin_ctx_t::~plugin_ctx_t()
    {
      clr_module_data(data_id);
      // listeners are uninstalled automatically
      // when the owner module is unloaded
    }
    
    //--------------------------------------------------------------------------
    // The plugin method
    // This is the main function of plugin.
    // It will be called when the user selects the plugin from the menu.
    // The input argument is usually zero. Non-zero values can be specified
    // by using load_and_run_plugin() or through plugins.cfg file (discouraged).
    bool idaapi plugin_ctx_t::run(size_t)
    {
      if ( hooked )
        unhook_event_listener(HT_IDP, this);
      else
        hook_event_listener(HT_IDP, this);
      hooked = !hooked;
      nec_node.create(node_name);
      nec_node.altset(0, hooked);
      info("AUTOHIDE NONE\n"
           "NEC V20 processor extender now is %s", hooked ? "enabled" : "disabled");
      return true;
    }
    
    //--------------------------------------------------------------------------
    static const char comment[] = "NEC V20 processor extender";
    static const char help[] =
      "A sample plugin module\n"
      "\n"
      "This module shows you how to create plugin modules.\n"
      "\n"
      "It supports some NEC V20 instructions\n"
      "and shows the current address.\n";
    
    //--------------------------------------------------------------------------
    // This is the preferred name of the plugin module in the menu system
    // The preferred name may be overridden in plugins.cfg file
    
    static const char desired_name[] = "NEC V20 processor extender";
    
    // This is the preferred hotkey for the plugin module
    // The preferred hotkey may be overridden in plugins.cfg file
    
    static const char desired_hotkey[] = "";
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_PROC           // this is a processor extension plugin
    | PLUGIN_MULTI,         // this plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      comment,              // long comment about the plugin. not used.
      help,                 // multiline help about the plugin. not used.
      desired_name,         // the preferred short name of the plugin
      desired_hotkey        // the preferred hotkey to run the plugin
    };
    

    ui_requests

    This plugin demonstrates the UI requests and the process_ui_action()

    /*
    * This is a sample plugin to demonstrate the UI requests and the process_ui_action()
    * One process_ui_action() can be processed during an UI request.
    * The UI request is a nice example to show how to schedule UI actions for sequential execution
    */
    
    #include <ida.hpp>
    #include <idp.hpp>
    #include <graph.hpp>
    #include <loader.hpp>
    #include <kernwin.hpp>
    
    
    //--------------------------------------------------------------------------
    struct plugin_ctx_t : public plugmod_t
    {
      int req_id = 0;
    
      ~plugin_ctx_t()
      {
        if ( req_id != 0 && cancel_exec_request(req_id) )
          msg("Cancelled unexecuted ui_request\n");
      }
    
      virtual bool idaapi run(size_t) override;
    };
    
    //--------------------------------------------------------------------------
    bool idaapi plugin_ctx_t::run(size_t)
    {
      class msg_req_t: public ui_request_t
      {
        const char *_msg;
      public:
        msg_req_t(const char *mesg): _msg(qstrdup(mesg)) {}
        ~msg_req_t() { qfree((void *)_msg); }
        virtual bool idaapi run() override
        {
          msg("%s", _msg);
          return false;
        }
      };
    
      class msgs_req_t: public ui_request_t
      {
        int count;
      public:
        msgs_req_t(int cnt): count(cnt) {}
        virtual bool idaapi run() override
        {
          msg("%d\n", count);
          return --count != 0;
        }
      };
    
      req_id = execute_ui_requests(
        new msg_req_t("print "),
        new msg_req_t("3 countdown "),
        new msg_req_t("mesages:\n"),
        new msgs_req_t(3),
        nullptr);
      return true;
    }
    
    
    //--------------------------------------------------------------------------
    static plugmod_t *idaapi init()
    {
      return new plugin_ctx_t;
    }
    
    //--------------------------------------------------------------------------
    //
    //      PLUGIN DESCRIPTION BLOCK
    //
    //--------------------------------------------------------------------------
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // The plugin can work with multiple idbs in parallel
      init,                 // initialize
      nullptr,
      nullptr,
      "This is a sample ui_requests plugin.",
                            // long comment about the plugin
      "A sample ui_requests and process_ui_commands plugin",
                            // multiline help about the plugin
      "UI requests demo",   // the preferred short name of the plugin
      "Shift-F8"            // the preferred hotkey to run the plugin
    };
    

    More plugin samples

    We encourage you to browse the plugins folder inside the SDK directory to check out all of examples, including more complex and advances ones, like FindCrypt program, that finds constants used in crypto algorithms, or qproject, that demonstrates how to fully use the Qt environment in IDA.

    Modules samples

    The modules folder contains sample processor modules, that are used to add support for new instruction sets or architectures to IDA. Inside the README file you will find instructions on how to compile and run the modules.

    If you are going to write a new processor module, it’s recommended to follow the below steps:

    1. copy the sample module files to a new directory
    2. edit ins.cpp and ins.hpp files
    3. write the analyser ana.cpp
    4. then outputter
    5. and emulator (you can start with an almost empty emulator)
    6. describe the processor & assembler, write the notify() function

    Loaders samples

    The ldr folder includes source code for new file format loaders:

    • aif ARM Image File
    • amiga Amige Hunk File
    • aof ARM Object File
    • aout a.out
    • dos MS DOS File
    • dump Memory Dump File
    • geos GEOS File
    • hex Intel/Motorola HEX File
    • hpsom HP SOM
    • intelomf Intel Object File
    • javaldr Java Class Loader
    • mas Macro Assembler
    • nlm Netware Loader Module
    • os9 FLEX/9
    • pef Portable Executable Format (MAC)
    • pilot Palm Pilot
    • qnx Qnx
    • rt11 RT/11
    • w32run Watcom RUN32

    ready to be compiled, similarly as processor module samples.

    Decompiler SDK sample plugins

    The exemplary decompiler plugins are shipped with the C++ SDK and can be found in the plugins folder (vds1-vds20) alongside other plugins.

    Below are descriptions of sample decompiler plugins.

    Sample 1

    This plugin decompiles the current function and prints the result in the message window. It is useful to learn how to initialize a decompiler plugin. Please note that all decompiler sample plugins have the “hexrays_” prefix in their names. This is done to make sure that the decompiler plugins are loaded after the hexrays plugin. Otherwise they would see that the decompiler is missing and immediately terminate.

    We recommend you to keep the same naming scheme: please use the “hexrays_” prefix for your decompiler plugins.

    N.B.: if you’re writing a plugin for non-x86 version of the decompiler, you should use another prefix. For example, the x64 decompiler is named “hexx64”, ARM is “hexarm” and so on. To be certain, check IDA’s “plugins” directory. To debug plugin loading issues, you can use -z20 switch when running IDA.

    Sample 2

    This plugin shows how to hook to decompiler events and react to them. It also shows how to visit all ctree elements and modify them.

    This plugin waits for the decompilation result to be ready and replaces zeroes in pointer contexts with NULLs. One might say that this is just cosmetic change, but it makes the output more readable.

    Since the plugin hooks to events, it is fully automatic. The user can disable it by selecting it from the Edit, Plugins menu.

    Sample 3

    This plugin shows

    - how to add a new popup menu item
    - how to map the cursor position to ctree element
    - how to modify ctree
    - how to make the changes persistent
    

    This is a quite complex plugin but it is thoroughly commented.

    Sample 4

    This plugin dumps all user-defined information to the message window. Read the source code to learn how to access various user-defined data from your plugins:

    - label names
    - indented comments
    - number formats
    - local variable names, types, comments
    

    Sample 5

    This plugin generates a graph from the current pseudocode and displays it with wingraph32.

    The source code can be used to learn ctree details.

    Sample 6

    This plugin modifies the decompilation output: removes some space characters.

    The source code can be used to learn the output text.

    Sample 7

    This plugin demonstrates how to use the cblock_t::iterator class. It enumerates all instructions of a block statement.

    Sample 8

    This plugin demonstrates how to use the udc_filter_t (User-Defined Call generator) class, which allows replacing cryptic function calls, with a simpler/more-readable counterpart.

    Sample 9

    This plugin demonstrates how to generate microcode for a given function and print it into the output window. It displays fully optimized microcode but it is also possible to retrieve microcode from earlier stages of decompilation. Generating the microcode text should be used only for debugging purposes. Printing microcode in production code may lead to crashes or wrong info.

    Sample 10

    This plugin installs a custom microcode optimization rule: call !DbgRaiseAssertionFailure fast:.0 => call !DbgRaiseAssertionFailure <fast:“char *” “assertion text”>.0

    See also sample19 for another example.

    Sample 11

    This plugin installs a custom inter-block optimization rule:

    goto L1     =>        goto L@
    ...
    

    L1: goto L2

    In other words we fix a goto target if it points to a chain of gotos. This improves the decompiler output is some cases.

    Sample 12

    This plugin displays list of direct references to a register from the current instruction.

    Sample 13

    This plugin generates microcode for selection and dumps it to the output window.

    Sample 14

    This plugin shows xrefs to the called function as the decompiler output. All calls are displayed with the call arguments.

    Sample 15

    This plugin shows list of possible values of a register using the value range analysis.

    Sample 16

    This plugin installs a custom instruction optimization rule:

    mov #N, var.4                  mov #N, var.4
    xor [email protected], #M, [email protected]    => mov #NM, [email protected]
                                     where NM == (N>>8)^M
    

    We need this rule because the decompiler cannot propagate the second byte of VAR into the xor instruction.

    The XOR opcode can be replaced by any other, we do not rely on it. Also operand sizes can vary.

    Sample 17

    This plugin shows how to use “Select offsets” widget (select_udt_by_offset() API). This plugin repeats the Alt-Y functionality.

    Sample 18

    This plugin shows how to specify a register value at a desired location. Such a functionality may be useful when the code to decompile is obfuscated and uses opaque predicates.

    Sample 19

    This plugin shows how to install a custom microcode optimization rule. Custom rules are useful to handle obfuscated code. See also sample10 for another example.

    Sample 20

    This plugin shows how to modify the decompiler output on the fly by adding dynamic comments.

    How to create a plugin with C++ SDK?

    Intro

    The C++ SDK allows developers to create powerful plugins that can extend the IDA Pro capabilities, that enable deeper integration and more control over IDA’s core functionality.

    This guide will walk you through creating a basic plugin using the C++ SDK, demonstrating the structure and best practices for developing C++ plugins for IDA.

    Prerequistes

    • Installed the latest C++ SDK. You can get it from our GitHub repository.
    • A working C++ development environment (compiler, debugger, etc.). For the Windows Visual Studio users, a plugin template has been created that can be used to create plugin solutions.

    Before you start

    1. Check the C++ SDK Reference Documentation for a comprehensive list of classes, functions, and available APIs.

    2. Familiarize yourself with the plugin_t class and plugmod_t, that are fundamental for creating plugins using the C++ SDK.

    3. Ensure compatibility with the latest version of IDA Pro and refer to the C++ SDK Porting Guide for any recent changes that might affect your plugin.

    Overview of the Plugin Structure

    An IDA Pro plugin written in C++ typically involves:

    • A class that inherits from plugmod_t, this class will implement the actual plugin functionality.
    • An init() function that will return a pointer to the above mentioned class.
    • Flags that specify when and how the plugin should be loaded and unloaded.

    Writing a plugin in C++—basic steps

    Create a basic plugin structure

    Start by creating a new C++ source file for your plugin. This file will contain the main logic and define the necessary classes and methods for your plugin.

    Define base classes

    When creating a plugin, it’s recommended to create an instace of the class plugin_t with specific flags and a class inheriting from plugmod_t that performs the core functionality.

    Example of `implementation:

    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <funcs.hpp>
    
    // Define the class that inherits from plugmod_t
    class MyPlugmod : public plugmod_t 
    {
    public:
    	// Constructor
    	MyPlugmod() 
    	{
    		msg("MyPlugmod: Constructor called.\n");
    	}
    
    	// Destructor
    	virtual ~MyPlugmod() 
    	{
    		msg("MyPlugmod: Destructor called.\n");
    	}
    
    	// Method that gets called when the plugin is activated
    	virtual bool idaapi run(size_t arg) override
    	{
    		msg("MyPlugmod.run() called with arg: %d\n", arg);
    
    		// Iterate through all functions and print their names and addresses
    		int n = get_func_qty();
    		for (int i = 0; i < n; i++) {
    			func_t* pfn = getn_func(i);
    			if (pfn == nullptr)
    				continue;
    
    			qstring name;
    			get_func_name(&name, pfn->start_ea);
    			msg("Function %s at address 0x%llX\n", name.length() ? name.c_str(): "-UNK-" , pfn->start_ea);
    		}
    
    		return true;
    	}
    };
    
    static plugmod_t* idaapi init(void)
    {
    	return new MyPlugmod();
    }
    
    plugin_t PLUGIN =
    {
      IDP_INTERFACE_VERSION,
      PLUGIN_MULTI,         // plugin flags
      init,                 // initialize
      nullptr,              // terminate. this pointer can be nullptr
      nullptr,              // invoke the plugin
      nullptr,              // long comment about the plugin
      nullptr,              // multiline help about the plugin
      "List functions",		// the preferred short name of the plugin
      ""					// the preferred hotkey to run the plugin
    };
    

    In our example:

    • MyPlugmod class: This class inherits from plugmod_t and overrides the run() method to perform the plugin’s main functionality. The constructor and destructor provide initialization and cleanup messages.

    • PLUGIN exported plugin_t instance: This object sets the PLUGIN_MULTI flag to allow the plugin to be loaded multiple times if needed.

    • init function: This function is called by the by the kernel in order to initialize the plugin. It returns an instance of MyPlugmod.

    Include an ida-plugin.json file

    To ensure your plugin is well-organized and can be easily included in the Hex-Rays plugins repository, add the ida-plugin.json file with essential metadata to your plugin directory.

    Build and install your plugin

    1. Compile your plugin. Once your plugin code is ready, Use your C++ development environment to compile the plugin source code into a shared library (.dll on Windows, .so on Linux, or .dylib on macOS).
    2. Install your plugin. Copy the compiled plugin binary to the plugins directory in your IDA installation folder.
    3. Run your plugin. Execute the plugin via the specified hotkey or by selecting it from the Edit -> Plugins submenu.

    Porting Guide from IDA 8.x to 9.0

    IDA 9.0 API Changes and porting guide

    Introduction

    The largest change is the removal of two headers:

    • struct.hpp
    • enum.hpp

    The functionalities for working with user-defined types are now available in typeinf.hpp (tinfo_t class).

    struct.hpp

    Removed classes

    • class member_t;
    • class struc_t;

    struc_t is replaced by the notion of “user-defined type” (udt_type_data_t class) and member_t by dt member (udm_t class).

    Removed APIs

    • get_struc_qty() Rough equivalent is get_ordinal_limit() or get_ordinal_count() but note that it also includes enums and typedefs.
    • get_first_struc_idx()
    • get_last_struc_idx()
    • get_prev_struc_idx()
    • get_next_struc_idx()

    Local type ordinals always start at 1 (0 is invalid ordinal) and go up to get_ordinal_limit().

    • get_struc_idx(tid_t id)
    • get_struc_by_idx(uval_t idx)

    enum.hpp

    Enumerations are now manipulated via:

    • tinfo_t class
    • enum_type_data_t class
    • edm_t class. in typeinf.hpp

    Removed APIs

    • get_enum_qty(void)
    • getn_enum(size_t idx)
    • get_enum_idx(enum_t id)
    • get_enum(const char *name)
    • is_bf(enum_t id)
    • is_enum_hidden(enum_t id)
    • set_enum_hidden(enum_t id, bool hidden)
    • is_enum_fromtil(enum_t id)
    • set_enum_fromtil(enum_t id, bool fromtil)
    • is_ghost_enum(enum_t id)
    • set_enum_ghost(enum_t id, bool ghost)
    • get_enum_name(qstring *out, enum_t id)
    • get_enum_name2(qstring *out, enum_t id, int flags=0)
    • get_enum_name(tid_t id, int flags=0)
    • get_enum_width(enum_t id)
    • set_enum_width(enum_t id, int width)
    • get_enum_cmt(qstring *buf, enum_t id, bool repeatable)
    • get_enum_size(enum_t id)
    • get_enum_flag(enum_t id)
    • get_enum_member_by_name(const char *name)
    • get_enum_member_value(const_t id)
    • get_enum_member_enum(const_t id)
    • get_enum_member_bmask(const_t id)
    • get_enum_member(enum_t id, uval_t value, int serial, bmask_t mask)
    • get_first_bmask(enum_t enum_id)
    • get_last_bmask(enum_t enum_id)
    • get_next_bmask(enum_t enum_id, bmask_t bmask\)
    • get_prev_bmask(enum_t enum_id, bmask_t bmask)
    • get_first_enum_member(enum_t id, bmask_t bmask=DEFMASK)
    • get_last_enum_member(enum_t id, bmask_t bmask=DEFMASK)
    • get_next_enum_member(enum_t id, uval_t value, bmask_t bmask=DEFMASK)
    • get_prev_enum_member(enum_t id, uval_t value, bmask_t bmask=DEFMASK)
    • get_enum_member_name(qstring *out, const_t id)
    • get_enum_member_cmt(qstring *buf, const_t id, bool repeatable)
    • get_first_serial_enum_member(uchar *out_serial, enum_t id, uval_t value, bmask_t bmask)
    • get_last_serial_enum_member(uchar *out_serial, enum_t id, uval_t value, bmask_t bmask)
    • get_next_serial_enum_member(uchar *in_out_serial, const_t first_cid)
    • get_prev_serial_enum_member(uchar *in_out_serial, const_t first_cid)
    • for_all_enum_members(enum_t id, enum_member_visitor_t &cv)
    • ida_export get_enum_member_serial(const_t cid)
    • get_enum_type_ordinal(enum_t id)
    • set_enum_type_ordinal(enum_t id, int32 ord)
    • add_enum(size_t idx, const char *name, flags64_t flag)
    • del_enum(enum_t id)
    • set_enum_idx(enum_t id, size_t idx)
    • set_enum_bf(enum_t id, bool bf)
    • set_enum_name(enum_t id, const char *name)
    • set_enum_cmt(enum_t id, const char *cmt, bool repeatable)
    • set_enum_flag(enum_t id, flags64_t flag)
    • add_enum_member(enum_t id, const char *name, uval_t value, bmask_t bmask=DEFMASK)
    • del_enum_member(enum_t id, uval_t value, uchar serial, bmask_t bmask)
    • set_enum_member_name(const_t id, const char *name)
    • set_enum_member_cmt(const_t id, const char *cmt, bool repeatable)
    • is_one_bit_mask(bmask_t mask)
    • set_bmask_name(enum_t id, bmask_t bmask, const char *name)
    • get_bmask_name(qstring *out, enum_t id, bmask_t bmask)
    • set_bmask_cmt(enum_t id, bmask_t bmask, const char *cmt, bool repeatable)
    • get_bmask_cmt(qstring *buf, enum_t id, bmask_t bmask, bool repeatable)

    bytes.hpp

    Added APIs

    • idaman ea_t ida_export find_binary(ea_t startea, ea_t endea, const char *ubinstr, int radix, int sflag, int strlits_encoding=0)

    Modified APIs

    In 8.4In 9.0
    idaman bool ida_export get_octet2(uchar *out, octet_generator_t *ogen)idaman bool ida_export get_octet(uchar *out, octet_generator_t *ogen)
    idaman bool ida_export op_enum(ea_t ea, int n, enum_t id, uchar serial=0)idaman bool ida_export op_enum(ea_t ea, int n, tid_t id, uchar serial=0)
    idaman enum_t ida_export get_enum_id(uchar *serial, ea_t ea, int n)idaman tid_t ida_export get_enum_id(uchar *serial, ea_t ea, int n)
    idaman ea_t ida_export bin_search3(size_t *out_matched_idx, ea_t start_ea, ea_t end_ea, const compiled_binpat_vec_t &data, int flags)idaman ea_t ida_export bin_search(ea_t start_ea, ea_t end_ea, const compiled_binpat_vec_t &data, int flags, size_t *out_matched_idx=nullptr)

    Removed APIs

    • bin_search2(ea_t start_ea, ea_t end_ea, const compiled_binpat_vec_t &data, int flags)
    • bin_search(ea_t, ea_t, const uchar *, const uchar *, size_t, int, int)
    • get_8bit(ea_t *ea, uint32 *v, int *nbit)
    • get_octet(ea_t *ea, uint64 *v, int *nbit)
    • free_chunk(ea_t bottom, asize_t size, int32 step)

    dirtree.hpp

    Modified APIs

    In 8.4In 9.0
    idaman bool ida_export dirtree_get_abspath_by_cursor2(qstring *out, const dirtree_impl_t *d, const dirtree_cursor_t &cursor, uint32 name_flags)idaman bool ida_export dirtree_get_abspath_by_cursor(qstring *out, const dirtree_impl_t *d, const dirtree_cursor_t &cursor, uint32 name_flags)

    diskio.hpp

    Modified APIs

    In 8.4In 9.0
    idaman THREAD_SAFE int ida_export enumerate_files2(char *answer, size_t answer_size, const char *path, const char *fname, file_enumerator_t &fv)idaman THREAD_SAFE int ida_export enumerate_files(char *answer, size_t answer_size, const char *path, const char *fname, file_enumerator_t &fv)

    Removed APIs

    • ecreate(const char *file)
    • eclose(FILE *fp)
    • eread(FILE *fp, void *buf, size_t size)
    • ewrite(FILE *fp, const void *buf, size_t size)
    • eseek(FILE *fp, qoff64_t pos)
    • enumerate_files(char *answer, size_t answer_size, const char *path, const char *fname, int (idaapi*func)(const char *file,void *ud), void *ud=nullptr)

    err.h

    Removed APIs

    • qerrcode(int new_code=-1)

    expr.hpp

    Modified APIs

    In 8.4In 9.0
    bool extlang_t::(idaapi *compile_file)(const char *file, qstring *errbuf)bool extlang_t::(idaapi *compile_file)(const char *file, const char *requested_namespace, qstring *errbuf)

    frame.hpp

    Added APIs

    • idaman bool ida_export add_frame_member(const func_t *pfn, const char *name, uval_t offset, const tinfo_t &tif, const struct value_repr_t *repr=nullptr, uint etf_flags=0)
    • THREAD_SAFE bool is_anonymous_member_name(const char *name)
    • THREAD_SAFE bool is_dummy_member_name(const char *name)
    • idaman bool ida_export is_special_frame_member(tid_t tid)
    • idaman bool ida_export set_frame_member_type(const func_t *pfn, uval_t offset, const tinfo_t &tif, const struct value_repr_t *repr=nullptr, uint etf_flags=0)
    • idaman bool ida_export delete_frame_members(const func_t *pfn, uval_t start_offset, uval_t end_offset)
    • idaman sval_t ida_export calc_frame_offset(func_t *pfn, sval_t off, const insn_t *insn = nullptr, const op_t *op = nullptr)

    Modified PIs

    In 8.4In 9.0
    idaman struc_t *ida_export get_frame(const func_t *pfn)idaman bool ida_export get_func_frame(tinfo_t *out, const func_t *pfn)
    idaman bool ida_export define_stkvar(func_t *pfn, const char *name, sval_t off, flags64_t flags, const opinfo_t *ti, asize_t nbytes)idaman bool ida_export define_stkvar(func_t *pfn, const char *name, sval_t off, const tinfo_t &tif, const struct value_repr_t *repr=nullptr)
    idaman void ida_export build_stkvar_xrefs(xreflist_t *out, func_t *pfn, const member_t *mptr)idaman void ida_export build_stkvar_xrefs(xreflist_t *out, func_t *pfn, uval_t start_offset, uval_t end_offset)

    Removed APIs

    • get_frame_member_by_id(qstring *out_mname, struc_t **out_fptr, tid_t mid)
    • get_stkvar(sval_t *actval, const insn_t &insn, const op_t &x, sval_t v) See get_stkvar in ida_typeinf.tinfo_t
    • get_min_spd_ea(func_t *pfn)
    • delete_unreferenced_stkvars(func_t *pfn)
    • delete_wrong_stkvar_ops(func_t *pfn)

    funcs.hpp

    Added APIs

    • bool func_item_iterator_t::set_ea(ea_t _ea)

    Removed APIs

    • save_signatures(void)
    • invalidate_sp_analysis(func_t *pfn)
    • invalidate_sp_analysis(ea_t ea)

    gdl.hpp

    Added classes/structures

    • struct edge_t
    • class node_ordering_t

    hexrays.hpp

    Added classes/structures

    • class control_graph_t
    • class edge_mapper_t
    • class node_bitset_t
    • class array_of_node_bitset_t
    • struct ctry_t
    • struct cthrow_t
    • struct catchexpr_t
    • struct ccatch_t
    • struct cblock_pos_t

    Added APIs

    • uvlr_t max_vlr_value(int size)
    • uvlr_t min_vlr_svalue(int size)
    • uvlr_t max_vlr_svalue(int size)
    • bool is_unsigned_cmpop(cmpop_t cmpop)
    • bool is_signed_cmpop(cmpop_t cmpop)
    • bool is_cmpop_with_eq(cmpop_t cmpop)
    • bool is_cmpop_without_eq(cmpop_t cmpop)

    lvar_t

    • bool was_scattered_arg() const
    • void set_scattered_arg()
    • void clr_scattered_arg()

    lvars_t

    • int find_input_reg(int reg, int _size=1)

    simple_graph_t

    • virtual bool ignore_edge(int /*src*/, int /*dst*/ ) const
    • void hexapi compute_dominators(array_of_node_bitset_t &domin, bool post=false) const
    • void hexapi compute_immediate_dominators(const array_of_node_bitset_t &domin, intvec_t &idomin, bool post=false) const
    • int hexapi depth_first_preorder(node_ordering_t *pre) const
    • int hexapi depth_first_postorder(node_ordering_t *post) const
    • void depth_first_postorder(node_ordering_t *post, edge_mapper_t *et) const
    • void depth_first_postorder_for_all_entries(node_ordering_t *post) const
    • intvec_t find_dead_nodes() const
    • void find_reaching_nodes(int n, node_bitset_t &reaching) const
    • bool path_exists(int m, int n) const
    • bool path_back(const array_of_node_bitset_t &domin, int m, int n) const
    • bool path_back(const edge_mapper_t &et, int m, int n) const
    • iterator begin() const
    • iterator end()
    • int front()
    • void inc(iterator &p, int n=1) const
    • virtual int hexapi goup(int node) const

    fnumber_t

    • int calc_max_exp() const
    • bool is_nan() const

    minsn_t

    • bool was_unpaired() const

    mba_t

    • mblock_t *hexapi split_block(mblock_t *blk, minsn_t *start_insn)
    • merror_t hexapi inline_func(codegen_t &cdg, int blknum, mba_ranges_t &ranges, int decomp_flags=0, int inline_flags=0)
    • const stkpnt_t *hexapi locate_stkpnt(ea_t ea) const

    codegen_t

    • void hexapi clear()

    vd_failure_t

    • virtual const char *what() const noexcept override

    Modified APIs

    In 8.4In 9.0
    void hexapi save_user_labels2(ea_t func_ea, const user_labels_t *user_labels, const cfunc_t *func=nullptr)void hexapi save_user_labels(ea_t func_ea, const user_labels_t *user_labels, const cfunc_t *func=nullptr)
    user_labels_t *hexapi restore_user_labels2(ea_t func_ea, const cfunc_t *func=nullptr)user_labels_t *hexapi restore_user_labels(ea_t func_ea, const cfunc_t *func=nullptr)

    stkvar_ref_t

    In 8.4In 9.0
    member_t *hexapi get_stkvar(uval_t *p_off=nullptr) constssize_t hexapi get_stkvar(udm_t *udm=nullptr, uval_t *p_off=nullptr) const

    mop_t

    In 8.4In 9.0
    member_t *get_stkvar(uval_t *p_off) constssize_t get_stkvar(udm_t *udm=nullptr, uval_t *p_off=nullptr) const

    mba_t

    In 8.4In 9.0
    member_t *get_stkvar(sval_t vd_stkoff, uval_t *poff) constssize_t get_stkvar(udm_t *udm, sval_t vd_stkoff, uval_t *poff=nullptr) const
    const mblock_t *get_mblock(int n) constconst mblock_t *get_mblock(uint n) const
    mblock_t *get_mblock(int n)mblock_t *get_mblock(uint n)
    bool hexapi combine_blocks()bool hexapi merge_blocks()

    valrng_t

    In 8.4In 9.0
    bool cvt_to_cmp(cmpop_t *cmp, uvlr_t *val, bool strict) constbool valrng_t::cvt_to_cmp(cmpop_t *cmp, uvlr_t *val) const

    Removed APIs:

    • bool hexapi get_member_type(const member_t *mptr, tinfo_t *type)
    • bool hexapi checkout_hexrays_license(bool silent)
    • bool get_member_type(const member_t *mptr, tinfo_t *type)

    valrng_t

    • static uvlr_t max_value(int size_)
    • static uvlr_t min_svalue(int size_)
    • static uvlr_t max_svalue(int size_)

    ctree_item_t

    • member_t *hexapi get_memptr(struc_t **p_sptr=nullptr) const

    ctree_parentee_t

    • cblock_t *get_block()

    vdui_t

    • bool hexapi set_strmem_type(struc_t *sptr, member_t *mptr)
    • bool hexapi rename_strmem(struc_t *sptr, member_t *mptr)

    graph.hpp

    Removed classes/structures

    • class node_ordering_t See code
    • struct edge_t See code

    Modified classes/structures

    In 8.4In 9.0
    class abstract_graph_tclass drawable_graph_t
    class mutable_graph_tclass interactive_graph_t

    Modified APIs

    In 8.4In 9.0
    mutable_graph_t *idaapi create_mutable_graph(uval_t id)interactive_graph_t *idaapi create_interactive_graph(uval_t id)
    mutable_graph_t *idaapi create_disasm_graph(ea_t ea)interactive_graph_t *idaapi create_disasm_graph(ea_t ea)
    mutable_graph_t *idaapi create_disasm_graph(const rangevec_t &ranges)interactive_graph_t *idaapi create_disasm_graph(const rangevec_t &ranges)
    mutable_graph_t *idaapi get_viewer_graph(graph_viewer_t *gv)interactive_graph_t *idaapi get_viewer_graph(graph_viewer_t *gv)
    void idaapi set_viewer_graph(graph_viewer_t *gv, mutable_graph_t *g)void idaapi set_viewer_graph(graph_viewer_t *gv, interactive_graph_t *g)
    void idaapi delete_mutable_graph(mutable_graph_t *g)void idaapi delete_interactive_graph(interactive_graph_t *g)
    void idaapi mutable_graph_t::del_custom_layout(void)void idaapi interactive_graph_t::del_custom_layout(void)
    void idaapi mutable_graph_t::set_custom_layout(void) constvoid idaapi interactive_graph_t::set_custom_layout(void) const
    void idaapi mutable_graph_t::set_graph_groups(void) constvoid idaapi interactive_graph_t::set_graph_groups(void) const
    void idaapi mutable_graph_t::clear(void)void idaapi interactive_graph_t::clear(void)
    bool idaapi mutable_graph_t::create_digraph_layout(void)bool idaapi interactive_graph_t::create_digraph_layout(void)
    bool idaapi abstract_graph_t::create_tree_layout(void)bool idaapi drawable_graph_t::create_tree_layout(void)
    bool idaapi abstract_graph_t::create_circle_layout(point_t c, int radius)bool idaapi drawable_graph_t::create_circle_layout(point_t c, int radius)
    int idaapi mutable_graph_t::get_node_representative(int node)int idaapi interactive_graph_t::get_node_representative(int node)
    int idaapi mutable_graph_t::_find_subgraph_node(int gr, int n) constint idaapi interactive_graph_t::_find_subgraph_node(int gr, int n) const
    int idaapi mutable_graph_t::create_group(const intvec_t &_nodes)int idaapi interactive_graph_t::create_group(const intvec_t &_nodes)
    bool idaapi mutable_graph_t::get_custom_layout(void)bool idaapi interactive_graph_t::get_custom_layout(void)
    bool idaapi mutable_graph_t::get_graph_groups(void)bool idaapi interactive_graph_t::get_graph_groups(void)
    bool idaapi mutable_graph_t::empty(void) constbool idaapi interactive_graph_t::empty(void) const
    bool idaapi mutable_graph_t::is_visible_node(int node) constbool idaapi interactive_graph_t::is_visible_node(int node) const
    bool idaapi mutable_graph_t::delete_group(int group)bool idaapi interactive_graph_t::delete_group(int group)
    bool idaapi mutable_graph_t::change_group_visibility(int gr, bool exp)bool idaapi interactive_graph_t::change_group_visibility(int gr, bool exp)
    bool idaapi mutable_graph_t::set_edge(edge_t e, const edge_info_t *ei)bool idaapi interactive_graph_t::set_edge(edge_t e, const edge_info_t *ei)
    int idaapi mutable_graph_t::node_qty(void) constint idaapi interactive_graph_t::node_qty(void) const
    rect_t &idaapi mutable_graph_t::nrect(int n)rect_t &idaapi interactive_graph_t::nrect(int n)

    idalib.hpp

    The new header for the IDA library

    Added APIs

    • idaman int ida_export init_library(int argc = 0, char *argv[] = nullptr)
    • idaman int ida_export open_database(const char *file_path, bool run_auto)
    • idaman void ida_export close_database(bool save)

    idd.hpp

    Added APIs

    • idaman int ida_export cpu2ieee(fpvalue_t *ieee_out, const void *cpu_fpval, int size)
    • idaman int ida_export ieee2cpu(void *cpu_fpval, const fpvalue_t &ieee_out, int size)

    idp.hpp

    Removed APIs:

    • processor_t::has_realcvt(void) const

    Modified APIs:

    In 8.4In 9.0
    static ssize_t processor_t::gen_stkvar_def(outctx_t &ctx, const class member_t *mptr, sval_t v)static ssize_t processor_t::gen_stkvar_def(outctx_t &ctx, const struct udm_t *mptr, sval_t v, tid_t tid)

    Added APIs

    procmod_t

    • const op_t *procmod_t::make_op_reg(op_t *op, int reg, int8 dtype = -1) const
    • const op_t *procmod_t::make_op_imm(op_t *op, uval_t val, int8 dtype = -1) const
    • const op_t *procmod_t::make_op_displ(op_t *op, int base_reg, uval_t displ, int8 dtype = -1) const
    • const op_t *procmod_t::make_op_phrase(op_t *op, int base_reg, int index_reg, int8 dtype = -1) const

    See also IDB events for a table providing a list a event replacement and removal.

    kernwin.hpp

    Removed APIs

    • open_enums_window(tid_t const_id=BADADDR)
    • open_structs_window(tid_t id=BADADDR, uval_t offset=0)
    • choose_struc(const char *title)
    • choose_enum_by_value(const char *title, enum_t default_id, uint64 value, int nbytes, uchar *serial)

    Removed classes/structures

    • class enumplace_t
    • class structplace_t

    Added APIs

    • bool is_ida_library(char *path, size_t pathsize, void** handle)

    tagged_line_section_t

    • const tagged_line_section_t::tagged_line_section_t *nearest_before(const tagged_line_section_t &range, cpidx_t start, color_t tag=0) const
    • const tagged_line_section_t::tagged_line_section_t *nearest_after(const tagged_line_section_t &range, cpidx_t start, color_t tag=0) const

    chooser_base_t

    • bool chooser_base_t::has_widget_lifecycle() const

    Modified APIs

    In 8.4In 9.0
    ea_t choose_stkvar_xref(func_t *pfn, member_t *mptr)ea_t choose_stkvar_xref(func_t *pfn, tid_t srkvar_tid)
    bool tagged_line_section_t::substr(qstring *out, const qstring &in) constbool tagged_line_section_t::substr(qstring *out,,const qstring &in, const tagged_line_section_t *end = nullptr) const

    lex.hpp

    Modified APIs

    In 8.4In 9.0
    idaman lexer_t *ida_export create_lexer(const char *const *keys, size_t size, void *ud=nullptr)idaman lexer_t *ida_export create_lexer(const char *const *keys, size_t size, void *ud=nullptr, uint32 macro_flags=0)

    lines.hpp

    Removed APIs

    • set_user_defined_prefix(size_t width, void (idaapi *get_user_defined_prefix)(qstring *buf, ea_t ea, int lnnum, int indent, const char *line))

    Modified APIs

    In 8.4In 9.0
    idaman void ida_export update_extra_cmt(ea_t ea, int what, const char *str)idaman bool ida_export update_extra_cmt(ea_t ea, int what, const char *str)
    idaman void ida_export del_extra_cmt(ea_t ea, int what)idaman bool ida_export del_extra_cmt(ea_t ea, int what)

    nalt.hpp

    Modified APIs

    In 8.4In 9.0
    idaman int ida_export validate_idb_names2(bool do_repair)idaman int ida_export validate_idb_names(bool do_repair)

    parsejson.hpp

    Added APIs

    jvalue_t

    • void jvalue_t::set_str(const char *s)

    jobj_t

    • void jobj_t::put(const char *key, const jobj_t &value)

    pro.h

    Removed APIs

    • unpack_memory(void *buf, size_t size, const uchar **pptr, const uchar *end)

    Added APIs

    • idaman THREAD_SAFE bool ida_export get_login_name(qstring *out)
    • idaman void *ida_export pipe_process(qhandle_t *read_handle, qhandle_t *write_handle, launch_process_params_t *lpp, qstring *errbuf=nullptr)

    bytevec_t

    • qstring bytevec_t::tohex(bool upper_case=true) const

    qlist

    • void qlist::splice(iterator pos, qlist &other, iterator first, iterator last)

    Added classes/structures

    • struct memory_serializer_t

    regex.hpp

    Removed APIs

    • regcomp(struct regex_t *preg, const char *pattern, int cflags)
    • regerror(int errcode, const struct regex_t *preg, char *errbuf, size_t errbuf_size)
    • regexec(const struct regex_t *preg, const char *str, size_t nmatch, struct regmatch_t pmatch[], int eflags)
    • regfree(struct regex_t *preg)

    regfinder.hpp

    Modified APIs

    In 8.4In 9.0
    void ida_export reg_finder_invalidate_cache(reg_finder_t *_this, ea_t ea)void ida_export reg_finder_invalidate_cache(reg_finder_t *_this, ea_t to, ea_t from)
    bool ida_export reg_finder_calc_op_addr(reg_finder_t *_this, reg_value_info_t *addr, const op_t *memop, const insn_t *insn, ea_t ea, ea_t ds)bool ida_export reg_finder_calc_op_addr(reg_finder_t *_this, reg_value_info_t *addr, const op_t *memop, const insn_t *insn, ea_t ea, ea_t ds, int max_depth)
    bool ida_export reg_finder_may_modify_stkvars(const reg_finder_t *_this, reg_finder_op_t op, const insn_t *insn)bool ida_export reg_finder_may_modify_stkvar(const reg_finder_t *_this, reg_finder_op_t op, const insn_t *insn)
    void idaapi invalidate_regfinder_cache(ea_t ea = BADADDR)void idaapi invalidate_regfinder_cache(ea_t to = BADADDR, ea_t from = BADADDR)

    Removed APIs

    • reg_finder_op_make_rfop(func_t *pfn, const insn_t &insn, const op_t &op)

    Added APIs

    • void reg_value_info_t::movt(const reg_value_info_t &r, const insn_t &insn)
    • static int reg_finder_op_t::get_op_width(const op_t &op)
    • static reg_finder_op_t reg_finder_op_t::make_stkoff(sval_t stkoff, int width)

    registry.hpp

    Removed APIs

    • reg_load(void)
    • reg_flush(void)

    search.hpp

    Removed APIs

    • user2bin(uchar *, uchar *, ea_t, const char *, int, bool)
    • find_binary(ea_t, ea_t, const char *, int, int)

    typeinf.hpp

    Removed APIs

    • set_numbered_type(til_t *ti, uint32 ordinal, int ntf_flags, const char *name, const type_t *type, const p_list *fields=nullptr, const char *cmt=nullptr, const p_list *fldcmts=nullptr, const sclass_t *sclass=nullptr)
    • get_ordinal_from_idb_type(const char *name, const type_t *type)
    • is_autosync(const char *name, const type_t *type)
    • is_autosync(const char *name, const tinfo_t &tif)
    • import_type(const til_t *til, int idx, const char *name, int flags=0)
    • get_udm_tid(const udm_t *udm, const char *udt_name)

    Modified APIs

    In 8.4In 9.0
    bool ida_export create_tinfo2(tinfo_t *_this, type_t bt, type_t bt2, void *ptr)bool ida_export create_tinfo(tinfo_t *_this, type_t bt, type_t bt2, void *ptr)
    int ida_export verify_tinfo(uint32 typid)int ida_export verify_tinfo(typid_t typid)
    bool ida_export get_tinfo_details2(uint32 typid, type_t bt2, void *buf)bool ida_export get_tinfo_details(typid_t typid, type_t bt2, void *buf)
    size_t ida_export get_tinfo_size(uint32 *p_effalign, uint32 typid, int gts_code)size_t ida_export get_tinfo_size(uint32 *p_effalign, typid_t typid, int gts_code)
    size_t ida_export get_tinfo_pdata(void *outptr, uint32 typid, int what)size_t ida_export get_tinfo_pdata(void *outptr, typid_t typid, int what)
    size_t ida_export get_tinfo_property(uint32 typid, int gta_prop)size_t ida_export get_tinfo_property(typid_t typid, int gta_prop)
    size_t ida_export get_tinfo_property4(uint32 typid, int gta_prop, size_t p1, size_t p2, size_t p3, size_t p4)size_t ida_export get_tinfo_property4(typid_t typid, int gta_prop, size_t p1, size_t p2, size_t p3, size_t p4)
    bool ida_export deserialize_tinfo2(tinfo_t *tif, const til_t *til, const type_t **ptype, const p_list **pfields, const p_list **pfldcmts, const char *cmt)bool ida_export deserialize_tinfo(tinfo_t *tif, const til_t *til, const type_t **ptype, const p_list **pfields, const p_list **pfldcmts, const char *cmt)
    int ida_export find_tinfo_udt_member(udm_t *udm, uint32 typid, int strmem_flags)int ida_export find_tinfo_udt_member(udm_t *udm, typid_t typid, int strmem_flags)
    bool ida_export compare_tinfo(uint32 t1, uint32 t2, int tcflags)bool ida_export compare_tinfo(typid_t t1, typid_t t2, int tcflags)
    int ida_export lexcompare_tinfo(uint32 t1, uint32 t2, int)int ida_export lexcompare_tinfo(typid_t t1, typid_t t2, int)
    uint64 ida_export read_tinfo_bitfield_value(uint32 typid, uint64 v, int bitoff)uint64 ida_export read_tinfo_bitfield_value(typid_t typid, uint64 v, int bitoff)
    uint64 ida_export write_tinfo_bitfield_value(uint32 typid, uint64 dst, uint64 v, int bitoff)uint64 ida_export write_tinfo_bitfield_value(typid_t typid, uint64 dst, uint64 v, int bitoff)
    bool ida_export get_tinfo_attr(uint32 typid, const qstring &key, bytevec_t *bv, bool all_attrs)bool ida_export get_tinfo_attr(typid_t typid, const qstring &key, bytevec_t *bv, bool all_attrs)
    bool ida_export get_tinfo_attrs(uint32 typid, type_attrs_t *tav, bool include_ref_attrs)bool ida_export get_tinfo_attrs(typid_t typid, type_attrs_t *tav, bool include_ref_attrs)
    bool ida_export append_tinfo_covered(rangeset_t *out, uint32 typid, uint64 offset)bool ida_export append_tinfo_covered(rangeset_t *out, typid_t typid, uint64 offset)
    bool ida_export calc_tinfo_gaps(rangeset_t *out, uint32 typid)bool ida_export calc_tinfo_gaps(rangeset_t *out, typid_t typid)
    bool ida_export name_requires_qualifier(qstring *out, uint32 typid, const char *name, uint64 offset)bool ida_export name_requires_qualifier(qstring *out, typid_t typid, const char *name, uint64 offset)
    void ida_export tinfo_get_innermost_udm(tinfo_t *itif, const tinfo_t *tif, uint64 offset, size_t *udm_idx, uint64 *bit_offset)void ida_export tinfo_get_innermost_udm(tinfo_t *itif, const tinfo_t *tif, uint64 offset, size_t *udm_idx, uint64 *bit_offset, bool return_member_type)
    tinfo_code_t tinfo_t::find_edm(edm_t *edm, uint64 value, bmask64_t bmask=DEFMASK64, uchar serial=0) constssize_t tinfo_t::find_edm(edm_t *edm, uint64 value, bmask64_t bmask=DEFMASK64, uchar serial=0) const
    tinfo_code_t tinfo_t::find_edm(edm_t *edm, const char *name) constssize_t tinfo_t::find_edm(edm_t *edm, const char *name) const
    bool tinfo_t::get_type_by_edm_name(const char *mname, til_t *til=nullptr)ssize_t tinfo_t::get_edm_by_name(const char *mname, const til_t *til=nullptr)
    void ida_export gen_use_arg_tinfos2(struct argtinfo_helper_t *_this, ea_t caller, func_type_data_t *fti, funcargvec_t *rargs)void ida_export gen_use_arg_tinfos(struct argtinfo_helper_t *_this, ea_t caller, func_type_data_t *fti, funcargvec_t *rargs)

    Added classes/structures

    • struct udm_visitor_t

    Added APIs

    • bool ida_export detach_tinfo_t(tinfo_t *_this)
    • bool stroff_as_size(int plen, const tinfo_t &tif, asize_t value)
    • int ida_export visit_stroff_udms(udm_visitor_t &sfv, const tid_t *path, int plen, adiff_t *disp, bool appzero)
    • bool is_one_bit_mask(uval_t mask)

    til_t

    • til_t *til_t::find_base(const char *n)

    callregs_t

    • void callregs_t::set_registers(reg_kind_t kind, int first_reg, int last_reg)

    tinfo_t

    • bool tinfo_t::get_named_type(const char *name, type_t decl_type=BTF_TYPEDEF, bool resolve=true, bool try_ordinal=true)
    • bool tinfo_t::get_numbered_type(uint32 ordinal, type_t decl_type=BTF_TYPEDEF, bool resolve=true)
    • bool tinfo_t::detach()
    • bool tinfo_t::is_punknown()
    • int tinfo_t::find_udm(uint64 offset, int strmem_flags=0) const
    • int tinfo_t::find_udm(const char *name, int strmem_flags=0) const
    • size_t tinfo_t::get_enum_nmembers() const
    • bool tinfo_t::is_empty_enum() const
    • tinfo_code_t tinfo_t::get_enum_repr(value_repr_t *repr) const
    • int tinfo_t::get_enum_width() const
    • uint64 tinfo_t::calc_enum_mask() const
    • tid_t tnfo_t::get_edm_tid(size_t idx) const
    • tinfo_t tinfo_t::get_innermost_member_type(uint64 bitoffset, uint64 *out_bitoffset=nullptr) const
    • bool tinfo_t::is_udm_by_til(size_t idx) const
    • tinfo_code_t tinfo_t::set_udm_by_til(size_t idx, bool on=true, uint etf_flags=0)
    • tinfo_code_t tinfo_t::set_fixed_struct(bool on=true)
    • tinfo_code_t tinfo_t::set_struct_size(size_t new_size)
    • bool tinfo_t::is_fixed_struct() const
    • bool tinfo_t::get_func_frame(const func_t *pfn)
    • bool tinfo_t::is_frame() const
    • ea_t tinfo_t::get_frame_func() const
    • ssize_t tinfo_t::get_stkvar(sval_t *actval, const insn_t &insn, const op_t *x, sval_t v)
    • tinfo_code_t tinfo_t::set_enum_radix(int radix, bool sign, uint etf_flags=0)
    • tinfo_code_t tinfo_t::set_funcarg_type(size_t index, const tinfo_t &tif, uint etf_flags=0)
    • tinfo_code_t tinfo_t::set_func_rettype(const tinfo_t &tif, uint etf_flags=0)
    • tinfo_code_t tinfo_t::del_funcargs(size_t idx1, size_t idx2, uint etf_flags=0)
    • tinfo_code_t tinfo_t::del_funcarg(size_t idx, uint etf_flags=0)
    • tinfo_code_t tinfo_t::add_funcarg(const funcarg_t &farg, uint etf_flags=0, ssize_t idx=-1)
    • tinfo_code_t tinfo_t::set_func_cc(cm_t cc, uint etf_flags=0)
    • tinfo_code_t tinfo_t::set_funcarg_loc(size_t index, const argloc_t &argloc, uint etf_flags=0)
    • tinfo_code_t tinfo_t::et_func_retloc(const argloc_t &argloc, uint etf_flags=0)

    func_type_data_t

    • ssize_t func_type_data_t::find_argument(const char *name, size_t from=0, size_t to=size_t(-1)) const

    enum_type_data_t

    • tinfo_code_t enum_type_data_t::get_value_repr(value_repr_t *repr) const
    • uchar enum_type_data_t::get_serial(size_t index) const
    • uchar enum_type_data_t::get_max_serial(uint64 value) const

    udm_t

    • bool udm_t::is_retaddr() const
    • bool udm_t::is_savregs() const
    • bool udm_t::is_special_member() const
    • bool udm_t::is_by_til() const
    • void udm_t::set_retaddr(bool on=true)
    • void udm_t::set_savregs(bool on=true)
    • void udm_t::set_by_til(bool on=true)

    udt_type_data_t

    • bool udt_type_data_t::is_fixed() const
    • void udt_type_data_t::set_fixed(bool on=true)

    IDB events

    The following table provide a list of IDB events that have been replaced or, in some cases, removed.

    Since 7In 9.0
    truc_createdlocal_types_changed
    deleting_strucnone
    struc_deletedlocal_types_changed
    changing_struc_alignnone
    struc_align_changedlocal_types_changed
    renaming_strucnone
    struc_renamedlocal_types_changed
    expanding_strucnone
    struc_expandedlt_udt_expanded, frame_expanded, local_types_changed
    struc_member_createdlt_udm_created, frame_udm_created, local_types_changed
    deleting_struc_membernone
    struc_member_deletedlt_udm_deleted, frame_udm_deleted, local_types_changed
    renaming_struc_membernone
    struc_member_renamedlt_udm_renamed, frame_udm_renamed, local_types_changed
    changing_struc_membernone
    struc_member_changedlt_udm_changed, frame_udm_changed, local_types_changed
    changing_struc_cmtnone
    struc_cmt_changedlocal_types_changed
    enum_createdlocal_types_changed
    deleting_enumnone
    enum_deletedlocal_types_changed
    renaming_enumnone
    enum_renamedlocal_types_changed
    changing_enum_bflocal_types_changed
    enum_bf_changedlocal_types_changed
    changing_enum_cmtnone
    enum_cmt_changedlocal_types_changed
    enum_member_createdlocal_types_changed
    deleting_enum_membernone
    enum_member_deletedlocal_types_changed
    enum_width_changedlocal_types_changed
    enum_flag_changedlocal_types_changed
    enum_ordinal_changednone

    IDAPython SDK

    IDAPython SDK allows you to use the Python code in IDA to write scripts and customize basic IDA functionality. It offers more advanced and powerful automation than the IDC language and gives you access to Python modules and native Python abilities to interact with our API.

    Where to find the IDAPython SDK?

    • IDA Pro: IDAPython SDK is shipped out-of-the-box with IDA Pro. You can find it int the python folder located in your IDA intallation directory.
    • Other IDA Products: Check our IDA SDK GitHub repository

    Resources

    IDAPython Referencehttps://python.docs.hex-rays.com/
    IDA SDK Source Code on GitHub https://github.com/HexRaysSA/ida-sdk

    Typical use cases

    When you are asking yourself how to automate work in IDA, like renaming variables or performing custom analyses, the IDAPython API comes in handy. You can use simple code snippets directly inside the IDA output window to perform specific tasks or more advanced scripts for complex usage. Moreover, with IDAPython, you can write plugins to expand basic IDA capabilities even further.

    Looking for a beginner-friendly entry point?

    We’ve got you covered. The Domain API, built on top of the IDAPython SDK, provides a simple and intuitive starting point for those new to scripting in IDA. For more advanced use cases or finer control, you can fall back to the IDAPython SDK. The Domain API is fully compatible with the IDAPython SDK, so both can be used together to complement each other.

    What to check next?

    IDAPython Getting StartedCheck this guide to kickstart learning IDAPython with simple snippets.idapython-getting-started.md
    IDAPython ExamplesDig into complex examples that showcase the full potential and versatility of our PythonAPI.migration-guides.md
    IDAPython ReferenceExplore the technical details of all functions, classes, and more.https://python.docs.hex-rays.com
    Writing Plugins in IDAPythonLearn the best practices for creating plugins with IDAPython.how-to-create-a-plugin.md

    IDAPython Porting Guide

    Check out our Porting Guide, which is prepared to help you migrate and adapt your existing scripts and plugins from IDA 8.x to IDA 9.0.

    Getting started with IDAPython

    Intro

    The IDAPython API provides you a range of functions to interact with the disassembler, navigate through the output, and manipulate various elements such as functions, instructions, data, and comments.

    This guide is is designed to speed up the learning curve in IDAPython and kickstart your journey with scripting in IDA, assuming that you are already found your way around IDA and got familiar with IDA basics.

    Our IDA SDK is open source and available on GitHub.

    How this guide is structured?

    First, check basics for the core concepts like common variables, then dive into our simple, short and reusable code snippets showing basic examples of commonly used functions.

    Where can I find the complete examples library?

    When you feel comfortable with most popular IDAPython API usage, you can delve into our set of more complex examples. The full library of our examples is shipped with your IDA instance in the python/examples folder. You can find them also in the GitHub repository.

    Basics

    Common modules

    IDAPython API is organized in modules, however their number may be a bit overwhelming for the first sigh. Here’s the list of modules that should catch your attention first:

    • idautils: This module extracts the most useful and handy functions allowing you to jump right away and interact with the disassembly without the need to scrutinize the whole IDAPython API from the start. You can find here functions to iterate through whole segments, functions (founded by IDA and also user-defined), named locations, etc.

    • ida_idaapi: The ida_idaapi module comes handy when you want to create custom plugins or handle events, as it gives you access to more advanced functions and allows interaction with overall system

    • idc: This module provides functions that were originally part of native IDA IDC scripting language, wrapped for use in IDAPython API. This is a great starting point if you’re already familiar with IDC scripting.

    • ida_funcs: This module gives you tools to create and manipulate functions within IDA.

    • ida_kernwin: This module provides functionality to interact with IDA UI, so you can create custom dialogs and more.

    Common variables and constants

    When you start working with IDAPython, you’ll realize that one of the most commonly passed variables is ea, which refers to the valid memory address (effective address). On the other hand, the BADADDR is a constant that indicates an invalid address. It is used to indicate that an operation (such as querying a function) has failed or returned an invalid result, or signify that a specific memory location is unusable. Whenever you’re working with functions that return memory addresses, it’s a best practice to check whether the result equals BADADDR to ensure the operation was successful.

    Code snippets

    Here you can check the most common functions grouped by topics and short code samples that can serve as building blocks for longer scripts. They are usually focused on performing one specific action and can be easily reusable in more complex scripts, which you can find later under examples.

    Part 1: Navigating the disassembly—addresses and names

    Get the current address:**

    ea = idc.here()  # Get the current address
    print(f"Current address: {hex(ea)}")
    
    idc.get_screen_ea()
    

    Set the current address

    idc.jumpto(0x401000)  # Jump to address 0x401000
    

    Get the minimum address in IDB

    idc.get_inf_attr(INF_MIN_EA)
    

    Get the maximum address in IDB

    idc.get_inf_attr(INF_MAX_EA)
    

    List all instruction addresses

    for ea in idautils.Heads():
      print(hex(ea))
    

    Get the name associated with a given address

    ida_name.get_name(0x100000da0)
    

    Get the address associated with a given name

    ida_name.get_name_ea(0, "_main")
    

    Part 2: Reading and Writing Data

    Reading Bytes and Words

    byte_value = idc.get_wide_byte(0x401000)  # Read a byte at address 0x401000
    word_value = idc.get_wide_word(0x401002)  # Read a word (2 bytes) at address 0x401002
    dword_value = idc.get_wide_dword(0x401004)  # Read a double word (4 bytes) at address 0x401004
    
    print(f"Byte: {byte_value}, Word: {word_value}, Dword: {dword_value}")
    

    Writing Bytes and Words

    idc.patch_byte(0x401000, 0x90)  # Write a byte (0x90) at address 0x401000
    idc.patch_word(0x401002, 0x9090)  # Write a word (0x9090) at address 0x401002
    idc.patch_dword(0x401004, 0x90909090)  # Write a double word (0x90909090) at address 0x401004
    

    Part 3: Comments

    Add a regular (non-repetable) or repeatable comment

    idc.set_cmt(0x401000, "This is a comment", 0)  # Add a regular comment at address 0x401000
    idc.set_cmt(0x401000, "This is a repeatable comment", 1)  # Add a repeatable comment at address 0x401000
    

    Get a regular comment

    comment = idc.get_cmt(0x401000, 0)  # Get a regular comment at address 0x401000
    print(f"Comment: {comment}")
    

    Segments

    Get a segment name

    idc.get_segm_name(ea)
    
    

    Get the first segment address:

    get_first_seg()

    Iterate through all segments and return segment names

    for seg in idautils.Segments(): print (idc.get_segm_name(seg))
    

    Add segment

    Part X: Functions

    Create and delete function

    idc.add_func(0x401000, 0x401050)  # Create a function starting at 0x401000 and ending at 0x401050
    idc.del_func(0x401000)  # Delete the function at 0x401000
    

    Get the name of the function

    get_func_name(ea)
    

    Iterate through all functions and print their effective addresses and names

    for func_ea in idautils.Functions(): func_name = idc.get_func_name(func_ea); print(hex(func_ea), func_name)
    

    Part: Navigating cross-references (Xrefs)

    List cross-references to an address

    for xref in idautils.XrefsTo(0x401000):
        print(f"Xref to 0x401000 from {hex(xref.frm)}")
    

    List cross-references from an address:**

    for xref in idautils.XrefsFrom(0x401000):
        print(f"Xref from 0x401000 to {hex(xref.to)}")
    

    Iterate through all cross-references to the specific address and print the address from where the reference originates.

    for ref in idautils.XrefsTo(ea):
      print(hex(ref.frm))
    

    Part X: UI

    Set background color of a function

    set_color(0x401000, idc.CIC_FUNC, 0x007fff)  # Set background color for the function starting at address 0x401000
    

    Display a custom dialog

    ida_kernwin.info("This is a custom message dialog. Good luck with learning IDAPython API!")
    

    Complex script examples

    If you feel more comfortable with IDAPython now, you can delve into more complex and advanced examples shipped with your IDA instance. You can find them in the python/examples folder where your IDA is installed or check them from our docs. These collection gathered more advanced code samples, which usually make use of more modules and APIs.

    What’s next?

    Delve into our tutorial on how to create your first custom plugin in IDAPython.

    Reference

    Examples

    IDAPython examples

    This collection of examples organizes all IDAPython sample code into categories for easy reference. Each example demonstrates practical implementation for the IDAPython API, complementing the reference documentation with a real-world usage scenario.

    How to run the examples?

    Load the script via File Loader

    1. Navigate to File -> Script file….
    2. In the new dialog, select the .py script you want to run and click Open.

    Load the script via Script command

    1. Navigate to File -> Script command….
    2. Paste the code into Please enter script body field and click Run.

    Load the script via output window/console

    1. In the output window/IDAPython console, type the following command: exec(open("path/to/your_script.py").read()) to execute the script.

    Example Categories: Overview

    User interfaceCreating & manipulating user-interface widgets, prompting the user with forms, enriching existing widgets, or creating your own UI through Python Qt bindings.
    DisassemblyVarious ways to query, or modify the disassembly listing, alter the way analysis is performed, or be notified of changes made to the IDB.
    DecompilationQuerying the decompiler, manipulating the decompilation trees (either at the microcode level, or the C-tree), and examples showing how to intervene in the decompilation output.
    DebuggersDriving debugging sessions, be notified of debugging events.
    Working with typesThese samples utilize our Type APIs, which allow you to manage the types and perform various operations on them, like creating the structures or enums and adding their members programmatically.
    MiscellaneousMiscellaneous examples that don't quite fall into another category, but don't really justify one of their own.

    User interface

    LevelExamples
    Beginner
    Intermediate
    Advanced

    Disassembly

    LevelExamples
    Beginner
    Intermediate
    Advanced

    Decompilation

    LevelExamples
    Beginner
    Intermediate
    Advanced

    Debuggers

    LevelExamples
    Beginner
    Intermediate
    Advanced

    Working with types

    LevelExamples
    Beginner
    Intermediate
    Advanced

    Miscellaneous

    LevelExamples
    Beginner
    Intermediate
    Advanced

    Examples list

    Assign a shortcut to a custom function

    ida_kernwin.add_hotkey is a simpler, but much less flexible alternative to ida_kernwin.register_action (though it does use the same mechanism under the hood.)

    It’s particularly useful during prototyping, but note that the actions that are created cannot be inserted in menus, toolbars or cannot provide a custom ida_kernwin.action_handler_t.update callback.

    Source codeKeywordsLevel
    add_hotkey.pyactionsBeginner

    APIs Used:

    • ida_kernwin.add_hotkey
    • ida_kernwin.del_hotkey

    Add custom menus to IDA

    It is possible to add custom menus to IDA, either at the toplevel (i.e., into the menubar), or as submenus of existing menus.

    Notes:

    • the same action can be present in more than 1 menu
    • this example does not deal with context menus
    Source codeKeywordsLevel
    add_menus.pyactionsBeginner

    APIs Used:

    • ida_kernwin.AST_ENABLE_ALWAYS
    • ida_kernwin.SETMENU_INS
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_menu
    • ida_kernwin.create_menu
    • ida_kernwin.register_action

    Assign a background color to an address, function & segment

    This illustrates the setting/retrieval of background colours using the IDC wrappers

    In order to do so, we’ll be assigning colors to specific ranges (item, function, or segment). Those will be persisted in the database.

    Source codeKeywordsLevel
    colorize_disassembly.pycoloring idcBeginner

    APIs Used:

    • idc.CIC_FUNC
    • idc.CIC_ITEM
    • idc.CIC_SEGM
    • idc.get_color
    • idc.here
    • idc.set_color

    Override the default “Functions” chooser colors

    Color the function in the Function window according to its size. The larger the function, the darker the color.

    The key, is overriding ida_kernwin.UI_Hooks.get_chooser_item_attrs

    Source codeKeywordsLevel
    func_chooser_coloring.pyUI_HooksBeginner

    APIs Used:

    • ida_funcs.get_func
    • ida_kernwin.UI_Hooks
    • ida_kernwin.enable_chooser_item_attrs

    Create a dockable container, and populate it with Qt widgets

    Using ida_kernwin.PluginForm.FormToPyQtWidget, this script converts IDA’s own dockable widget into a type that is recognized by PyQt5, which then enables populating it with regular Qt widgets.

    Source codeKeywordsLevel
    populate_pluginform_with_pyqt_widgets.pyBeginner

    APIs Used:

    • ida_kernwin.PluginForm

    Prevent an action from being triggered

    Using ida_kernwin.UI_Hooks.preprocess_action, it is possible to respond to a command instead of the action that would otherwise do it.

    Source codeKeywordsLevel
    prevent_jump.pyUI_HooksBeginner

    APIs Used:

    • ida_kernwin.UI_Hooks

    Use timers for delayed execution

    Register (possibly repeating) timers.

    Source codeKeywordsLevel
    register_timer.pyBeginner

    APIs Used:

    • ida_kernwin.register_timer

    Show, update & hide the progress dialog

    Using the progress dialog (aka ‘wait box’) primitives.

    Source codeKeywordsLevel
    show_and_hide_waitbox.pyactionsBeginner

    APIs Used:

    • ida_hexrays.decompile
    • ida_kernwin.hide_wait_box
    • ida_kernwin.replace_wait_box
    • ida_kernwin.show_wait_box
    • ida_kernwin.user_cancelled
    • idautils.Functions

    Custom actions, with icons & tooltips

    How to create user actions, that once created can be inserted in menus, toolbars, context menus, …

    Those actions, when triggered, will be passed a ‘context’ that contains some of the most frequently needed bits of information.

    In addition, custom actions can determine when they want to be available (through their ida_kernwin.action_handler_t.update callback)

    Source codeKeywordsLevel
    actions.pyactions ctxmenu UI_HooksIntermediate

    APIs Used:

    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.SETMENU_APP
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_menu
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.attach_action_to_toolbar
    • ida_kernwin.get_widget_type
    • ida_kernwin.load_custom_icon
    • ida_kernwin.register_action
    • ida_kernwin.unregister_action

    Show tabular data

    Shows how to subclass the ida_kernwin.Choose class to show data organized in a simple table. In addition, registers a couple actions that can be applied to it.

    Source codeKeywordsLevel
    choose.pyactions chooser ctxmenuIntermediate

    APIs Used:

    • Choose
    • Choose.ALL_CHANGED
    • Choose.CH_CAN_DEL
    • Choose.CH_CAN_EDIT
    • Choose.CH_CAN_INS
    • Choose.CH_CAN_REFRESH
    • Choose.CH_RESTORE
    • Choose.NOTHING_CHANGED
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.is_chooser_widget
    • ida_kernwin.register_action
    • ida_kernwin.unregister_action

    Show tabular data, with multiple selection

    Similar to choose, but with multiple selection

    Source codeKeywordsLevel
    choose_multi.pyactions chooserIntermediate

    APIs Used:

    • Choose
    • Choose.ALL_CHANGED
    • Choose.CHCOL_HEX
    • Choose.CH_MULTI
    • Choose.NOTHING_CHANGED

    Create custom listings in IDA

    How to create simple listings, that will share many of the features as the built-in IDA widgets (highlighting, copy & paste, notifications, …)

    In addition, creates actions that will be bound to the freshly-created widget (using ida_kernwin.attach_action_to_popup.)

    Source codeKeywordsLevel
    custom_viewer.pyactions ctxmenu listingIntermediate

    APIs Used:

    • ida_kernwin.AST_ENABLE_ALWAYS
    • ida_kernwin.IK_DELETE
    • ida_kernwin.IK_ESCAPE
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.ask_long
    • ida_kernwin.ask_str
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.register_action
    • ida_kernwin.simplecustviewer_t
    • ida_kernwin.simplecustviewer_t.Create
    • ida_kernwin.simplecustviewer_t.Show
    • ida_kernwin.unregister_action
    • ida_lines.COLOR_DEFAULT
    • ida_lines.COLOR_DNAME
    • ida_lines.COLSTR
    • ida_lines.SCOLOR_PREFIX
    • ida_lines.SCOLOR_VOIDOP

    Implement an alternative “Functions” window

    Partially re-implements the “Functions” widget present in IDA, with a custom widget.

    Source codeKeywordsLevel
    func_chooser.pychooser functionsIntermediate

    APIs Used:

    • ida_funcs.get_func_name
    • ida_kernwin.Choose
    • ida_kernwin.Choose.ALL_CHANGED
    • ida_kernwin.Choose.CHCOL_FNAME
    • ida_kernwin.Choose.CHCOL_HEX
    • ida_kernwin.Choose.CHCOL_PLAIN
    • ida_kernwin.get_icon_id_by_name
    • idautils.Functions
    • idc.del_func

    Implement a “jump to next comment” action within IDA’s listing

    We want our action not only to find the next line containing a comment, but to also place the cursor at the right horizontal position.

    To find that position, we will have to inspect the text that IDA generates, looking for the start of a comment. However, we won’t be looking for a comment “prefix” (e.g., “; “), as that would be too fragile.

    Instead, we will look for special “tags” that IDA injects into textual lines, and that bear semantic information.

    Those tags are primarily used for rendering (i.e., switching colors), but can also be very handy for spotting tokens of interest (registers, addresses, comments, prefixes, instruction mnemonics, …)

    Source codeKeywordsLevel
    jump_next_comment.pyactions idaviewIntermediate

    APIs Used:

    • ida_bytes.next_head
    • ida_idaapi.BADADDR
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.CVNF_LAZY
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.custom_viewer_jump
    • ida_kernwin.get_custom_viewer_location
    • ida_kernwin.place_t_as_idaplace_t
    • ida_kernwin.register_action
    • ida_kernwin.unregister_action
    • ida_lines.SCOLOR_AUTOCMT
    • ida_lines.SCOLOR_ON
    • ida_lines.SCOLOR_REGCMT
    • ida_lines.SCOLOR_RPTCMT
    • ida_lines.generate_disassembly
    • ida_lines.tag_strlen
    • ida_moves.lochist_entry_t

    Dynamically colorize [parts of] lines

    Shows how one can dynamically alter the lines background rendering (as opposed to, say, using ida_nalt.set_item_color()), and also shows how that rendering can be limited to just a few glyphs, not the whole line.

    Source codeKeywordsLevel
    lines_rendering.pyUI_HooksIntermediate

    APIs Used:

    • ida_bytes.next_head
    • ida_idaapi.BADADDR
    • ida_kernwin.CK_EXTRA1
    • ida_kernwin.CK_EXTRA10
    • ida_kernwin.CK_EXTRA11
    • ida_kernwin.CK_EXTRA12
    • ida_kernwin.CK_EXTRA13
    • ida_kernwin.CK_EXTRA14
    • ida_kernwin.CK_EXTRA15
    • ida_kernwin.CK_EXTRA16
    • ida_kernwin.CK_EXTRA2
    • ida_kernwin.CK_EXTRA3
    • ida_kernwin.CK_EXTRA4
    • ida_kernwin.CK_EXTRA5
    • ida_kernwin.CK_EXTRA6
    • ida_kernwin.CK_EXTRA7
    • ida_kernwin.CK_EXTRA8
    • ida_kernwin.CK_EXTRA9
    • ida_kernwin.CK_TRACE
    • ida_kernwin.CK_TRACE_OVL
    • ida_kernwin.LROEF_CPS_RANGE
    • ida_kernwin.UI_Hooks
    • ida_kernwin.get_screen_ea
    • ida_kernwin.line_rendering_output_entry_t
    • ida_kernwin.refresh_idaview_anyway

    React to UI events/notifications

    Hooks to be notified about certain UI events, and dump their information to the “Output” window

    Source codeKeywordsLevel
    log_misc_events.pyUI_HooksIntermediate

    APIs Used:

    • ida_kernwin.UI_Hooks

    Paint on top of the navigation band

    Using an “event filter”, we will intercept paint events targeted at the navigation band widget, let it paint itself, and then add our own markers on top.

    Source codeKeywordsLevel
    paint_over_navbar.pyIntermediate

    APIs Used:

    • ida_kernwin.PluginForm.FormToPyQtWidget
    • ida_kernwin.get_navband_pixel
    • ida_kernwin.open_navband_window
    • ida_segment.get_segm_qty
    • ida_segment.getnseg
    • idc.here

    Save, and then restore, positions in a listing

    Shows how it is possible re-implement IDA’s bookmark capability, using 2 custom actions: one action saves the current location, and the other restores it.

    Note that, contrary to actual bookmarks, this example:

    • remembers only 1 saved position
    • doesn’t save that position in the IDB (and therefore cannot be restored if IDA is closed & reopened.)
    Source codeKeywordsLevel
    save_and_restore_listing_pos.pyactions listingIntermediate

    APIs Used:

    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_CUSTVIEW
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.BWN_TILVIEW
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.custom_viewer_jump
    • ida_kernwin.find_widget
    • ida_kernwin.get_custom_viewer_location
    • ida_kernwin.register_action
    • ida_kernwin.unregister_action
    • ida_moves.lochist_entry_t

    Retrieve the selection from the “Strings” window

    In IDA it’s possible to write actions that can be applied even to core (i.e., “standard”) widgets. The actions in this example use the action “context” to know what the current selection is.

    This example shows how you can either retrieve string literals data directly from the chooser (ida_kernwin.get_chooser_data), or by querying the IDB (ida_bytes.get_strlit_contents)

    Source codeKeywordsLevel
    show_selected_strings.pyactions ctxmenuIntermediate

    APIs Used:

    • ida_bytes.get_strlit_contents
    • ida_idaapi.BADADDR
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_STRINGS
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.find_widget
    • ida_kernwin.get_chooser_data
    • ida_kernwin.open_strings_window
    • ida_kernwin.register_action
    • ida_kernwin.unregister_action
    • ida_strlist.get_strlist_item
    • ida_strlist.string_info_t

    Follow the movements of one graph, in another

    Since it is possible to be notified of movements that happen take place in a widget, it’s possible to “replay” those movements in another.

    In this case, “IDA View-B” (will be opened if necessary) will show the same contents as “IDA View-A”, slightly zoomed out.

    Source codeKeywordsLevel
    sync_two_graphs.pygraph idaviewIntermediate

    APIs Used:

    • ida_graph.GLICTL_CENTER
    • ida_graph.viewer_fit_window
    • ida_graph.viewer_get_gli
    • ida_graph.viewer_set_gli
    • ida_kernwin.DP_RIGHT
    • ida_kernwin.IDAViewWrapper
    • ida_kernwin.MFF_FAST
    • ida_kernwin.TCCRT_GRAPH
    • ida_kernwin.execute_sync
    • ida_kernwin.find_widget
    • ida_kernwin.get_custom_viewer_place
    • ida_kernwin.jumpto
    • ida_kernwin.open_disasm_window
    • ida_kernwin.set_dock_pos
    • ida_kernwin.set_view_renderer_type
    • ida_moves.graph_location_info_t

    Trigger actions programmatically

    It’s possible to invoke any action programmatically, by using either of those two:

    • ida_kernwin.execute_ui_requests()
    • ida_kernwin.process_ui_action()

    Ideally, this script should be run through the “File > Script file…” menu, so as to keep focus on “IDA View-A” and have the ‘ProcessUiActions’ part work as intended.

    Source codeKeywordsLevel
    trigger_actions_programmatically.pyactionsIntermediate

    APIs Used:

    • ida_kernwin.ask_yn
    • ida_kernwin.execute_ui_requests
    • ida_kernwin.msg
    • ida_kernwin.process_ui_action

    Advanced usage of the form API

    How to query for complex user input, using IDA’s built-in forms.

    Note: while this example produces full-fledged forms for complex input, simpler types of inputs might can be retrieved by using ida_kernwin.ask_str and similar functions.

    Source codeKeywordsLevel
    askusingform.pyformsAdvanced

    APIs Used:

    • ida_kernwin.Choose
    • ida_kernwin.Choose.CH_MULTI
    • ida_kernwin.Form
    • ida_kernwin.PluginForm.FORM_TAB
    • ida_kernwin.ask_str

    Restore custom widgets across sessions

    This is an example demonstrating how one can create widgets from a plugin, and have them re-created automatically at IDA startup-time or at desktop load-time.

    This example should be placed in the ‘plugins’ directory of the IDA installation, for it to work.

    There are 2 ways to use this example:

    1. reloading an IDB, where the widget was opened
      • open the widget (‘View > Open subview > …’)
      • save this IDB, and close IDA
      • restart IDA with this IDB => the widget will be visible
    2. reloading a desktop, where the widget was opened
      • open the widget (‘View > Open subview > …’)
      • save the desktop (‘Windows > Save desktop…’) under, say, the name ‘with_auto’
      • start another IDA instance with some IDB, and load that desktop => the widget will be visible
    Source codeKeywordsLevel
    auto_instantiate_widget_plugin.pydesktop plugin UI_HooksAdvanced

    APIs Used:

    • ida_idaapi.plugin_t
    • ida_kernwin.AST_ENABLE_ALWAYS
    • ida_kernwin.SETMENU_APP
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_menu
    • ida_kernwin.find_widget
    • ida_kernwin.register_action
    • ida_kernwin.simplecustviewer_t
    • ida_kernwin.simplecustviewer_t.Create

    Showing tabular data in a flat, or tree-like fashion

    By adding the necessary bits to a ida_kernwin.Choose subclass, IDA can show the otherwise tabular data, in a tree-like fashion.

    The important bits to enable this are:

    • ida_dirtree.dirspec_t (and my_dirspec_t)
    • ida_kernwin.CH_HAS_DIRTREE
    • ida_kernwin.Choose.OnGetDirTree
    • ida_kernwin.Choose.OnIndexToInode
    Source codeKeywordsLevel
    chooser_with_folders.pyactions chooser foldersAdvanced

    APIs Used:

    • ida_dirtree.DTE_OK
    • ida_dirtree.direntry_t
    • ida_dirtree.direntry_t.BADIDX
    • ida_dirtree.dirspec_t
    • ida_dirtree.dirtree_t
    • ida_dirtree.dirtree_t.isdir
    • ida_kernwin.CH_CAN_DEL
    • ida_kernwin.CH_CAN_EDIT
    • ida_kernwin.CH_CAN_INS
    • ida_kernwin.CH_HAS_DIRTREE
    • ida_kernwin.CH_MULTI
    • ida_kernwin.Choose
    • ida_kernwin.Choose.ALL_CHANGED
    • ida_kernwin.Choose.CHCOL_DRAGHINT
    • ida_kernwin.Choose.CHCOL_INODENAME
    • ida_kernwin.Choose.CHCOL_PLAIN
    • ida_kernwin.ask_str
    • ida_netnode.BADNODE
    • ida_netnode.netnode

    Colorize lines interactively

    This builds upon the ida_kernwin.UI_Hooks.get_lines_rendering_info feature, to provide a quick & easy way to colorize disassembly lines.

    Contrary to @colorize_disassembly, the coloring is not persisted in the database, and will therefore be lost after the session.

    By triggering the action multiple times, the user can “carousel” across 4 predefined colors (and return to the “no color” state.)

    Source codeKeywordsLevel
    colorize_disassembly_on_the_fly.pycoloring UI_HooksAdvanced

    APIs Used:

    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.CK_EXTRA5
    • ida_kernwin.CK_EXTRA6
    • ida_kernwin.CK_EXTRA7
    • ida_kernwin.CK_EXTRA8
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_current_viewer
    • ida_kernwin.get_custom_viewer_location
    • ida_kernwin.get_custom_viewer_place_xcoord
    • ida_kernwin.get_widget_title
    • ida_kernwin.line_rendering_output_entry_t
    • ida_kernwin.register_action
    • ida_moves.lochist_entry_t

    Add a custom command-line interpreter

    Illustrates how one can add command-line interpreters to IDA

    This custom interpreter doesn’t actually run any code; it’s there as a ‘getting started’. It provides an example tab completion support.

    Source codeKeywordsLevel
    custom_cli.pyAdvanced

    APIs Used:

    • ida_idaapi.NW_CLOSEIDB
    • ida_idaapi.NW_OPENIDB
    • ida_idaapi.NW_REMOVE
    • ida_idaapi.NW_TERMIDA
    • ida_idaapi.notify_when
    • ida_kernwin.cli_t

    Draw custom graphs

    Showing custom graphs, using ida_graph.GraphViewer. In addition, show how to write actions that can be performed on those.

    Source codeKeywordsLevel
    custom_graph_with_actions.pyactions graph View_HooksAdvanced

    APIs Used:

    • ida_funcs.get_func
    • ida_funcs.get_func_name
    • ida_graph.GraphViewer
    • ida_graph.get_graph_viewer
    • ida_graph.screen_graph_selection_t
    • ida_graph.viewer_get_selection
    • ida_idp.is_call_insn
    • ida_kernwin.AST_ENABLE_ALWAYS
    • ida_kernwin.View_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_dynamic_action_to_popup
    • ida_kernwin.get_screen_ea
    • ida_ua.decode_insn
    • ida_ua.insn_t
    • ida_xref.XREF_FAR
    • ida_xref.xrefblk_t

    Retrieve & dump current selection

    Shows how to retrieve the selection from a listing widget (“IDA View-A”, “Hex View-1”, “Pseudocode-A”, …) as two “cursors”, and from there retrieve (in fact, generate) the corresponding text.

    After running this script:

    • select some text in one of the listing widgets (i.e., “IDA View-…”, “Local Types”, “Pseudocode-…”)
    • press Ctrl+Shift+S to dump the selection
    Source codeKeywordsLevel
    dump_selection.pyAdvanced

    APIs Used:

    • ida_kernwin.ACF_HAS_SELECTION
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.BWN_TILVIEW
    • ida_kernwin.IWID_ANY_LISTING
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_last_widget
    • ida_kernwin.get_viewer_user_data
    • ida_kernwin.l_compare2
    • ida_kernwin.linearray_t
    • ida_kernwin.read_selection
    • ida_kernwin.register_action
    • ida_kernwin.twinpos_t
    • ida_kernwin.unregister_action
    • ida_lines.tag_remove

    Inject commands in the “Output” window

    This example illustrates how one can execute commands in the “Output” window, from their own widgets.

    A few notes:

    • the original, underlying cli:Execute action, that has to be triggered for the code present in the input field to execute and be placed in the history, requires that the input field has focus (otherwise it simply won’t do anything.)
    • this, in turn, forces us to do “delayed” execution of that action, hence the need for a QTimer
    • the IDA/SWiG ‘TWidget’ type that we retrieve through ida_kernwin.find_widget, is not the same type as a QtWidgets.QWidget. We therefore need to convert it using ida_kernwin.PluginForm.TWidgetToPyQtWidget
    Source codeKeywordsLevel
    inject_command.pyAdvanced

    APIs Used:

    • ida_kernwin.PluginForm.TWidgetToPyQtWidget
    • ida_kernwin.disabled_script_timeout_t
    • ida_kernwin.find_widget
    • ida_kernwin.process_ui_action

    A lazy-loaded, tree-like data view

    Brings lazy-loading of folders to the tree-like tabular views.

    The important bit to enable this are:

    • ida_kernwin.Choose.OnLazyLoadDir
    Source codeKeywordsLevel
    lazy_loaded_chooser.pyactions chooser foldersAdvanced

    Paint text on graph view edges

    This sample registers an action enabling painting of a recognizable string of text over horizontal nodes edge sections beyond a satisfying size threshold.

    In a disassembly view, open the context menu and select “Paint on edges”. This should work for both graph disassembly, and proximity browser.

    Using an “event filter”, we will intercept paint events targeted at the disassembly view, let it paint itself, and then add our own markers along.

    Source codeKeywordsLevel
    paint_over_graph.pyctxmenu UI_HooksAdvanced

    APIs Used:

    • ida_gdl.edge_t
    • ida_graph.get_graph_viewer
    • ida_graph.get_viewer_graph
    • ida_graph.point_t
    • ida_graph.viewer_get_gli
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.PluginForm.FormToPyQtWidget
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.get_widget_type
    • ida_kernwin.register_action
    • ida_moves.graph_location_info_t

    Programmatically manipulate disassembly and graph widgets

    This is an example illustrating how to manipulate an existing IDA-provided view (and thus possibly its graph), in Python.

    Source codeKeywordsLevel
    wrap_idaview.pygraph idaviewAdvanced

    APIs Used:

    • ida_graph.NIF_BG_COLOR
    • ida_graph.NIF_FRAME_COLOR
    • ida_graph.node_info_t
    • ida_kernwin.IDAViewWrapper
    • ida_kernwin.MFF_FAST
    • ida_kernwin.TCCRT_FLAT
    • ida_kernwin.TCCRT_GRAPH
    • ida_kernwin.execute_sync

    Dump function flowchart

    Dumps the current function’s flowchart, using 2 methods:

    • the low-level ida_gdl.qflow_chart_t type
    • the somewhat higher-level, and slightly more pythonic ida_gdl.FlowChart type.
    Source codeKeywordsLevel
    dump_flowchart.pyBeginner

    APIs Used:

    • ida_funcs.get_func
    • ida_gdl.FlowChart
    • ida_gdl.qflow_chart_t
    • ida_kernwin.get_screen_ea

    Insert information into listing prefixes

    By default, disassembly line prefixes contain segment + address information (e.g., ‘.text:08047718’), but it is possible to “inject” other bits of information in there, thanks to the ida_lines.user_defined_prefix_t helper type.

    Source codeKeywordsLevel
    install_user_defined_prefix.pypluginBeginner

    APIs Used:

    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_lines.SCOLOR_INV
    • ida_lines.user_defined_prefix_t

    Enumerate file imports

    Using the API to enumerate file imports.

    Source codeKeywordsLevel
    list_imports.pyBeginner

    APIs Used:

    • ida_nalt.enum_import_names
    • ida_nalt.get_import_module_name
    • ida_nalt.get_import_module_qty

    Enumerate patched bytes

    Using the API to iterate over all the places in the file, that were patched using IDA.

    Source codeKeywordsLevel
    list_patched_bytes.pyBeginner

    APIs Used:

    • ida_bytes.visit_patched_bytes
    • ida_idaapi.BADADDR

    Enumerate known problems

    Using the API to list all problems that IDA encountered during analysis.

    Source codeKeywordsLevel
    list_problems.pyBeginner

    APIs Used:

    • ida_ida.inf_get_min_ea
    • ida_idaapi.BADADDR
    • ida_problems.PR_ATTN
    • ida_problems.PR_BADSTACK
    • ida_problems.PR_COLLISION
    • ida_problems.PR_DECIMP
    • ida_problems.PR_DISASM
    • ida_problems.PR_FINAL
    • ida_problems.PR_HEAD
    • ida_problems.PR_ILLADDR
    • ida_problems.PR_JUMP
    • ida_problems.PR_MANYLINES
    • ida_problems.PR_NOBASE
    • ida_problems.PR_NOCMT
    • ida_problems.PR_NOFOP
    • ida_problems.PR_NONAME
    • ida_problems.PR_NOXREFS
    • ida_problems.PR_ROLLED
    • ida_problems.get_problem
    • ida_problems.get_problem_name

    List segment functions (and cross-references to them)

    List all the functions in the current segment, as well as all the cross-references to them.

    Source codeKeywordsLevel
    list_segment_functions.pyxrefsBeginner

    APIs Used:

    • ida_funcs.get_func
    • ida_funcs.get_func_name
    • ida_funcs.get_next_func
    • ida_kernwin.get_screen_ea
    • ida_segment.getseg
    • ida_xref.xrefblk_t

    List all functions (and cross-references) in segment

    List all the functions in the current segment, as well as all the cross-references to them.

    Contrary to @list_segment_functions, this uses the somewhat higher-level idautils module.

    Source codeKeywordsLevel
    list_segment_functions_using_idautils.pyxrefsBeginner

    APIs Used:

    • ida_funcs.get_func_name
    • ida_idaapi.BADADDR
    • ida_kernwin.get_screen_ea
    • ida_segment.getseg
    • idautils.CodeRefsTo
    • idautils.Functions

    Dump the strings that are present in the file

    This uses idautils.Strings to iterate over the string literals that are present in the IDB. Contrary to @show_selected_strings, this will not require that the “Strings” window is opened & available.

    Source codeKeywordsLevel
    list_strings.pyBeginner

    APIs Used:

    • ida_nalt.STRTYPE_C
    • ida_nalt.STRTYPE_C_16
    • idautils.Strings

    Produce disassembly listing for the entire file

    Automate IDA to perform auto-analysis on a file and, once that is done, produce a .lst file with the disassembly.

    Run like so:

      ida -A "-S...path/to/produce_lst_file.py" <binary-file>
    

    where:

    • -A instructs IDA to run in non-interactive mode
    • -S holds a path to the script to run (note this is a single token; there is no space between ‘-S’ and its path.)
    Source codeKeywordsLevel
    produce_lst_file.pyBeginner

    APIs Used:

    • ida_auto.auto_wait
    • ida_fpro.qfile_t
    • ida_ida.inf_get_max_ea
    • ida_ida.inf_get_min_ea
    • ida_loader.OFILE_LST
    • ida_loader.PATH_TYPE_IDB
    • ida_loader.gen_file
    • ida_loader.get_path
    • ida_pro.qexit

    Rewrite the representation of some instructions

    Implements disassembly of BUG_INSTR used in Linux kernel BUG() macro, which is architecturally undefined and is not disassembled by IDA’s ARM module

    See Linux/arch/arm/include/asm/bug.h for more info

    Source codeKeywordsLevel
    ana_emu_out.pyIDP_HooksIntermediate

    APIs Used:

    • ida_bytes.get_wide_dword
    • ida_bytes.get_wide_word
    • ida_idp.CUSTOM_INSN_ITYPE
    • ida_idp.IDP_Hooks
    • ida_idp.PLFM_ARM
    • ida_idp.ph.id
    • ida_idp.str2reg
    • ida_segregs.get_sreg

    Implement assembly of instructions

    We add support for assembling the following pseudo instructions:

    • “zero eax” -> xor eax, eax
    • “nothing” -> nop
    Source codeKeywordsLevel
    assemble.pyIDP_HooksIntermediate

    APIs Used:

    • ida_idp.IDP_Hooks
    • idautils.DecodeInstruction

    Retrieve comments surrounding instructions

    Use the ida_lines.get_extra_cmt API to retrieve anterior and posterior extra comments.

    This script registers two actions, that can be used to dump the previous and next extra comments.

    Source codeKeywordsLevel
    dump_extra_comments.pyctxmenuIntermediate

    APIs Used:

    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.find_widget
    • ida_kernwin.get_screen_ea
    • ida_kernwin.register_action
    • ida_kernwin.unregister_action
    • ida_lines.E_NEXT
    • ida_lines.E_PREV
    • ida_lines.get_extra_cmt
    • ida_view

    Dump function information

    Dump some of the most interesting bits of information about the function we are currently looking at.

    Source codeKeywordsLevel
    dump_func_info.pyIntermediate

    APIs Used:

    • ida_funcs.FUNC_FRAME
    • ida_funcs.FUNC_LUMINA
    • ida_funcs.FUNC_OUTLINE
    • ida_funcs.FUNC_THUNK
    • ida_funcs.get_fchunk
    • ida_funcs.is_func_entry
    • ida_funcs.is_func_tail
    • ida_kernwin.get_screen_ea

    Using “ida_bytes.find_string”

    IDAPython’s ida_bytes.find_string can be used to implement a simple replacement for the ‘Search > Sequence of bytes…’ dialog, that lets users search for sequences of bytes that compose string literals in the binary file (either in the default 1-byte-per-char encoding, or as UTF-16.)

    Source codeKeywordsLevel
    find_string.pyIntermediate

    APIs Used:

    • ida_bytes.BIN_SEARCH_FORWARD
    • ida_bytes.BIN_SEARCH_NOBREAK
    • ida_bytes.BIN_SEARCH_NOSHOW
    • ida_bytes.find_string
    • ida_ida.inf_get_max_ea
    • ida_idaapi.BADADDR
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.Form
    • ida_kernwin.Form.ChkGroupControl
    • ida_kernwin.Form.StringInput
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_screen_ea
    • ida_kernwin.jumpto
    • ida_kernwin.register_action
    • ida_nalt.BPU_1B
    • ida_nalt.BPU_2B
    • ida_nalt.get_default_encoding_idx

    The goal of this script is to demonstrate some usage of the type API. In this script, we will create an IDB hook that intercepts ti_changed IDB events, and if it is a function prototype that changed, print it.

    Source codeKeywordsLevel
    func_ti_changed_listener.pyIDB_HooksIntermediate

    APIs Used:

    • ida_funcs.get_func_name
    • ida_idp.IDB_Hooks
    • ida_typeinf.tinfo_t

    List listing bookmarks

    This sample shows how to programmatically access the list of bookmarks placed in a listing widget (e.g., “IDA View-A”, “Pseudocode-”, …) using the low-level ida_moves.bookmarks_t type.

    Source codeKeywordsLevel
    list_bookmarks.pybookmarksIntermediate

    APIs Used:

    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_current_viewer
    • ida_kernwin.get_viewer_user_data
    • ida_kernwin.get_widget_title
    • ida_kernwin.register_action
    • ida_moves.bookmarks_t

    Showcase (some of) the iterators available on a function

    This demonstrates how to use some of the iterators available on the func_t type.

    This example will focus on:

    • func_t[.__iter__]: the default iterator; iterates on instructions
    • func_t.data_items: iterate on data items contained within a function
    • func_t.head_items: iterate on ‘heads’ (i.e., addresses containing the start of an instruction, or a data item.
    • func_t.addresses: iterate on all addresses within function (code and data, beginning of an item or not)

    Type help(ida_funcs.func_t) for a full list of iterators.

    In addition, one can use:

    • func_tail_iterator_t: iterate on all the chunks (including the main one) of the function
    • func_parent_iterator_t: iterate on all the parent functions, that include this chunk
    Source codeKeywordsLevel
    list_function_items.pyfuncs iteratorIntermediate

    APIs Used:

    • ida_bytes.get_flags
    • ida_bytes.is_code
    • ida_bytes.is_data
    • ida_bytes.is_tail
    • ida_bytes.is_unknown
    • ida_funcs.func_tail_iterator_t
    • ida_funcs.get_fchunk
    • ida_funcs.get_func
    • ida_funcs.get_func_name
    • ida_kernwin.get_screen_ea
    • ida_ua.print_insn_mnem

    React to database events/notifications

    These hooks will be notified about IDB events, and dump their information to the “Output” window

    Source codeKeywordsLevel
    log_idb_events.pyIDB_HooksIntermediate

    APIs Used:

    • ida_idp.IDB_Hooks

    React to processor events/notifications

    These hooks will be notified about IDP events, and dump their information to the “Output” window

    Source codeKeywordsLevel
    log_idp_events.pyIDP_HooksIntermediate

    APIs Used:

    • ida_idp.IDP_Hooks

    Record and replay changes in function prototypes

    This is a sample script, that will record (in memory) all changes in functions prototypes, in order to re-apply them later.

    To use this script:

    • open an IDB (say, “test.idb”)
    • modify some functions prototypes (e.g., by triggering the ‘Y’ shortcut when the cursor is placed on the first address of a function)
    • reload that IDB, without saving it first
    • call rpc.replay(), to re-apply the modifications.

    Note: ‘ti_changed’ is also called for changes to the function frames, but we’ll only record function prototypes changes.

    Source codeKeywordsLevel
    replay_prototypes_changes.pyIDB_HooksIntermediate

    APIs Used:

    • ida_funcs.get_func
    • ida_idp.IDB_Hooks
    • ida_typeinf.PRTYPE_1LINE
    • ida_typeinf.TINFO_DEFINITE
    • ida_typeinf.apply_tinfo
    • ida_typeinf.get_idati
    • ida_typeinf.tinfo_t

    Add a new member to an existing function frame

    The goal of this script is to demonstrate some usage of the type API. In this script, we show a way to add a new frame member (a pointer to an uint64) inside a wide enough gap in the frame:

    • Get the function object surrounding cursor location.
    • Use this function to retrieve the corresponding frame object.
    • Find a wide enough gap to create our new member.
    • If found, we use cal_frame_offset() to get the actual offset in the frame structure.
    • Use the previous result to add the new member.
    Source codeKeywordsLevel
    add_frame_member.pyAdvanced

    APIs Used:

    • ida_frame.add_frame_member
    • ida_frame.calc_frame_offset
    • ida_frame.get_func_frame
    • ida_funcs.get_func
    • ida_range.rangeset_t
    • ida_typeinf.BTF_UINT64
    • ida_typeinf.tinfo_t
    • idc.here

    Custom data types & printers

    IDA can be extended to support certain data types that it does not know about out-of-the-box.

    A ‘custom data type’ provide information about the type & size of a piece of data, while a ‘custom data format’ is in charge of formatting that data (there can be more than one format for a specific ‘custom data type’.)

    Source codeKeywordsLevel
    custom_data_types_and_formats.pyAdvanced

    APIs Used:

    • ida_bytes.data_format_t
    • ida_bytes.data_type_t
    • ida_bytes.find_custom_data_type
    • ida_bytes.get_byte
    • ida_bytes.register_data_types_and_formats
    • ida_bytes.unregister_data_types_and_formats
    • ida_idaapi.NW_CLOSEIDB
    • ida_idaapi.NW_OPENIDB
    • ida_idaapi.NW_REMOVE
    • ida_idaapi.NW_TERMIDA
    • ida_idaapi.notify_when
    • ida_idaapi.struct_unpack
    • ida_lines.COLSTR
    • ida_lines.SCOLOR_IMPNAME
    • ida_lines.SCOLOR_INSN
    • ida_lines.SCOLOR_NUMBER
    • ida_lines.SCOLOR_REG
    • ida_nalt.get_input_file_path
    • ida_netnode.netnode
    • ida_typeinf.tinfo_t

    List operands representing a “path” to a (possibly nested) structure member

    It is possible to assign, to instruction operands, the notion of “structure offset”, which really is a pointer to a specific offset in a type, leading to a possible N-deep path within types.

    E.g., assuming the following types

        struct c
        {
            int foo;
            int bar;
            int baz;
            int quux;
            int trail;
        };
    
        struct b
        {
            int gap;
            c c_instance;
        };
    
        struct a
        {
            int count;
            b b_instance;
        };
    

    and assuming an instruction that initially looks like this:

        mov eax, 10h
    

    by pressing t, the user will be able set the “structure offset” to either:

    • c.trail
    • b.c_instance.quux
    • a.b_inscance.c_instance.baz

    Here’s why IDA offers a.b_inscance.c_instance.baz:

        0000   struct a
               {
        0000       int count;
        0004       struct b
                   {
        0004           int gap;
        0008           struct c
                       {
        0008               int foo;
        000C               int bar;
        0010               int baz;
        0014               int quux;
        0018               int trail;
                       };
                   };
               };
    

    This sample shows how to programmatically retrieve information about that “structure member path” that an operand was made pointing to.

    Source codeKeywordsLevel
    list_struct_accesses.pybookmarksAdvanced

    APIs Used:

    • ida_bytes.get_full_flags
    • ida_bytes.get_stroff_path
    • ida_bytes.is_stroff
    • ida_typeinf.get_tid_name
    • ida_typeinf.tinfo_t
    • ida_ua.decode_insn
    • ida_ua.insn_t
    • ida_ua.o_imm
    • ida_ua.o_void

    Notify the user when an instruction operand changes

    Show notifications whenever the user changes an instruction’s operand, or a data item.

    Source codeKeywordsLevel
    operand_changed.pyIDB_HooksAdvanced

    APIs Used:

    • ida_bytes.ALOPT_IGNCLT
    • ida_bytes.ALOPT_IGNHEADS
    • ida_bytes.get_flags
    • ida_bytes.get_max_strlit_length
    • ida_bytes.get_opinfo
    • ida_bytes.get_strlit_contents
    • ida_bytes.is_custfmt
    • ida_bytes.is_custom
    • ida_bytes.is_enum
    • ida_bytes.is_off
    • ida_bytes.is_strlit
    • ida_bytes.is_stroff
    • ida_bytes.is_struct
    • ida_idp.IDB_Hooks
    • ida_nalt.STRENC_DEFAULT
    • ida_nalt.get_default_encoding_idx
    • ida_nalt.get_encoding_name
    • ida_nalt.get_str_encoding_idx
    • ida_nalt.get_strtype_bpu
    • ida_nalt.opinfo_t
    • ida_typeinf.get_tid_name
    • ida_typeinf.tinfo_t

    Produce C listing for the entire file

    Automate IDA to perform auto-analysis on a file and, once that is done, produce a .c file containing the decompilation of all the functions in that file.

    Run like so:

      ida -A "-S...path/to/produce_c_file.py" <binary-file>
    

    where:

    • -A instructs IDA to run in non-interactive mode
    • -S holds a path to the script to run (note this is a single token; there is no space between ‘-S’ and its path.)
    Source codeKeywordsLevel
    produce_c_file.pyBeginner

    APIs Used:

    • ida_auto.auto_wait
    • ida_hexrays.VDRUN_MAYSTOP
    • ida_hexrays.VDRUN_NEWFILE
    • ida_hexrays.VDRUN_SILENT
    • ida_hexrays.decompile_many
    • ida_loader.PATH_TYPE_IDB
    • ida_loader.get_path
    • ida_pro.qexit

    Decompile & print current function

    Decompile the function under the cursor

    Source codeKeywordsLevel
    vds1.pyBeginner

    APIs Used:

    • ida_funcs.get_func
    • ida_hexrays.decompile
    • ida_hexrays.get_hexrays_version
    • ida_hexrays.init_hexrays_plugin
    • ida_kernwin.get_screen_ea
    • ida_lines.tag_remove

    Generate microcode for the selected range of instructions

    Generates microcode for selection and dumps it to the output window.

    Source codeKeywordsLevel
    vds13.pyBeginner

    APIs Used:

    • ida_bytes.get_flags
    • ida_bytes.is_code
    • ida_hexrays.DECOMP_WARNINGS
    • ida_hexrays.gen_microcode
    • ida_hexrays.hexrays_failure_t
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.mba_ranges_t
    • ida_hexrays.vd_printer_t
    • ida_kernwin.read_range_selection
    • ida_kernwin.warning
    • ida_range.range_t

    Dump statement blocks

    Using a ida_hexrays.ctree_visitor_t, search for ida_hexrays.cit_block instances and dump them.

    Source codeKeywordsLevel
    vds7.pyHexrays_HooksBeginner

    APIs Used:

    • ida_hexrays.CMAT_BUILT
    • ida_hexrays.CV_FAST
    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.cit_block
    • ida_hexrays.ctree_visitor_t
    • ida_hexrays.init_hexrays_plugin

    Provide custom decompiler hints

    Handle ida_hexrays.hxe_create_hint notification using hooks, to return our own.

    If the object under the cursor is:

    • a function call, prefix the original decompiler hint with ==>
    • a local variable declaration, replace the hint with our own in the form of !{varname} (where {varname} is replaced with the variable name)
    • an if statement, replace the hint with our own, saying “condition”
    Source codeKeywordsLevel
    vds_create_hint.pyHexrays_HooksBeginner

    APIs Used:

    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.USE_MOUSE
    • ida_hexrays.VDI_EXPR
    • ida_hexrays.VDI_LVAR
    • ida_hexrays.cit_if
    • ida_hexrays.cot_call

    Interactively color decompilation lines

    Provides an action that can be used to dynamically alter the lines background rendering for pseudocode listings (as opposed to using ida_hexrays.cfunc_t.pseudocode[N].bgcolor)

    After running this script, pressing ‘M’ on a line in a “Pseudocode-?” widget, will cause that line to be rendered with a special background color.

    Source codeKeywordsLevel
    colorize_pseudocode_lines.pycolors UI_HooksIntermediate

    APIs Used:

    • ida_hexrays.get_widget_vdui
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.CK_EXTRA11
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_custom_viewer_location
    • ida_kernwin.line_rendering_output_entry_t
    • ida_kernwin.refresh_custom_viewer
    • ida_kernwin.register_action
    • ida_moves.lochist_entry_t

    Decompile entrypoint automatically

    Attempts to load a decompiler plugin corresponding to the current architecture right after auto-analysis is performed, and then tries to decompile the function at the first entrypoint.

    It is particularly suited for use with the ‘-S’ flag, for example: idat -Ldecompile.log -Sdecompile_entry_points.py -c file

    Source codeKeywordsLevel
    decompile_entry_points.pyIntermediate

    APIs Used:

    • ida_auto.auto_wait
    • ida_entry.get_entry
    • ida_entry.get_entry_ordinal
    • ida_entry.get_entry_qty
    • ida_hexrays.decompile
    • ida_hexrays.init_hexrays_plugin
    • ida_idp.PLFM_386
    • ida_idp.PLFM_ARM
    • ida_idp.PLFM_MIPS
    • ida_idp.PLFM_PPC
    • ida_idp.PLFM_RISCV
    • ida_idp.ph.id
    • ida_kernwin.cvar.batch
    • ida_kernwin.msg
    • ida_loader.load_plugin
    • ida_pro.qexit
    • idc.get_idb_path

    Add custom microcode instruction optimization rule

    Installs a custom microcode instruction optimization rule, to transform:

    call   !DbgRaiseAssertionFailure <fast:>.0
    

    into

    call   !DbgRaiseAssertionFailure <fast:"char *" "assertion text">.0
    

    To see this plugin in action please use arm64_brk.i64

    Source codeKeywordsLevel
    vds10.pypluginIntermediate

    APIs Used:

    • ida_bytes.get_cmt
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.mop_str
    • ida_hexrays.optinsn_t
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_typeinf.STI_PCCHAR
    • ida_typeinf.tinfo_t.get_stock

    Dynamically provide a custom call type

    This plugin can greatly improve decompilation of indirect calls:

    call    [eax+4]
    

    For them, the decompiler has to guess the prototype of the called function. This has to be done at a very early phase of decompilation because the function prototype influences the data flow analysis. On the other hand, we do not have global data flow analysis results yet because we haven’t analyzed all calls in the function. It is a chicked-and-egg problem.

    The decompiler uses various techniques to guess the called function prototype. While it works very well, it may fail in some cases.

    To fix, the user can specify the call prototype manually, using “Edit, Operand types, Set operand type” at the call instruction.

    This plugin illustrates another approach to the problem: if you happen to be able to calculate the call prototypes dynamically, this is how to inform the decompiler about them.

    Source codeKeywordsLevel
    vds21.pyHexrays_Hooks pluginIntermediate

    APIs Used:

    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.m_call
    • ida_hexrays.mcallinfo_t
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_kernwin.msg
    • ida_kernwin.warning
    • ida_nalt.get_op_tinfo
    • ida_typeinf.BT_INT
    • ida_typeinf.CM_CC_STDCALL
    • ida_typeinf.CM_N32_F48
    • ida_typeinf.parse_decl
    • ida_typeinf.tinfo_t

    Dump user-defined information for a function

    Prints user-defined information to the “Output” window. Namely:

    • user defined label names
    • user defined indented comments
    • user defined number formats
    • user defined local variable names, types, comments

    This script loads information from the database without decompiling anything.

    Source codeKeywordsLevel
    vds4.pyIntermediate

    APIs Used:

    • ida_bytes.get_radix
    • ida_funcs.get_func
    • ida_hexrays.CIT_COLLAPSED
    • ida_hexrays.NF_NEGATE
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.lvar_uservec_t
    • ida_hexrays.restore_user_cmts
    • ida_hexrays.restore_user_iflags
    • ida_hexrays.restore_user_labels
    • ida_hexrays.restore_user_lvar_settings
    • ida_hexrays.restore_user_numforms
    • ida_hexrays.user_cmts_free
    • ida_hexrays.user_iflags_free
    • ida_hexrays.user_labels_free
    • ida_hexrays.user_numforms_free
    • ida_kernwin.get_screen_ea

    Superficially modify the decompilation output

    Modifies the decompilation output in a superficial manner, by removing some white spaces

    Note: this is rather crude, not quite “pythonic” code.

    Source codeKeywordsLevel
    vds6.pyHexrays_Hooks pluginIntermediate

    APIs Used:

    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.init_hexrays_plugin
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_lines.tag_advance
    • ida_lines.tag_skipcodes

    Improve decompilation by turning specific patterns into custom function calls

    Registers an action that uses a ida_hexrays.udc_filter_t to decompile svc 0x900001 and svc 0x9000F8 as function calls to svc_exit() and svc_exit_group() respectively.

    You will need to have an ARM + Linux IDB for this script to be usable

    In addition to having a shortcut, the action will be present in the context menu.

    Source codeKeywordsLevel
    vds8.pyctxmenu UI_HooksIntermediate

    APIs Used:

    • ida_allins.ARM_svc
    • ida_hexrays.get_widget_vdui
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.install_microcode_filter
    • ida_hexrays.udc_filter_t
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.get_widget_type
    • ida_kernwin.register_action

    React to decompiler events/notifications

    Shows how to hook to many notifications sent by the decompiler.

    This plugin doesn’t really accomplish anything: it just prints the parameters.

    The list of notifications handled below should be exhaustive, and is there to hint at what is possible to accomplish by subclassing ida_hexrays.Hexrays_Hooks

    Source codeKeywordsLevel
    vds_hooks.pyHexrays_HooksIntermediate

    APIs Used:

    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.cfunc_t
    • ida_hexrays.lvar_t
    • ida_hexrays.vdui_t

    Modifying function local variables

    Use a ida_hexrays.user_lvar_modifier_t to modify names, comments and/or types of local variables.

    Source codeKeywordsLevel
    vds_modify_user_lvars.pyIntermediate

    APIs Used:

    • ida_hexrays.modify_user_lvars
    • ida_hexrays.user_lvar_modifier_t
    • ida_typeinf.parse_decl
    • idc.here

    Shows how user input information can be retrieved during processing of a notification triggered by that input

    Source codeKeywordsLevel
    curpos_details.pyHexrays_HooksAdvanced

    APIs Used:

    • ida_hexrays.Hexrays_Hooks
    • ida_kernwin.get_user_input_event
    • ida_kernwin.iek_key_press
    • ida_kernwin.iek_key_release
    • ida_kernwin.iek_mouse_button_press
    • ida_kernwin.iek_mouse_button_release
    • ida_kernwin.iek_mouse_wheel
    • ida_kernwin.iek_shortcut
    • ida_kernwin.input_event_t

    Add a custom microcode block optimization rule

    Installs a custom microcode block optimization rule, to transform:

      goto L1
      ...
    L1:
      goto L2
    

    into

      goto L2
    

    In other words we fix a goto target if it points to a chain of gotos. This improves the decompiler output in some cases.

    Source codeKeywordsLevel
    vds11.pypluginAdvanced

    APIs Used:

    • ida_hexrays.getf_reginsn
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.m_goto
    • ida_hexrays.optblock_t
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t

    List instruction registers

    Shows a list of direct references to a register from the current instruction.

    Source codeKeywordsLevel
    vds12.pyAdvanced

    APIs Used:

    • ida_bytes.get_flags
    • ida_bytes.is_code
    • ida_funcs.get_func
    • ida_hexrays.ACFL_GUESS
    • ida_hexrays.DECOMP_NO_CACHE
    • ida_hexrays.DECOMP_WARNINGS
    • ida_hexrays.GCO_DEF
    • ida_hexrays.GCO_USE
    • ida_hexrays.GC_REGS_AND_STKVARS
    • ida_hexrays.MERR_OK
    • ida_hexrays.MMAT_PREOPTIMIZED
    • ida_hexrays.MUST_ACCESS
    • ida_hexrays.gco_info_t
    • ida_hexrays.gen_microcode
    • ida_hexrays.get_current_operand
    • ida_hexrays.get_merror_desc
    • ida_hexrays.hexrays_failure_t
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.mba_ranges_t
    • ida_hexrays.mlist_t
    • ida_hexrays.op_parent_info_t
    • ida_hexrays.voff_t
    • ida_kernwin.Choose
    • ida_kernwin.get_screen_ea
    • ida_kernwin.jumpto
    • ida_kernwin.warning
    • ida_lines.GENDSM_REMOVE_TAGS
    • ida_lines.generate_disasm_line
    • ida_pro.eavec_t

    Invoke the structure offset-choosing dialog from decompilation

    Registers an action opens the “Select offsets” widget (select_udt_by_offset() call).

    This effectively repeats the functionality already available through Alt+Y.

    Place cursor on the union field and press Shift+T

    Source codeKeywordsLevel
    vds17.pypluginAdvanced

    APIs Used:

    • ida_hexrays.USE_KEYBOARD
    • ida_hexrays.cot_add
    • ida_hexrays.cot_cast
    • ida_hexrays.cot_memptr
    • ida_hexrays.cot_memref
    • ida_hexrays.cot_num
    • ida_hexrays.cot_ref
    • ida_hexrays.get_hexrays_version
    • ida_hexrays.get_widget_vdui
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.select_udt_by_offset
    • ida_hexrays.ui_stroff_applicator_t
    • ida_hexrays.ui_stroff_ops_t
    • ida_idaapi.BADADDR
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_custom_viewer_curline
    • ida_kernwin.msg
    • ida_kernwin.register_action
    • ida_kernwin.warning
    • ida_lines.tag_remove
    • ida_typeinf.PRTYPE_1LINE
    • ida_typeinf.print_tinfo
    • ida_typeinf.remove_pointer

    Add a custom microcode instruction optimization rule

    Installs a custom microcode instruction optimization rule, to transform:

    x | ~x
    

    into

    -1
    

    To see this plugin in action please use be_ornot_be.idb

    Source codeKeywordsLevel
    vds19.pypluginAdvanced

    APIs Used:

    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.m_bnot
    • ida_hexrays.m_mov
    • ida_hexrays.m_or
    • ida_hexrays.minsn_visitor_t
    • ida_hexrays.mop_t
    • ida_hexrays.optinsn_t
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t

    Invert if/else blocks in decompilation

    Registers an action that can be used to invert the if and else blocks of a ida_hexrays.cif_t.

    For example, a statement like

    if ( cond )
    {
      statements1;
    }
    else
    {
      statements2;
    }
    

    will be displayed as

    if ( !cond )
    {
      statements2;
    }
    else
    {
      statements1;
    }
    

    The modifications are persistent: the user can quit & restart IDA, and the changes will be present.

    Source codeKeywordsLevel
    vds3.pyctxmenu Hexrays_Hooks IDP_Hooks pluginAdvanced

    APIs Used:

    • ida_hexrays.CMAT_FINAL
    • ida_hexrays.CV_FAST
    • ida_hexrays.CV_INSNS
    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.ITP_ELSE
    • ida_hexrays.USE_KEYBOARD
    • ida_hexrays.VDI_TAIL
    • ida_hexrays.cexpr_t
    • ida_hexrays.cit_if
    • ida_hexrays.ctree_visitor_t
    • ida_hexrays.get_widget_vdui
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.lnot
    • ida_hexrays.qswap
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_idp.IDP_Hooks
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.register_action
    • ida_netnode.netnode

    Dump C-tree graph

    Registers an action that can be used to show the graph of the ctree. The current item will be highlighted in the graph.

    The command shortcut is Ctrl+Shift+G, and is also added to the context menu.

    To display the graph, we produce a .gdl file, and request that ida displays that using ida_gdl.display_gdl.

    Source codeKeywordsLevel
    vds5.pyctxmenu Hexrays_Hooks pluginAdvanced

    APIs Used:

    • ida_gdl.display_gdl
    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.USE_KEYBOARD
    • ida_hexrays.cit_asm
    • ida_hexrays.cit_goto
    • ida_hexrays.cot_helper
    • ida_hexrays.cot_memptr
    • ida_hexrays.cot_memref
    • ida_hexrays.cot_num
    • ida_hexrays.cot_obj
    • ida_hexrays.cot_ptr
    • ida_hexrays.cot_str
    • ida_hexrays.cot_var
    • ida_hexrays.ctree_parentee_t
    • ida_hexrays.get_ctype_name
    • ida_hexrays.get_widget_vdui
    • ida_hexrays.init_hexrays_plugin
    • ida_idaapi.PLUGIN_HIDE
    • ida_idaapi.PLUGIN_KEEP
    • ida_idaapi.plugin_t
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.register_action
    • ida_kernwin.warning
    • ida_lines.tag_remove
    • ida_pro.str2user

    Show decompiler cross-references

    Show decompiler-style Xref when the Ctrl+X key is pressed in the Decompiler window.

    • supports any global name: functions, strings, integers, …
    • supports structure member.
    Source codeKeywordsLevel
    vds_xrefs.pyctxmenu Hexrays_HooksAdvanced

    APIs Used:

    • ida_funcs.get_func_name
    • ida_hexrays.DECOMP_GXREFS_FORCE
    • ida_hexrays.Hexrays_Hooks
    • ida_hexrays.USE_KEYBOARD
    • ida_hexrays.VDI_EXPR
    • ida_hexrays.VDI_FUNC
    • ida_hexrays.cexpr_t
    • ida_hexrays.cfunc_t
    • ida_hexrays.cinsn_t
    • ida_hexrays.decompile
    • ida_hexrays.get_widget_vdui
    • ida_hexrays.init_hexrays_plugin
    • ida_hexrays.open_pseudocode
    • ida_hexrays.qstring_printer_t
    • ida_idaapi.BADADDR
    • ida_kernwin.AST_DISABLE
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE
    • ida_kernwin.BWN_PSEUDOCODE
    • ida_kernwin.PluginForm
    • ida_kernwin.PluginForm.Show
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.register_action
    • ida_typeinf.PRTYPE_1LINE
    • ida_typeinf.STRMEM_OFFSET
    • ida_typeinf.print_tinfo
    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t
    • idautils.Functions
    • idautils.XrefsTo

    Iterate over the list of threads in the program being debugged, and dump all registers contents

    To use this example:

    • run ida64 on test program simple_appcall_linux64, or ida on test program simple_appcall_linux32, and wait for auto-analysis to finish
    • put a breakpoint somewhere in the code
    • select the ‘linux debugger’ (either local, or remote)
    • start debugging
    • Press Alt+Shift+C at the breakpoint
    Source codeKeywordsLevel
    print_registers.pyBeginner

    APIs Used:

    • ida_dbg.get_reg_vals
    • ida_dbg.get_thread_qty
    • ida_dbg.getn_thread
    • ida_idd.get_dbg
    • ida_kernwin.AST_ENABLE_ALWAYS
    • ida_kernwin.action_desc_t
    • ida_kernwin.register_action

    Dump symbols from a process being debugged

    Queries the debugger (possibly remotely) for the list of symbols that the process being debugged, provides.

    Source codeKeywordsLevel
    show_debug_names.pyBeginner

    APIs Used:

    • ida_dbg.DSTATE_SUSP
    • ida_dbg.get_process_state
    • ida_dbg.is_debugger_on
    • ida_ida.inf_get_max_ea
    • ida_ida.inf_get_min_ea
    • ida_name.get_debug_names

    Print the return addresses from the call stack at a breakpoint, when debugging a Linux binary. (and also print the module and the debug name from debugger)

    To use this example:

    • run ida on test program simple_appcall_linux64, or ida on test program simple_appcall_linux32, and wait for auto-analysis to finish
    • put a breakpoint where you want to see the call stack
    • select the ‘linux debugger’ (either local, or remote)
    • start debugging
    • Press Shift+C at the breakpoint
    Source codeKeywordsLevel
    print_call_stack.pyIntermediate

    APIs Used:

    • ida_dbg.collect_stack_trace
    • ida_dbg.get_current_thread
    • ida_dbg.get_module_info
    • ida_idd.call_stack_t
    • ida_idd.modinfo_t
    • ida_kernwin.AST_ENABLE_ALWAYS
    • ida_kernwin.action_desc_t
    • ida_kernwin.register_action
    • ida_name.GNCN_NOCOLOR
    • ida_name.GNCN_NOLABEL
    • ida_name.GNCN_NOSEG
    • ida_name.GNCN_PREFDBG
    • ida_name.get_nice_colored_name

    Add a custom action to the “registers” widget

    It’s possible to add actions to the context menu of pretty much all widgets in IDA.

    This example shows how to do just that for registers-displaying widgets (e.g., “General registers”)

    Source codeKeywordsLevel
    registers_context_menu.pyctxmenu UI_HooksIntermediate

    APIs Used:

    • ida_dbg.get_dbg_reg_info
    • ida_dbg.get_reg_val
    • ida_idd.register_info_t
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_CPUREGS
    • ida_kernwin.UI_Hooks
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.attach_action_to_popup
    • ida_kernwin.get_widget_type
    • ida_kernwin.register_action
    • ida_ua.dt_byte
    • ida_ua.dt_dword
    • ida_ua.dt_qword
    • ida_ua.dt_word

    Programmatically drive a debugging session

    Start a debugging session, step through the first five instructions. Each instruction is disassembled after execution.

    Source codeKeywordsLevel
    automatic_steps.pyDBG_HooksAdvanced

    APIs Used:

    • ida_dbg.DBG_Hooks
    • ida_dbg.get_reg_val
    • ida_dbg.request_exit_process
    • ida_dbg.request_run_to
    • ida_dbg.request_step_over
    • ida_dbg.run_requests
    • ida_ida.inf_get_start_ip
    • ida_idaapi.BADADDR
    • ida_lines.generate_disasm_line
    • ida_lines.tag_remove

    React to trace notifications

    This script demonstrates using the low-level tracing hook (ida_dbg.DBG_Hooks.dbg_trace). It can be run like so:

     ida.exe -B -Sdbg_trace.py -Ltrace.log file.exe
    
    Source codeKeywordsLevel
    dbg_trace.pyDBG_HooksAdvanced

    APIs Used:

    • GENDSM_FORCE_CODE
    • GENDSM_REMOVE_TAGS
    • NN_call
    • NN_callfi
    • NN_callni
    • generate_disasm_line
    • ida_dbg.DBG_Hooks
    • ida_dbg.ST_OVER_DEBUG_SEG
    • ida_dbg.ST_OVER_LIB_FUNC
    • ida_dbg.enable_step_trace
    • ida_dbg.get_process_state
    • ida_dbg.get_reg_val
    • ida_dbg.get_step_trace_options
    • ida_dbg.load_debugger
    • ida_dbg.refresh_debugger_memory
    • ida_dbg.request_continue_process
    • ida_dbg.request_enable_step_trace
    • ida_dbg.request_set_step_trace_options
    • ida_dbg.run_requests
    • ida_dbg.run_to
    • ida_dbg.set_step_trace_options
    • ida_dbg.wait_for_next_event
    • ida_ida.f_ELF
    • ida_ida.f_MACHO
    • ida_ida.f_PE
    • ida_ida.inf_get_filetype
    • ida_ida.inf_get_max_ea
    • ida_ida.inf_get_min_ea
    • ida_ida.inf_get_start_ip
    • ida_pro.qexit
    • ida_ua.decode_insn
    • ida_ua.insn_t
    • idc.ARGV

    Execute code into the application being debugged (on Linux)

    Using the ida_idd.Appcall utility to execute code in the process being debugged.

    This example will run the test program and stop wherever the cursor currently is, and then perform an appcall to execute the ref4 and ref8 functions.

    To use this example:

    • run ida64 on test program simple_appcall_linux64, or ida on test program simple_appcall_linux32, and wait for auto-analysis to finish
    • select the ‘linux debugger’ (either local, or remote)
    • run this script

    Note: the real body of code is in simple_appcall_common.py.

    Source codeKeywordsLevel
    simple_appcall_linux.pyAdvanced

    APIs Used:

    • ida_dbg.DBG_Hooks
    • ida_dbg.run_to
    • ida_idaapi.BADADDR
    • ida_idd.Appcall
    • ida_idd.Appcall.byref
    • ida_idd.Appcall.int64
    • ida_kernwin.get_screen_ea
    • ida_name.get_name_ea
    • ida_name.set_name
    • ida_typeinf.apply_cdecl

    Execute code into the application being debugged (on Windows)

    Using the ida_idd.Appcall utility to execute code in the process being debugged.

    This example will run the test program and stop wherever the cursor currently is, and then perform an appcall to execute the ref4 and ref8 functions.

    To use this example:

    • run ida on test program simple_appcall_win64.exe, or ida on test program simple_appcall_win32.exe, and wait for auto-analysis to finish
    • select the ‘windows debugger’ (either local, or remote)
    • run this script

    Note: the real body of code is in simple_appcall_common.py.

    Source codeKeywordsLevel
    simple_appcall_win.pyAdvanced

    APIs Used:

    • ida_dbg.DBG_Hooks
    • ida_dbg.run_to
    • ida_ida.inf_is_64bit
    • ida_idaapi.BADADDR
    • ida_idd.Appcall
    • ida_idd.Appcall.byref
    • ida_idd.Appcall.int64
    • ida_kernwin.get_screen_ea
    • ida_name.get_name_ea
    • ida_name.set_name
    • ida_typeinf.apply_cdecl

    Create a structure by parsing its definition

    The goal of this script is to demonstrate some usage of the type API. In this script, we create a structure using the “parsing” method.

    Source codeKeywordsLevel
    create_struct_by_parsing.pyBeginner

    APIs Used:

    • ida_typeinf.tinfo_t

    Delete structure members that fall within an offset range

    The goal of this script is to demonstrate some usage of the type API. In this script, we first create a structure with many members, and then remove all those that fall within a range.

    Source codeKeywordsLevel
    del_struct_members.pyBeginner

    APIs Used:

    • ida_typeinf.STRMEM_OFFSET
    • ida_typeinf.TERR_OK
    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t

    In this example, we will first ask the user to provide the name of an enumeration, and then iterate on it

    Source codeKeywordsLevel
    list_enum_member.pyBeginner

    APIs Used:

    • ida_kernwin.ask_str

    The goal of this script is to demonstrate some usage of the type API. In this script, we retrieve the function frame structure, and iterate on the frame members.

    Source codeKeywordsLevel
    list_frame_info.pyBeginner

    APIs Used:

    • ida_funcs.get_func
    • ida_kernwin.get_screen_ea

    List database functions prototypes

    This script demonstrates how to list a function return type along with its parameters types and name if any. We do this for all the functions found in the database.

    Source codeKeywordsLevel
    list_func_details.pyBeginner

    APIs Used:

    • ida_funcs.get_func
    • idautils.Functions

    List structure members

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • Ask the user for a structure name. It must already be present in the local types.
    • Retrieve the structure type info from the local type
    • Extract its type details (udt)
    • Iterates it members and prints their names.
    Source codeKeywordsLevel
    list_struct_member.pyBeginner

    APIs Used:

    • ida_kernwin.ask_str
    • ida_typeinf.BTF_STRUCT
    • ida_typeinf.get_idati
    • ida_typeinf.tinfo_t
    • ida_typeinf.udt_type_data_t

    List cross-references to a structure

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • Ask the user for a structure name. It must already be present in the local types.
    • Get its tid
    • Create the list of all the reference.
    • Print it
    Source codeKeywordsLevel
    list_struct_xrefs.pyBeginner

    APIs Used:

    • ida_kernwin.choose_struct
    • ida_typeinf.tinfo_t
    • ida_xref.xrefblk_t

    List union members

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • Ask the user for a union name. It must already be present in the local types.
    • Retrieve the union type info from the local type
    • Extract its type details (udt)
    • Iterates it members and prints their names.
    Source codeKeywordsLevel
    list_union_member.pyBeginner

    APIs Used:

    • ida_kernwin.ask_str
    • ida_typeinf.BTF_UNION
    • ida_typeinf.get_idati
    • ida_typeinf.tinfo_t
    • ida_typeinf.udt_type_data_t

    Mark a register “spoiled” by a function

    At least two possibilies are offered in order to indicate that a function spoils registers (excluding the “normal” ones):

    You can either parse & apply a declaration:

      func_tfinfo = ida_typeinf.tinfo_t("int _spoils<rsi> main();")
      ida_typeinf.apply_tinfo(func.start_ea, func_tinfo, ida_typeinf.TINFO_DEFINITE)
    

    or retrieve & modify the tinfo_t object directly.

    This script showcases the latter.

    Source codeKeywordsLevel
    mark_func_spoiled.pyBeginner

    APIs Used:

    • ida_funcs.get_func
    • ida_idp.parse_reg_name
    • ida_idp.reg_info_t
    • ida_kernwin.get_screen_ea
    • ida_nalt.get_tinfo
    • ida_typeinf.FTI_SPOILED
    • ida_typeinf.TINFO_DEFINITE
    • ida_typeinf.apply_tinfo
    • ida_typeinf.func_type_data_t
    • ida_typeinf.tinfo_t

    Apply function prototype to call sites

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • Open the private type libary.
    • Load its declaration in the type library by parsing its declaration and keep the return tuple for future use.
    • Deserialize the type info stored in the returned tuple.
    • Get the address of the function.
    • Get the address of the code reference to the function and apply the type info there.
    Source codeKeywordsLevel
    apply_callee_tinfo.pyIntermediate

    APIs Used:

    • ida_idaapi.BADADDR
    • ida_name.get_name_ea
    • ida_typeinf.PT_REPLACE
    • ida_typeinf.apply_callee_tinfo
    • ida_typeinf.get_idati
    • ida_typeinf.idc_parse_decl
    • ida_typeinf.tinfo_t
    • idautils.CodeRefsTo

    Create an array type

    The goal of this script is to demonstrate some usage of the type API. In this script, we create an array using both versions of create_array tinfo_t method.

    Source codeKeywordsLevel
    create_array.pyIntermediate

    APIs Used:

    • ida_typeinf.BTF_INT
    • ida_typeinf.array_type_data_t
    • ida_typeinf.tinfo_t

    Create a structure with bitfield members

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • Create a bitfield structure. In the present case the bitfield is an int32 made of three ‘members’ spanning it entirely: bit0->bit19: bf1 bit20->bit25: bf2 bit26->bit31: bf3
    • For each member create a repeatable comment.
    Source codeKeywordsLevel
    create_bfstruct.pyIntermediate

    APIs Used:

    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t
    • ida_typeinf.udt_type_data_t

    Create a bitmask enumeration

    The goal of this script is to demonstrate some usage of the type API. In this script, we create a bitmask enumeration member by member.

    Source codeKeywordsLevel
    create_bmenum.pyIntermediate

    APIs Used:

    • ida_typeinf.BTE_BITMASK
    • ida_typeinf.BTE_HEX
    • ida_typeinf.tinfo_t

    Create a type library file

    The goal of this script is to demonstrate some usage of the type API. In this script:

    • We create a new libssh2-64.til file holding some libssh2 64-bit structures.
    • Once the file has been created, it can copied in the IDA install til directory or in the user IDA til directory.
    Source codeKeywordsLevel
    create_libssh2_til.pyIntermediate

    APIs Used:

    • ida_typeinf.HTI_DCL
    • ida_typeinf.HTI_PAKDEF
    • ida_typeinf.compact_til
    • ida_typeinf.free_til
    • ida_typeinf.new_til
    • ida_typeinf.parse_decls
    • ida_typeinf.store_til

    Create a structure programmatically

    The goal of this script is to demonstrate some usage of the type API. In this script, we create a structure by building it member by member.

    Source codeKeywordsLevel
    create_struct_by_member.pyIntermediate

    APIs Used:

    • ida_typeinf.BTF_UINT32
    • ida_typeinf.NTF_TYPE
    • ida_typeinf.del_named_type
    • ida_typeinf.tinfo_errstr
    • ida_typeinf.tinfo_t
    • ida_typeinf.udt_type_data_t

    Create & populate a structure

    Usage of the API to create & populate a structure with members of different types.

    Source codeKeywordsLevel
    create_structure_programmatically.pyIntermediate

    APIs Used:

    • ida_typeinf.BTF_BYTE
    • ida_typeinf.BTF_DOUBLE
    • ida_typeinf.BTF_FLOAT
    • ida_typeinf.BTF_INT
    • ida_typeinf.BTF_INT128
    • ida_typeinf.BTF_INT16
    • ida_typeinf.BTF_INT64
    • ida_typeinf.BTF_TBYTE
    • ida_typeinf.BTF_UINT32
    • ida_typeinf.FRB_NUMO
    • ida_typeinf.NTF_TYPE
    • ida_typeinf.PRTYPE_DEF
    • ida_typeinf.PRTYPE_MULTI
    • ida_typeinf.PRTYPE_TYPE
    • ida_typeinf.del_named_type
    • ida_typeinf.idc_parse_types
    • ida_typeinf.tinfo_errstr
    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t
    • ida_typeinf.udt_type_data_t
    • ida_typeinf.value_repr_t

    Create a union

    The goal of this script is to demonstrate some usage of the type API. In this script, we create a union by building it member after member.

    Source codeKeywordsLevel
    create_union_by_member.pyIntermediate

    APIs Used:

    • ida_typeinf.BTF_CHAR
    • ida_typeinf.BTF_FLOAT
    • ida_typeinf.BTF_INT32
    • ida_typeinf.BTF_UNION
    • ida_typeinf.NTF_TYPE
    • ida_typeinf.PRTYPE_DEF
    • ida_typeinf.PRTYPE_MULTI
    • ida_typeinf.PRTYPE_TYPE
    • ida_typeinf.del_named_type
    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t
    • ida_typeinf.udt_type_data_t

    Create a segment, and define (complex) data in it

    The goal of this script is to demonstrate some usage of the type API. In this script, we show how to create, set type and name of a user shared data region in an ntdll IDB:

    • Load the _KUSER_SHARED_DATA data type from a type info library shipped with IDA, and import it into the IDB’s “local types”
    • Create a data segment with UserSharedData as its name.
    • Apply the type to the start of the newly created segment base address.
    • Set the address name.
    Source codeKeywordsLevel
    create_user_shared_data.pyIntermediate

    APIs Used:

    • ida_name.set_name
    • ida_segment.add_segm_ex
    • ida_segment.saRelPara
    • ida_segment.scPub
    • ida_segment.segment_t
    • ida_segment.setup_selector
    • ida_typeinf.TINFO_DEFINITE
    • ida_typeinf.apply_tinfo
    • ida_typeinf.free_til
    • ida_typeinf.load_til

    Utilities to detect structure gaps & alignment

    The goal of this script is to illustrate ways to detect gaps & alignments in structures, from a structure name & (byte) offset.

    Source codeKeywordsLevel
    gap_size_align_snippet.pyIntermediate

    APIs Used:

    • ida_range.rangeset_t

    Get member by offset, taking into account variable sized structures

    The goal of this script is to provide a way to figure out what structure member, is most likely referenced by an offset.

    This also works for variable sized types.

    Source codeKeywordsLevel
    get_best_fit_member.pyIntermediate

    APIs Used:

    • ida_typeinf.tinfo_t
    • ida_typeinf.udt_type_data_t

    Get information about the “innermost” member of a structure

    Assuming the 2 following types:

        struct b
        {
            int low;
            int high;
        };
    
        struct a
        {
            int foo;
            b b_instance;
            int bar;
        };
    

    looking at an offset of 5 bytes inside an a instance, might be interpreted as pointing somewhere inside member b_instance, of type b. Alternatively, that same offset might be intprereted as pointing somewhere inside low, of type int.

    We refer to that latter interpretation as “innermost”, and this sample shows how the API lets us “drill down” to retrieve that innermost member.

    Source codeKeywordsLevel
    get_innermost_member.pyIntermediate

    APIs Used:

    • ida_typeinf.get_idati
    • ida_typeinf.parse_decls

    Load a type library from a file, and then a type from it

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • ask the user for a specific til to be lodaed
    • if successfully loaded ask the user for a type name to be imported.
    • append the type to the local types.
    Source codeKeywordsLevel
    import_type_from_til.pyIntermediate

    APIs Used:

    • ida_kernwin.ask_str
    • ida_typeinf.load_til

    Inject a member in the middle of a structure

    This sample will retrieve the type info object by its name, find the member at the specified offset, and insert a new member right before it

    Source codeKeywordsLevel
    insert_struct_member.pyIntermediate

    APIs Used:

    • ida_typeinf.TERR_OK
    • ida_typeinf.tinfo_t

    List all xrefs to a function stack variable

    Contrary to (in-memory) data & code xrefs, retrieving stack variables xrefs requires a bit more work than just using ida_xref’s first_to(), next_to() (or higher level utilities such as idautils.XrefsTo)

    Source codeKeywordsLevel
    list_stkvar_xrefs.pyxrefsIntermediate

    APIs Used:

    • ida_bytes.get_flags
    • ida_bytes.is_stkvar
    • ida_frame.calc_stkvar_struc_offset
    • ida_funcs.get_func
    • ida_ida.UA_MAXOP
    • ida_kernwin.AST_DISABLE_FOR_WIDGET
    • ida_kernwin.AST_ENABLE_FOR_WIDGET
    • ida_kernwin.BWN_DISASM
    • ida_kernwin.action_desc_t
    • ida_kernwin.action_handler_t
    • ida_kernwin.get_current_viewer
    • ida_kernwin.get_highlight
    • ida_kernwin.get_screen_ea
    • ida_kernwin.register_action
    • ida_typeinf.tinfo_t
    • ida_ua.decode_insn
    • ida_ua.insn_t

    List cross-references to function stack frame variables

    The goal of this script is to demonstrate some usage of the type API. In this script, we demonstrate how to list each stack variables xref:

    • Get the function object surrounding cursor location.
    • Use this function to retrieve the corresponding frame object.
    • For each frame element:
      • Build the stack variable xref list
      • Print it.
    Source codeKeywordsLevel
    print_stkvar_xrefs.pyIntermediate

    APIs Used:

    • ida_frame.build_stkvar_xrefs
    • ida_frame.get_func_frame
    • ida_frame.xreflist_t
    • ida_funcs.get_func
    • ida_kernwin.get_screen_ea
    • ida_typeinf.tinfo_t
    • ida_typeinf.udt_type_data_t
    • ida_xref.dr_R
    • ida_xref.dr_W

    Assign DOS/PE headers structures to a PE binary

    The goal of this script is to demonstrate some usage of the type API.

    In this script, we:

    • load a PE64 file in binary mode
    • import some types from the mssdk64 til
    • apply these types at the correct ofsset in the DB
    • finally, rebase the program based on the information stored in the ImageBase field of the IMAGE_OPTIONAL_HEADER64.
    Source codeKeywordsLevel
    setpehdr.pyIntermediate

    APIs Used:

    • ida_bytes.create_struct
    • ida_bytes.get_dword
    • ida_bytes.get_qword
    • ida_bytes.get_word
    • ida_hexrays.get_type
    • ida_name.set_name
    • ida_netnode.BADNODE
    • ida_segment.MSF_FIXONCE
    • ida_segment.rebase_program
    • ida_typeinf.ADDTIL_DEFAULT
    • ida_typeinf.BTF_STRUCT
    • ida_typeinf.add_til
    • ida_typeinf.tinfo_t
    • ida_typeinf.udt_type_data_t
    • idc.import_type

    Recursively visit a type and its members

    In this script, we show an example of tinfo_visitor_t to list a user define type members, recursively.

    This scripts skips array & pointer members (by calling tinfo_visitor_t.prune_now())

    Source codeKeywordsLevel
    visit_tinfo.pyIntermediate

    APIs Used:

    • ida_netnode.BADNODE
    • ida_typeinf.ADDTIL_DEFAULT
    • ida_typeinf.TVST_DEF
    • ida_typeinf.add_til
    • ida_typeinf.array_type_data_t
    • ida_typeinf.get_idati
    • ida_typeinf.tinfo_t
    • ida_typeinf.tinfo_visitor_t
    • idc.import_type

    Change the name of an existing stack variable

    The goal of this script is to demonstrate some usage of the type API. In this script, we demonstrate a way to change the name of a stack variable:

    • Get the function object surrounding cursor location.
    • Use this function to retrieve the corresponding frame object.
    • Find the frame member matching the given name.
    • Using its offset in the frame structure object, calculate the actual stack delta.
    • Use the previous result to redefine the stack variable name if it is not a special or argument member.
    Source codeKeywordsLevel
    change_stkvar_name.pyAdvanced

    APIs Used:

    • ida_frame.define_stkvar
    • ida_frame.get_func_frame
    • ida_frame.is_funcarg_off
    • ida_frame.is_special_frame_member
    • ida_frame.soff_to_fpoff
    • ida_funcs.get_func
    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t
    • idc.here

    Change the type & name of a function stack frame variable

    The goal of this script is to demonstrate some usage of the type API.

    In this script, we show a way to change the type and the name of a stack variable. In this case we will take advantage of the fact that RtlImageNtHeader calls RtlImageNtHeaderEx which takes a pointer to PIMAGE_NT_HEADERS as its fourth parameter and, for this, uses a stack variable of its caller.

    • Get the function object for RtlImageNtHeader.
    • Iterate through the function item to localize the load of the stack variable address before the call to RtlImageNtHeaderEx. We keep this information.
    • Localize the call and take advantage of the previoulsy stored instruction to get the stack variable index in the frame.
    • Set the type and rename the stack variable.
    Source codeKeywordsLevel
    change_stkvar_type.pyAdvanced

    APIs Used:

    • ida_allins.NN_call
    • ida_allins.NN_lea
    • ida_frame.get_func_frame
    • ida_funcs.func_item_iterator_t
    • ida_funcs.get_func
    • ida_funcs.get_func_name
    • ida_ida.inf_get_procname
    • ida_ida.inf_is_64bit
    • ida_idaapi.BADADDR
    • ida_name.get_name_ea
    • ida_typeinf.BTF_STRUCT
    • ida_typeinf.TERR_OK
    • ida_typeinf.tinfo_t
    • ida_ua.decode_insn
    • ida_ua.insn_t
    • ida_ua.o_reg
    • idautils.procregs.r9.reg

    Turn instruction operand into a structure offset

    The goal of this script is to demonstrate some usage of the type API. In this script, we:

    • ask the user to choose the structure that will be used for the conversion.
    • build the structure path and call ida_bytes.op_stroff. In case an enum is found a modal chooser is displayed in order to select a member.
    Source codeKeywordsLevel
    operand_to_struct_member.pyAdvanced

    APIs Used:

    • ida_bytes.op_stroff
    • ida_kernwin.Choose
    • ida_kernwin.Choose.CHCOL_HEX
    • ida_kernwin.Choose.CHCOL_PLAIN
    • ida_kernwin.choose_struct
    • ida_kernwin.get_opnum
    • ida_kernwin.get_screen_ea
    • ida_pro.tid_array
    • ida_typeinf.STRMEM_OFFSET
    • ida_typeinf.tinfo_t
    • ida_typeinf.udm_t
    • ida_typeinf.udt_type_data_t
    • ida_ua.decode_insn
    • ida_ua.insn_t

    Code to be run right after IDAPython initialization

    The idapythonrc.py file:

    • %APPDATA%\Hex-Rays\IDA Pro\idapythonrc.py (on Windows)
    • ~/.idapro/idapythonrc.py (on Linux & Mac)

    can contain any IDAPython code that will be run as soon as IDAPython is done successfully initializing.

    Source codeKeywordsLevel
    idapythonrc.pyBeginner

    Add functions to the IDC runtime, from IDAPython

    You can add IDC functions to IDA, whose “body” consists of IDAPython statements!

    We’ll register a ‘pow’ function, available to all IDC code, that when invoked will call back into IDAPython, and execute the provided function body.

    After running this script, try switching to the IDC interpreter (using the button on the lower-left corner of IDA) and executing pow(3, 7)

    Source codeKeywordsLevel
    extend_idc.pyIntermediate

    APIs Used:

    • ida_expr.VT_LONG
    • ida_expr.add_idc_func

    Add 64-bit (.idb->.i64) conversion capabilities to custom plugins

    For more infortmation see SDK/plugins/cvt64_sample example

    Source codeKeywordsLevel
    py_cvt64_sample.pyAdvanced

    APIs Used:

    • ida_idaapi.BADADDR
    • ida_idaapi.BADADDR32
    • ida_netnode.atag
    • ida_netnode.htag
    • ida_netnode.stag

    Add merge functionality to a simple plugin

    This is a primitive plugin which asks user for some info and saves it for some addresses.

    We will add a merge functionality to plugin.

    An IDA plugin may have two kinds of data with permanent storage:

    1. Data common for entire database (e.g. the options). To describe them we will use the idbattr_info_t type.
    2. Data specific to a particular address. To describe them we will use the merge_node_info_t type.

    Also, see SDK/plugins/mex1 example

    Source codeKeywordsLevel
    py_mex1.pyIDP_Hooks pluginAdvanced

    APIs Used:

    • ida_funcs.get_func
    • ida_ida.IDI_ALTVAL
    • ida_ida.IDI_CSTR
    • ida_ida.IDI_SCALAR
    • ida_ida.IDI_SUPVAL
    • ida_ida.idbattr_info_t
    • ida_idaapi.BADADDR
    • ida_idaapi.PLUGIN_MOD
    • ida_idaapi.PLUGIN_MULTI
    • ida_idaapi.plugin_t
    • ida_idaapi.plugmod_t
    • ida_idp.IDP_Hooks
    • ida_kernwin.Form
    • ida_kernwin.Form.ChkGroupControl
    • ida_kernwin.Form.StringInput
    • ida_kernwin.get_screen_ea
    • ida_merge.MERGE_KIND_END
    • ida_merge.MERGE_KIND_NONE
    • ida_merge.NDS_IS_STR
    • ida_merge.NDS_MAP_IDX
    • ida_merge.merge_handler_params_t
    • ida_merge.merge_node_info_t
    • ida_merge.moddata_diff_helper_t
    • ida_mergemod.create_std_modmerge_handlers
    • ida_netnode.BADNODE
    • ida_netnode.SIZEOF_nodeidx_t
    • ida_netnode.atag
    • ida_netnode.netnode
    • ida_netnode.stag

    Implement merging functionality for custom plugins

    IDA Teams uses a chooser to display the merge conflicts. To fill the chooser columns IDA Teams uses the following methods from diff_source_t type:

    • print_diffpos_name()
    • print_diffpos_details()

    and UI hints from merge_handler_params_t type:

    • ui_has_details()
    • ui_complex_details()
    • ui_complex_name()

    In general, chooser columns are filled as following:

          columns.clear()
          NAME = print_diffpos_name()
          if ui_complex_name()
          then
            columns.add(split NAME by ui_split_char())
          else
            columns[0] = NAME
          if not ui_complex_details()
          then
            columns.add(print_diffpos_details())
    

    Also, see SDK/plugins/mex3 example

    Source codeKeywordsLevel
    py_mex3.pyIDP_Hooks pluginAdvanced

    APIs Used:

    • ida_funcs.get_func
    • ida_ida.IDI_ALTVAL
    • ida_ida.IDI_CSTR
    • ida_ida.IDI_SCALAR
    • ida_ida.IDI_SUPVAL
    • ida_ida.idbattr_info_t
    • ida_idaapi.BADADDR
    • ida_idaapi.PLUGIN_MOD
    • ida_idaapi.PLUGIN_MULTI
    • ida_idaapi.plugin_t
    • ida_idaapi.plugmod_t
    • ida_idp.IDP_Hooks
    • ida_kernwin.Form
    • ida_kernwin.Form.ChkGroupControl
    • ida_kernwin.Form.StringInput
    • ida_kernwin.get_screen_ea
    • ida_merge.MERGE_KIND_END
    • ida_merge.MERGE_KIND_NONE
    • ida_merge.MH_UI_COLONNAME
    • ida_merge.MH_UI_COMMANAME
    • ida_merge.MH_UI_NODETAILS
    • ida_merge.NDS_IS_STR
    • ida_merge.NDS_MAP_IDX
    • ida_merge.create_nodeval_merge_handlers
    • ida_merge.get_ea_diffpos_name
    • ida_merge.merge_handler_params_t
    • ida_merge.merge_node_helper_t
    • ida_merge.merge_node_info_t
    • ida_merge.moddata_diff_helper_t
    • ida_mergemod.create_std_modmerge_handlers
    • ida_nalt.node2ea
    • ida_netnode.BADNODE
    • ida_netnode.SIZEOF_nodeidx_t
    • ida_netnode.atag
    • ida_netnode.netnode
    • ida_netnode.stag

    Intro

    The IDAPython API enables you to extend IDA’s core functionality and create custom plugins. Whether running as standalone scripts in the output window or leveraging advanced UI features, these plugins can significantly enhance your workflow.

    Compared to C++ plugins, IDAPython plugins are faster and easier to develop—no need for lengthy build or compilation steps—while maintaining almost the same capabilities.

    This tutorial outlines how to write plugins using the updated plugin framework and best practices to streamline your development process.

    Before you start

    1. Check our IDAPython reference docs for an up-to-date list of all modules, classes, functions, and so on. You can get the latest version of IDAPython SDK from our GitHub repository.

    2. Get familiar with the ida_idaapi.plugin_t class, a basic and required class that provides the necessary structure for your plugin. It mirrors the C++ SDK plugin_t class.

    3. Ensure compatibility with the latest IDA version by reviewing our IDAPython Porting Guide for recent updates.

    Get a sample plugin

    In this tutorial, we’ll use a simple sample plugin designed to work with the new plugin framework, that simplifies plugin development. The plugin performs a straightforward task: once invoked by the user after loading a database, it lists all functions and their addresses for the current IDA database before exiting.

    You can download “My First Plugin” from here: {% file src=“assets/my-first-IDAPython-plugin.zip” %}

    Writing a plugin in IDAPython—basic steps

    Create a single .py file to start

    To begin, your plugin should consist of a single Python file that serves as the entry point. This file should define the main logic and include necessary imports and primary functions that will be executed when the plugin runs.

    Define base classes

    It’s recommended to create a class that inherits from plugin_t with specific flags and a class inheriting from plugmod_t that performs the core functionality.

    Define a class that inherits from ida_idaapi.plugin_t

    Include a class that inherits from plugin_t. This base class will outline the core functionality and lifecycle of your plugin.

    Example of plugin_t class implementation:

    class MyPlugin(ida_idaapi.plugin_t):
        flags = ida_idaapi.PLUGIN_UNL | ida_idaapi.PLUGIN_MULTI
        comment = "This is my first simple IDA Pro plugin"
        help = "This plugin lists all functions in the current database"
        wanted_name = "My First Plugin"
        wanted_hotkey = "Shift-P"
    
        def init(self):
            print(">>>MyPlugin: Init called.")
            return MyPlugmod()
    

    Define a subclass that inherits from ida_idaapi.plugmod_t

    To implement the main functionality of your plugin within the new framework, it is recommended to define a subclass of plugmod_t, that performs the main task of the plugin.

    Example of plugmod_t class implementation:

    class MyPlugmod(ida_idaapi.plugmod_t):
        def __del__(self):
            print(">>> MyPlugmod: destructor called.")
        
        def run(self, arg):
            print(">>> MyPlugmod.run() is invoked with argument value: {arg}.")
            for func_ea in idautils.Functions():
                func_name = ida_funcs.get_func_name(func_ea)
                print(f">>>MyPlugmod: Function{func_name} at address {func_ea:x}")
    

    Overview of MyPlugin class attributes

    flags attribute

    The flags attribute defines the behavior and plugin properties, and what is crucial, describe its lifecycle: how and when it is loaded into IDA.

    Your plugin may have no flags (flags = 0). It is usually a good strategy for basic plugins that perform a specific task once and then are no longer needed. Assigning 0 to flags apply a default behavior to your plugin:

    • it can be loaded and reloaded at any time;
    • it is triggered by the user and does not run constantly in the background;
    • it does not modify the database.

    Common flags for plugins:

    • PLUGIN_MULTI: Recommended for all plugins; this flag enables the plugin to run simultaneously across multiple opened IDBs within the same IDA instance.
    • PLUGIN_FIX: The plugin loads when IDA launches and stays loaded until IDA exits.
    • PLUGIN_DRAW: The plugin needs to be invoked for every screen refresh.
    • PLUGIN_MOD: The plugin modifies the IDA database.
    • PLUGIN_PROC: The plugin is a processor module extension.
    • PLUGIN_DBG: The plugin will be loaded only when a debugger is active (for debugger-related plugins)
    • PLUGIN_UNL: The plugin will be unloaded immediately after calling the run method.

    In our example, we used PLUGIN_UNL flag, as after performing a specific task—listing functions in the current database—is no longer needed.

    For a full list of available flags, refer to the ida_idaapi module.

    comment attribute The comment attribute allows you to provide a brief description of your plugin.

    wanted_name attribute The wanted_name attribute specifies the preferred short name of the plugin, as it apperas under Edit -> Plugins submenu.

    wanted_hotkey attribute The wanted_hotkey attribute specifies a preferred shortcut to run the plugin.

    {% hint style=“info” %} The preferred name and hotkey may be overridden by changing the settings in the plugins.cfg file. {% endhint %}

    Specify your plugin lifecycle

    Below we scrutinize the key components for defining your plugin lifecycle.

    Define a PLUGIN_ENTRY function Declare a function called PLUGIN_ENTRY that returns a plugin_t instance (or an object containing all attributes of a plugin_t object).

    Initialization

    The init() method is called when the plugin is loaded into IDA and is responsible for initializing your plugin.

    The init() method returns an pointer to a plugmod_t object and indicate that this object run method is going to be used.

    {% hint style=“info” %} In the new plugin framework, run/term functions of plugin_t are not used. Virtual functions of plugmod_t are used instead. {% endhint %}

    In our example, when MyPlugin.init() is called it initalizes the plugin and returns a new instance of MyPlugmod.

        def init(self):
            print(">>>MyPlugin: Init called.")
            return MyPlugmod()
    

    Activation

    The run method is executed when the user triggers your plugin activation, whether via hotkey or Edit -> Plugins submenu.

    {% hint style=“info” %} An alternative way of activation your plugin is via IDA events and registering a callback functions. {% endhint %}

    In our example, when the run() method of MyPlugmod is called, it prints function names and addresses in Output window.

        def run(self, arg):
            print(">>> MyPlugmod.run() is invoked with argument value: {arg}.")
            for func_ea in idautils.Functions():
                func_name = ida_funcs.get_func_name(func_ea)
                print(f">>>MyPlugmod: Function{func_name} at address {func_ea:x}")
    

    Unloading

    The __del__() is called automatically when the plugin is going to be unloaded (destroyed). The conditions that define the circumstances under which the plugin should be unloaded depend on the flags setting.

    Example of plugin lifecycle implementation:

    class MyPlugmod(ida_idaapi.plugmod_t):
        def __del__(self):
            print(">>> MyPlugmod: destructor called.")
        
        def run(self, arg):
            print(">>> MyPlugmod.run() is invoked with argument value: {arg}.")
            for func_ea in idautils.Functions():
                func_name = ida_funcs.get_func_name(func_ea)
                print(f">>>MyPlugmod: Function{func_name} at address {func_ea:x}")
    
    
    class MyPlugin(ida_idaapi.plugin_t):
        flags = ida_idaapi.PLUGIN_UNL | ida_idaapi.PLUGIN_MULTI
        comment = "This is my first simple IDA Pro plugin"
        help = "This plugin lists all functions in the current database"
        wanted_name = "My First Plugin"
        wanted_hotkey = "Shift-P"
    
        def init(self):
            print(">>>MyPlugin: Init called.")
            return MyPlugmod()
    
    
    def PLUGIN_ENTRY():
        return MyPlugin()
    

    In our example:

    • PLUGIN_ENTRY() returns an instance of the MyPlugin class.
    • MyPlugin.init() is called to initialize the plugin and returns an instance of MyPlugmod. MyPlugmod.run() is called when the plugin is activated by the user via the hotkey or the Plugins menu. Then, the run() method of MyPlugmod is called, which prints function names and addresses in the current IDA database.
    • MyPlugmod.__del__() is called automatically when the plugin is destroyed (unloaded), and it prints a termination message. As we defined in flags, our exemplary plugin unloads directly after performing its task.

    Include an ida-plugin.json file

    To ensure your plugin is well-organized and can be easily included in the Hex-Rays plugins repository, add the ida-plugin.json file with essential metadata to your plugin directory.

    Install and execute your plugin

    1. Copy the plugin directory (in our example, the folder containing my-first-plugin.py and ida-plugin.json files) or single script to plugins directory in your IDA installation folder. Once it’s done, you may need to restart your IDA to see your plugin name under Edit -> Plugins submenu.
    2. Run the plugin by pressing the specified hotkey or execute it from Edit -> Plugins -> <your_plugin>.

    Porting Guide from IDA 8.x to 9.0

    IDA 9.0 IDAPython changes and porting guide

    {% hint style=“info” %} How to use this Porting Guide? This guide provides a comprehensive list of all changes in IDAPython API between IDA 8.4 and 9.0. Here’s how you can make the most of it:

    Introduction

    This guide provides information about what has been changed in the IDAPython API between IDA 8.4 and 9.0.

    The largest change is due to the removal of two modules:

    • ida_struct
    • ida_enum

    For years now, those 2 modules have been superseded by the ida_typeinf module, which offers similar functionality.

    In case you are not familiar with ida_typeinf’s main concepts, we recommend having a look at them first.

    ida_struct

    1. ida_struct structures were accessed mostly through their index (or ID), while ida_typeinf adopts another approach using type names (or ordinals). Consequently, the notion of “structure index” bears less importance, and doesn’t have a direct alternative.
    2. many ida_struct.get_struc_* operations were accepting a tid_t. While the notion of tid_t is still present in IDA 9.0, it is not part of identifying a type anymore (a type is now identified either by its name, or its ordinal). The notion of tid_t is mostly used to “bind” types to data & functions in the IDB. For example, calling ida_nalt.get_strid(address) will return you such a tid_t. From a tid_t, you can load the corresponding tinfo_t object by using tinfo_t(tid=id).

    Removed functions:

    The table below provides alternatives to the functions that have been removed in IDA 9.0.

    8.49.0
    add_structinfo_t.create_udt
    add_struc_membertinfo_t.add_udm
    del_strucdel_numbered_type, del_named_type
    del_struc_membertinfo_t.del_udm
    del_struc_memberssee example
    expand_structinfo_t.expand_udt
    get_best_fit_memberudt_type_data_t.get_best_fit_member
    get_first_struc_idxtil_t.numbered_types (see notes)
    get_innermost_membertinfo_t.get_innermost_udm
    get_last_struc_idxsee notes
    get_max_offsettinfo_t.get_size (structures), or tinfo_t.get_udt_nmembers (unions)
    get_membertinfo_t.get_udm / tinfo_t.get_udm_by_offset
    get_member_by_fullnameget_udm_by_fullname
    get_member_by_idtinfo_t.get_udm_by_tid
    get_member_by_nametinfo_t.get_udm
    get_member_cmttinfo_t.get_udm + udm_t.cmt
    get_member_fullnameget_tif_name
    get_member_idtinfo_t(tid=...) + tinfo_t.get_udm_tid
    get_member_nametinfo_t(tid=...) + tinfo_t.get_udm + udm_t.name
    get_member_sizetinfo_t(tid=...) + tinfo_t.get_udm + udm_t.size
    get_member_strucget_udm_by_fullname
    get_member_tinfoudm_t.type
    get_next_member_idxsee notes
    get_next_struc_idxsee notes
    get_or_guess_member_tinfo
    get_prev_member_idxsee notes
    get_prev_struc_idxsee notes
    get_sptrsee example
    get_structinfo_t(tid=...)
    get_struc_by_idxsee notes
    get_struc_cmttinfo_t.get_type_cmt
    get_struc_first_offset
    get_struc_idget_named_type_tid
    get_struc_idxsee notes
    get_struc_last_offsettinfo_t.get_udt_details + udm_t.offset
    get_struc_nameget_tid_name
    get_struc_next_offset
    get_struc_prev_offset
    get_struc_qtysee example
    get_struc_sizetinfo_t(tid=...) + tinfo_t.get_size
    is_anonymous_member_nameida_frame.is_anonymous_member_name
    is_dummy_member_nameida_frame.is_dummy_member_name
    is_member_ididc.is_member_id
    is_special_membersee example
    is_uniontinfo_t(tid=...) + tinfo_t.is_union
    is_varmemberudm_t.is_varmember
    is_varstrtinfo_t(tid=...) + tinfo_t.is_varstruct
    retrieve_member_info
    save_structinfo_t.save_type / tinfo_t.set_named_type / tinfo_t.set_numbered_type
    set_member_cmttinfo_t(tid=...) + tinfo_t.set_udm_cmt
    set_member_nametinfo_t(tid=...) + tinfo_t.rename_udm
    set_member_tinfo
    set_member_typetinfo_t(tid=...) + tinfo_t.set_udm_type
    set_struc_align
    set_struc_cmttinfo_t(tid=...) + tinfo_t.set_type_cmt
    set_struc_hidden
    set_struc_idx
    set_struc_listedset_type_choosable
    set_struc_nametinfo_t(tid=...) + tinfo_t.rename_type
    stroff_as_sizeida_typeinf.stroff_as_size
    struct_field_visitor_tida_typeinf.tinfo_visitor_t
    unsync_and_delete_struc
    visit_stroff_fields
    visit_stroff_udmsida_typeinf.visit_stroff_udms

    Removed methods and members

    member_t

    • by_til see ida_typeinf.udm_t.is_by_til
    • eoff
    • flag
    • get_size use ida_typeinf.udm_t.size // 8 instead.
    • get_soff see soff below.
    • has_ti
    • has_union
    • id
    • is_baseclass see ida_typeinf.udm_t.is_baseclass
    • is_destructor see ida_typeinf.udm_t.can_be_dtor
    • is_dupname
    • props
    • soff use ida_typeinf.udm_t.offset // 8 instead.
    • this
    • thisown
    • unimem

    struct_t

    • age
    • from_til
    • get_alignment
    • get_last_member
    • get_member
    • has_union see ida_typeinf.tinfo_t.has_union
    • id see ida_typeinf.tinfo_t.get_tid
    • is_choosable
    • is_copyof
    • is_frame see ida_typeinf.tinfo_t.is_frame
    • is_ghost
    • is_hidden
    • is_mappedto
    • is_synced
    • is_union see ida_typeinf.tinfo_t.is_union
    • is_varstr see ida_typeinf.tinfo_t.is_varstruct
    • like_union
    • members
    • memqty see ida_typeinf.tinfo_t.get_udt_nmembers
    • ordinal see ida_typeinf.tinfo_t.get_ordinal
    • props
    • set_alignment
    • thisown

    struct_field_visitor_t

    • visit_field

    udm_visitor_t

    • visit_udm

    ida_enum

    Removed functions

    The functions below 8.4 are removed those under 9.0 are alternatives.

    The idc alternatives are based on:

    • ida_typeinf module
    • ida_typeinf.tinfo_t, the type info class
    • ida_typeinf.enum_type_data_t, the enumeration type class
    • ida_typeinf.edm_t, the enumeration member class
    8.49.0
    add_enumidc.add_enum
    add_enum_memberidc.add_enum_member
    del_enumidc.del_enum
    del_enum_memberidc.del_enum_member
    for_all_enum_members
    get_bmask_cmtidc.get_bmask_cmt
    get_bmask_nameidc.get_bmask_name
    get_enumidc.get_enum
    get_enum_cmtidc.get_enum_cmt
    get_enum_flagidc.get_enum_flag
    get_enum_idx
    get_enum_memberidc.get_enum_member
    get_enum_member_bmaskidc.get_enum_member_bmask
    get_enum_member_by_nameidc.get_enum_member_by_name
    get_enum_member_cmtidc.get_enum_member_cmt
    get_enum_member_enumidc.get_enum_member_enum
    get_enum_member_nameidc.get_enum_member_name
    get_enum_member_serial
    get_enum_member_valueidc.get_enum_member_value
    get_enum_nameidc.get_enum_name
    get_enum_name2
    get_enum_qty
    get_enum_sizeidc.get_enum_size
    get_enum_type_ordinal
    get_enum_widthidc.get_enum_width
    get_first_bmaskidc.get_first_bmask
    get_first_enum_memberidc.get_first_enum_member
    get_first_serial_enum_member
    get_last_bmaskidc.get_last_bmask
    get_last_enum_memberidc.get_last_enum_member
    get_last_serial_enum_member
    get_next_bmaskidc.get_next_bmask
    get_next_enum_memberidc.get_next_enum_member
    get_next_serial_enum_member
    get_prev_bmaskidc.get_prev_bmask
    get_prev_enum_memberidc.get_prev_enum_member
    get_prev_serial_enum_member
    getn_enum
    is_bfidc.is_bf
    is_enum_fromtil
    is_enum_hidden
    is_ghost_enum
    is_one_bit_mask
    set_bmask_cmtidc.set_bmask_cmt
    set_bmask_nameidc.set_bmask_name
    set_enum_bfidc.set_enum_bf
    set_enum_cmtidc.set_enum_cmt
    set_enum_flagidc.set_enum_flag
    set_enum_fromtil
    set_enum_ghost
    set_enum_hidden
    set_enum_idx
    set_enum_member_cmtidc.set_enum_member_cmt
    set_enum_member_nameidc.set_enum_member_name
    set_enum_nameidc.set_enum_name
    set_enum_type_ordinal
    set_enum_widthidc.set_enum_width

    enum_member_visitor_t

    • visit_enum_member

    ida_typeinf

    Removed functions

    • callregs_t_regcount
    • get_ordinal_from_idb_type
    • is_autosync
    • get_udm_tid: use tinfo_t.get_udm_tid as an alternative.
    • get_tinfo_tid: use tinfo_t.get_tid as an alternative.
    • tinfo_t_get_stock
    • get_ordinal_qty: use ida_typeinf.get_ordinal_count or ida_typeinf.get_ordinal_limit as alternatives.
    • import_type: use idc.import_type as an alternative.

    Added functions

    • detach_tinfo_t(_this: "tinfo_t") -> "bool"
    • get_tinfo_by_edm_name(tif: "tinfo_t", til: "til_t", mname: "char const *") -> "ssize_t"
    • stroff_as_size(plen: "int", tif: "tinfo_t", value: "asize_t") -> "bool"
    • visit_stroff_udms(sfv: "udm_visitor_t", path: "tid_t const *", disp: "adiff_t *", appzero: "bool") -> "adiff_t *"
    • is_one_bit_mask(mask: "uval_t") -> "bool"
    • get_idainfo_by_udm(flags: "flags64_t *", ti: "opinfo_t", set_lzero: "bool *", ap: "array_parameters_t", udm: "udm_t") -> "bool"

    Added class

    udm_visitor_t

    • visit_udm

    Removed methods

    enum_type_data_t

    • get_constant_group

    Added methods

    callregs_t

    • set_registers(self, kind: "callregs_t::reg_kind_t", first_reg: "int", last_reg: "int") -> "void"

    enum_type_data_t

    • all_constants(self)
    • all_groups(self, skip_trivial=False)
    • get_constant_group(self, *args) -> "PyObject *"
    • get_max_serial(self, value: "uint64") -> "uchar"
    • get_serial(self, index: "size_t") -> "uchar"

    func_type_data_t.

    • find_argument(self, *args) -> "ssize_t"

    til_t

    • find_base(self, n: "char const *") -> "til_t *"
    • get_type_names(self) -> "const char *"

    tinfo_t

    • detach(self) -> "bool"
    • is_punknown(self) -> "bool"
    • get_enum_nmembers(self) -> "size_t"
    • is_empty_enum(self) -> "bool"
    • get_enum_width(self) -> "int"
    • calc_enum_mask(self) -> "uint64"
    • get_edm_tid(self, idx: "size_t") -> "tid_t"
    • is_udm_by_til(self, idx: "size_t") -> "bool"
    • set_udm_by_til(self, idx: "size_t", on: "bool"=True, etf_flags: "uint"=0) -> "tinfo_code_t"
    • set_fixed_struct(self, on: "bool"=True) -> "tinfo_code_t"
    • set_struct_size(self, new_size: "size_t") -> "tinfo_code_t"
    • is_fixed_struct(self) -> "bool"
    • get_func_frame(self, pfn: "func_t const *") -> "bool"
    • is_frame(self) -> "bool"
    • get_frame_func(self) -> "ea_t"
    • set_enum_radix(self, radix: "int", sign: "bool", etf_flags: "uint"=0) -> "tinfo_code_t"
    • rename_funcarg(self, index: "size_t", name: "char const *", etf_flags: "uint"=0) -> "tinfo_code_t"
    • set_funcarg_type(self, index: "size_t", tif: "tinfo_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • set_func_rettype(self, tif: "tinfo_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • del_funcargs(self, idx1: "size_t", idx2: "size_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • del_funcarg(self, idx: "size_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • add_funcarg(self, farg: "funcarg_t", etf_flags: "uint"=0, idx: "ssize_t"=-1) -> "tinfo_code_t"
    • set_func_cc(self, cc: "cm_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • set_funcarg_loc(self, index: "size_t", argloc: "argloc_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • set_func_retloc(self, argloc: "argloc_t", etf_flags: "uint"=0) -> "tinfo_code_t"
    • get_stkvar(self, insn: "insn_t const &", x: "op_t const", v: "sval_t") -> "ssize_t"

    udm_t

    • is_retaddr(self) -> "bool"
    • is_savregs(self) -> "bool"
    • is_special_member(self) -> "bool"
    • is_by_til(self) -> "bool"
    • set_retaddr(self, on: "bool"=True) -> "void"
    • set_savregs(self, on: "bool"=True) -> "void
    • set_by_til(self, on: "bool"=True) -> "void"

    udtmembervec_t

    • set_fixed(self, on: "bool"=True) -> "void"

    Modified methods:

    tinfo_t

    8.49.0
    find_udm(self, udm: "udmt_t *", strmem_flags: "int") -> "int"find_udm(self, udm: "udmt_t *", strmem_flags: "int") -> "int"
    find_udm(self, name: "char const *", strmem_flags: "int") -> "int"
    get_type_by_edm_name(self, mname: "const char *", til: "til_t"=None) -> "bool"get_edm_by_name(self, mname: "char const *", til: "til_t"=None) -> "ssize_t"

    ida_frame

    8.4 To access the structure of a function frame, use:

    • get_struc() (use func_t::frame as structure ID)
    • get_frame(const func_t *pfn)
    • get_frame(ea_t ea)

    9.0 To access the structure of a function frame, use:

    • tinfo_t::get_func_frame(const func_t *pfn) as the preferred way.
    • get_func_frame(tinfo_t *out, const func_t *pfn)

    Removed functions

    • get_stkvar: see tinfo_t
    • get_frame: see tinfo_t.get-func_frame
    • get_frame_member_by_id
    • get_min_spd_ea
    • delete_unreferenced_stkvars
    • delete_wrong_stkvar_ops

    Added functions

    • get_func_frame(out: "tinfo_t",pfn: "func_t const *") -> "bool"
    • add_frame_member(pfn: "func_t const *", name: "char const *", offset: "uval_t", tif: "tinfo_t", repr: "value_repr_t"=None, etf_flags: "uint"=0) -> "bool"
    • is_anonymous_member_name(name: "char const *") -> "bool"
    • is_dummy_member_name(name: "char const *") -> "bool"
    • is_special_frame_member(tid: "tid_t") -> "bool"
    • set_frame_member_type(pfn: "func_t const *",offset: "uval_t", tif: "tinfo_t", repr: "value_repr_t"=None, etf_flags: "uint"=0) -> "bool"
    • delete_frame_members(pfn: "func_t const *",start_offset: "uval_t", end_offset: "uval_t") -> "bool"
    • calc_frame_offset(pfn: "func_t *", off: "sval_t", insn: "insn_t const *"=None, op: "op_t const *"=None) -> "sval_t"

    Modified functions

    8.49.0
    define_stkvar(pfn: "func_t *", name: "const char *", off: "sval_t", flags: "flags64_t", ti: "const opinfo_t *", nbytes: "asize_t") -> booldefine_stkvar(pfn: "func_t *", name: "char const *", off: "sval_t", tif: "tinfo_t", repr: "value_repr_t"=None) -> "bool"

    ida_bytes

    Removed functions

    • free_chunck
    • get_8bit

    Added functions

    • find_bytes(bs: typing.Union[bytes, bytearray, str], range_start: int, range_size: typing.Optional[int] = None, range_end: typing.Optional[int] = ida_idaapi.BADADDR, mask: typing.Optional[typing.Union[bytes, bytearray]] = None, flags: typing.Optional[int] = BIN_SEARCH_FORWARD | BIN_SEARCH_NOSHOW, radix: typing.Optional[int] = 16, strlit_encoding: typing.Optional[typing.Union[int, str]] = PBSENC_DEF1BPU) -> int
    • find_string(_str: str, range_start: int, range_end: typing.Optional[int] = ida_idaapi.BADADDR, range_size: typing.Optional[int] = None, strlit_encoding: typing.Optional[typing.Union[int, str]] = PBSENC_DEF1BPU, flags: typing.Optional[int] = BIN_SEARCH_FORWARD | BIN_SEARCH_NOSHOW) -> int

    Modified functions

    8.49.0
    op_enum(ea: "ea_t", n: "int", id: "enum_t", serial: "uchar"=0) -> "bool"op_enum(ea: "ea_t", n: "int", id: "tid_t", serial: "uchar"=0) -> "bool"
    get_enum_id(ea: "ea_t", n: "int") -> "tid_t"get_enum_id(ea: "ea_t", n: "int") -> "enum_t"
    parse_binpat_str(out: "compiled_binpat_vec_t", ea: "ea_t", _in: "char const *", radix: "int", strlits_encoding: "int"=0) -> "str"parse_binpat_str(out: "compiled_binpat_vec_t", ea: "ea_t", _in: "char const *", radix: "int", strlits_encoding: "int"=0) -> "bool"
    bin_search3(start_ea: "ea_t", end_ea: "ea_t", data: "compiled_binpat_vec_t", flags: "int) -> ea_tbin_search(start_ea: "ea_t", end_ea: "ea_t", data: "compiled_binpat_vec_t const &", flags: "int") -> (ea_t, size_t)
    bin_search(start_ea: "ea_t", end_ea: "ea_t", image: "uchar const *", mask: "uchar const *", len: "size_t", flags: "int") -> ea_t
    get_octet2(ogen: "octet_generator_t") -> "uchar_t*"get_octet(ogen: "octet_generator_t") -> "uchar_t*"

    idc

    Removed functions

    ida_dirtree

    Removed functions

    • dirtree_cursor_root_cursor
    • dirtree_t_errstr

    ida_diskio

    Removed functions

    • enumerate_files2
    • eclose

    ida_fpro

    Added functions

    • qflcose(fp: "FILE *") -> "int"

    ida_funcs

    Added methods

    func_item_iterator_t

    • set_ea(self, _ea: "ea_t") -> "bool"

    ida_gdl

    Added classes

    edge_t

    edgevec_t

    node_ordering_t

    • clear(self)
    • resize(self, n: "int") -> "void"
    • size(self) -> "size_t"
    • set(self, _node: "int", num: "int") -> "void"
    • clr(self, _node: "int") -> "bool"
    • node(self, _order: "size_t") -> "int"
    • order(self, _node: "int") -> "int"

    ida_graph

    Removed classes

    node_ordering_t

    See ida-gdl node_ordering_t has been made an alias of ida_gdl.node_ordering_t

    edge_t

    See ida-gdl edge_t has been made an alias of ida_gdl.edge_t

    Renamed clases

    8.49.0
    abstract_graph_tdrawable_graph_t
    mutable_graph_tinteractive_graph_t

    abstract_graph_t has been made an alias of drawable_graph_t mutbale_graph_t has been made an alias of interactive_graph_t

    Renamed functions

    8.49.0
    create_mutable_graphcreate_interactive_graph
    delete_mutable_graphdelete_interactive_graph
    grcode_create_mutable_graphgrcode_create_interactive_graph

    create_mutable_graph has been made an alias of create_interactive_graph delete_mutable_graph has been made an alias of delete_interactive_graph grcode_create_mutable_graph has been made an alias of grcode_create_interactive_graph

    ida_hexrays

    Removed functions

    • get_member_type
    • checkout_hexrays_license
    • cinsn_t_insn_is_epilog

    Modified functions

    8.49.0
    save_user_labels2(func_ea: "ea_t", user_labels: "user_labels_t", func: "cfunc_t"=None) -> "void"save_user_labels(func_ea: "ea_t", user_labels: "user_labels_t", func: "cfunc_t"=None) -> "void"
    restore_user_labels2(func_ea: "ea_t", func: "cfunc_t"=None) -> "user_labels_t *"restore_user_labels(func_ea: "ea_t", func: "cfunc_t"=None) -> "user_labels_t *"

    Added functions

    • max_vlr_value(size: "int") -> "uvlr_t"
    • min_vlr_svalue(size: "int") -> "uvlr_t"
    • max_vlr_svalue(size: "int") -> "uvlr_t"
    • is_unsigned_cmpop(cmpop: "cmpop_t") -> "bool"
    • is_signed_cmpop(cmpop: "cmpop_t") -> "bool"
    • is_cmpop_with_eq(cmpop: "cmpop_t") -> "bool"
    • is_cmpop_without_eq(cmpop: "cmpop_t") -> "bool"

    Added classes

    • catchexpr_t
    • ccatch_t
    • ctry_t
    • cthrow_t
    • cblock_pos_t

    Removed methods

    vdui_t

    • set_strmem_type
    • rename_strmem

    Added methods

    cinsn_list_t

    • splice(self, pos: "qlist< cinsn_t >::iterator", other: "cinsn_list_t", first: "qlist< cinsn_t >::iterator", last: "qlist< cinsn_t >::iterator") -> "void"

    Hexrays_Hooks

    • pre_structural(self, ct: "control_graph_t *", cfunc: "cfunc_t", g: "simple_graph_t") -> "int"
    • begin_inlining(self, cdg: "codegen_t", decomp_flags: "int") -> "int"
    • inlining_func(self, cdg: "codegen_t", blk: "int", mbr: "mba_ranges_t") -> "int"
    • inlined_func(self, cdg: "codegen_t", blk: "int", mbr: "mba_ranges_t", i1: "int", i2: "int") -> "int"
    • collect_warnings(self, warnings: "qstrvec_t *", cfunc: "cfunc_t") -> "int"

    lvar_t

    • was_scattered_arg(self) -> "bool"
    • set_scattered_arg(self) -> "void"
    • clr_scattered_arg(self) -> "void"

    lvars_t

    • find_input_reg(self, reg: "int", _size: "int"=1) -> "int"

    simple_graph_t

    • compute_dominators(self, domin: "array_of_node_bitset_t &", post: "bool"=False) -> "void"
    • compute_immediate_dominators(self, domin: "array_of_node_bitset_t const &", idomin: "intvec_t", post: "bool"=False) -> "void"
    • depth_first_preorder(self, pre: "node_ordering_t") -> "int"
    • depth_first_postorder(self, post: "node_ordering_t") -> "int"
    • begin(self) -> "simple_graph_t::iterator"
    • end(self) -> "simple_graph_t::iterator"
    • front(self) -> "int"
    • inc(self, p: "simple_graph_t::iterator &", n: "int"=1) -> "void"
    • goup(self, node: "int") -> "int"

    fnumber_t

    • calc_max_exp(self) -> "int"
    • is_nan(self) -> "bool"

    minsn_t

    • was_unpaired(self) -> "bool"

    mba_t

    • split_block(self, blk: "mblock_t", start_insn: "minsn_t") -> "mblock_t *"
    • inline_func(self, cdg: "codegen_t", blknum: "int", ranges: "mba_ranges_t", decomp_flags: "int"=0, inline_flags: "int"=0) -> "merror_t"
    • locate_stkpnt(self, ea: "ea_t") -> "stkpnt_t const *"

    codegen_t

    • clear(self) -> "void"

    Modified methods

    Hexrays_Hooks

    8.49.0
    flowchart(self, fc: "qflow_chart_t") -> "int"flowchart(self, fc: "qflow_chart_t", mba: "mba_t") -> "int"

    valrng_t

    8.49.0
    cvt_to_cmp(self, strict: "bool") -> "bool"cvt_to_cmp(self) -> "bool"
    max_value(self, size_ : "int") -> "uvlr_t"max_value(self) -> "uvlr_t"
    min_svalue(self, size_: "int") -> "uvlr_t"min_svalue(self) -> "uvlr_t"
    max_svalue(self, size_: "int") -> "uvlr_t"max_svalue(self) -> "uvlr_t"

    stkvar_ref_t

    8.49.0
    get_stkvar(self, p_off=None: "uval_t *") -> "member_t *"get_stkvar(self, udm: "udm_t"=None, p_off: "uval_t *"=None) -> "ssize_t"

    mop_t

    8.49.0
    get_stkvar(self, p_off: "uval_t *") -> "member_t *"get_stkvar(self, udm: "udm_t"=None, p_off: "uval_t *"=None) -> "ssize_t"

    ida_ida

    Added classes

    idbattr_valmap_t

    idbattr_info_t

    • is_node_altval(self) -> "bool"
    • is_node_supval(self) -> "bool"
    • is_node_valobj(self) -> "bool"
    • is_node_blob(self) -> "bool"
    • is_node_var(self) -> "bool"
    • is_struc_field(self) -> "bool"
    • is_cstr(self) -> "bool"
    • is_qstring(self) -> "bool"
    • is_bytearray(self) -> "bool"
    • is_buf_var(self) -> "bool"
    • is_decimal(self) -> "bool"
    • is_hexadecimal(self) -> "bool"
    • is_readonly_var(self) -> "bool"
    • is_incremented(self) -> "bool"
    • is_val_mapped(self) -> "bool"
    • is_hash(self) -> "bool"
    • use_hlpstruc(self) -> "bool"
    • is_bitmap(self) -> "bool"
    • is_onoff(self) -> "bool"
    • is_scalar_var(self) -> "bool"
    • is_bitfield(self) -> "bool"
    • is_boolean(self) -> "bool"
    • has_individual_node(self) -> "bool"
    • str_true(self) -> "char const *"
    • str_false(self) -> "char const *"
    • ridx(self) -> "size_t"
    • hashname(self) -> "char const *"

    inf_structure accessors

    As will be shown in ida_idaapi Removed functions get_inf_structure has been removed. It has been replaced by the following accessors.

    Replacement examples:

    In 8.4In 9.0
    ida_idaapi.get_inf_structure().procnameida_ida.inf_get_procname()
    ida_idaapi.get_inf_structure().max_eaida_ida.inf_get_max_ea()
    ida_idaapi.get_inf_structure().is_32bit()ida_ida.inf_is_32bit_exactly()

    The list of getters and setters is given below.

    inf_structure getters

    • inf_get_version() -> "ushort"
    • inf_get_genflags() -> "ushort"
    • inf_get_lflags() -> "uint32"
    • inf_get_app_bitness() -> "uint"
    • inf_get_database_change_count() -> "uint32"
    • inf_get_filetype() -> "filetype_t"
    • inf_get_ostype() -> "ushort"
    • inf_get_apptype() -> "ushort"
    • inf_get_asmtype() -> "uchar"
    • inf_get_specsegs() -> "uchar"
    • inf_get_af() -> "uint32"
    • inf_get_af2() -> "uint32"
    • inf_get_baseaddr() -> "uval_t"
    • inf_get_start_ss() -> "sel_t"
    • inf_get_start_cs() -> "sel_t"
    • inf_get_start_ip() -> "ea_t"
    • inf_get_start_ea() -> "ea_t"
    • inf_get_start_sp() -> "ea_t"
    • inf_get_main() -> "ea_t"
    • inf_get_min_ea() -> "ea_t"
    • inf_get_max_ea() -> "ea_t"
    • inf_get_omin_ea() -> "ea_t"
    • inf_get_omax_ea() -> "ea_t"
    • inf_get_lowoff() -> "ea_t"
    • inf_get_highoff() -> "ea_t"
    • inf_get_maxref() -> "uval_t"
    • inf_get_netdelta() -> "sval_t"
    • inf_get_xrefnum() -> "uchar"
    • inf_get_type_xrefnum() -> "uchar"
    • inf_get_refcmtnum() -> "uchar"
    • inf_get_xrefflag() -> "uchar"
    • inf_get_max_autoname_len() -> "ushort"
    • inf_get_nametype() -> "char"
    • inf_get_short_demnames() -> "uint32"
    • inf_get_long_demnames() -> "uint32"
    • inf_get_demnames() -> "uchar"
    • inf_get_listnames() -> "uchar"
    • inf_get_indent() -> "uchar"
    • inf_get_cmt_indent() -> "uchar"
    • inf_get_margin() -> "ushort"
    • inf_get_lenxref() -> "ushort"
    • inf_get_outflags() -> "uint32"
    • inf_get_cmtflg() -> "uchar"
    • inf_get_limiter() -> "uchar"
    • inf_get_bin_prefix_size() -> "short"
    • inf_get_prefflag() -> "uchar"
    • inf_get_strlit_flags() -> "uchar"
    • inf_get_strlit_break() -> "uchar"
    • inf_get_strlit_zeroes() -> "char"
    • inf_get_strtype() -> "int32"
    • inf_get_strlit_sernum() -> "uval_t"
    • inf_get_datatypes() -> "uval_t"
    • inf_get_abibits() -> "uint32"
    • inf_get_appcall_options() -> "uint32"
    • inf_get_privrange_start_ea() -> "ea_t"
    • inf_get_privrange_end_ea() -> "ea_t"
    • inf_get_cc_id() -> "comp_t"
    • inf_get_cc_cm() -> "cm_t"
    • inf_get_cc_size_i() -> "uchar"
    • inf_get_cc_size_b() -> "uchar"
    • inf_get_cc_size_e() -> "uchar"
    • inf_get_cc_defalign() -> "uchar"
    • inf_get_cc_size_s() -> "uchar"
    • inf_get_cc_size_l() -> "uchar"
    • inf_get_cc_size_ll() -> "uchar"
    • inf_get_cc_size_ldbl() -> "uchar"
    • inf_get_procname() -> "size_t"
    • inf_get_strlit_pref() -> "size_t"
    • inf_get_cc(out: "compiler_info_t") -> "bool"
    • inf_get_privrange(*args) -> "range_t"
    • inf_get_af_low() -> "ushort"
    • inf_get_af_high() -> "ushort"
    • inf_get_af2_low() -> "ushort"
    • inf_get_pack_mode() -> "int"
    • inf_get_demname_form() -> "uchar"
    • inf_is_auto_enabled() -> "bool"
    • inf_is_graph_view() -> "bool"
    • inf_is_32bit_or_higher() -> "bool"
    • inf_is_32bit_exactly() -> "bool"
    • inf_is_16bit() -> "bool"
    • inf_is_64bit() -> "bool"
    • inf_is_dll() -> "bool"
    • inf_is_flat_off32() -> "bool"
    • inf_is_be() -> "bool"
    • inf_is_wide_high_byte_first() -> "bool"
    • inf_is_snapshot() -> "bool"
    • inf_is_kernel_mode() -> "bool"
    • inf_is_limiter_thin() -> "bool"
    • inf_is_limiter_thick() -> "bool"
    • inf_is_limiter_empty() -> "bool"
    • inf_is_mem_aligned4() -> "bool"
    • inf_is_hard_float() -> "bool"
    • inf_abi_set_by_user() -> "bool"
    • inf_allow_non_matched_ops() -> "bool"
    • inf_allow_sigmulti() -> "bool"
    • inf_append_sigcmt() -> "bool"
    • inf_big_arg_align(*args) -> "bool"
    • inf_check_manual_ops() -> "bool"
    • inf_check_unicode_strlits() -> "bool"
    • inf_coagulate_code() -> "bool"
    • inf_coagulate_data() -> "bool"
    • inf_compress_idb() -> "bool"
    • inf_create_all_xrefs() -> "bool"
    • inf_create_func_from_call() -> "bool"
    • inf_create_func_from_ptr() -> "bool"
    • inf_create_func_tails() -> "bool"
    • inf_create_jump_tables() -> "bool"
    • inf_create_off_on_dref() -> "bool"
    • inf_create_off_using_fixup() -> "bool"
    • inf_create_strlit_on_xref() -> "bool"
    • inf_data_offset() -> "bool"
    • inf_dbg_no_store_path() -> "bool"
    • inf_decode_fpp() -> "bool"
    • inf_del_no_xref_insns() -> "bool"
    • inf_final_pass() -> "bool"
    • inf_full_sp_ana() -> "bool"
    • inf_gen_assume() -> "bool"
    • inf_gen_lzero() -> "bool"
    • inf_gen_null() -> "bool"
    • inf_gen_org() -> "bool"
    • inf_huge_arg_align(cc: cm_t) -> "bool"
    • inf_like_binary() -> "bool":
    • inf_line_pref_with_seg() -> "bool"
    • inf_loading_idc() -> "bool"
    • inf_macros_enabled() -> "bool"
    • inf_map_stkargs() -> "bool"
    • inf_mark_code() -> "bool"
    • inf_merge_strlits() -> "bool"
    • inf_no_store_user_info() -> "bool"
    • inf_noflow_to_data() -> "bool"
    • inf_noret_ana() -> "bool"
    • inf_op_offset() -> "bool"
    • inf_pack_idb() -> "bool"
    • inf_pack_stkargs(*args) -> "bool"
    • inf_prefix_show_funcoff() -> "bool"
    • inf_prefix_show_segaddr() -> "bool"
    • inf_prefix_show_stack() -> "bool"
    • inf_prefix_truncate_opcode_bytes() -> "bool"
    • inf_propagate_regargs() -> "bool"
    • inf_propagate_stkargs() -> "bool"
    • inf_readonly_idb() -> "bool"
    • inf_rename_jumpfunc() -> "bool"
    • inf_rename_nullsub() -> "bool"
    • inf_should_create_stkvars() -> "bool"
    • inf_should_trace_sp() -> "bool"
    • inf_show_all_comments() -> "bool"
    • inf_show_auto() -> "bool"
    • inf_show_hidden_funcs() -> "bool"
    • inf_show_hidden_insns() -> "bool"
    • inf_show_hidden_segms() -> "bool"
    • inf_show_line_pref() -> "bool"
    • inf_show_repeatables() -> "bool"
    • inf_show_src_linnum() -> "bool"
    • inf_show_void() -> "bool"
    • inf_show_xref_fncoff() -> "bool"
    • inf_show_xref_seg() -> "bool"
    • inf_show_xref_tmarks() -> "bool"
    • inf_show_xref_val() -> "bool"
    • inf_stack_ldbl() -> "bool"
    • inf_stack_varargs() -> "bool"
    • inf_strlit_autocmt() -> "bool"
    • inf_strlit_name_bit() -> "bool"
    • inf_strlit_names() -> "bool"
    • inf_strlit_savecase() -> "bool"
    • inf_strlit_serial_names() -> "bool"
    • inf_test_mode() -> "bool"
    • inf_trace_flow() -> "bool"
    • inf_truncate_on_del() -> "bool"
    • inf_unicode_strlits() -> "bool"
    • inf_use_allasm() -> "bool"
    • inf_use_flirt() -> "bool"
    • inf_use_gcc_layout() -> "bool"

    inf_structure setters

    • inf_set_allow_non_matched_ops(_v: "bool"=True) -> "bool"
    • inf_set_graph_view(_v: "bool"=True) -> "bool"
    • inf_set_lflags(_v: "uint32") -> "bool"
    • inf_set_decode_fpp(_v: "bool"=True) -> "bool"
    • inf_set_32bit(_v: "bool"=True) -> "bool"
    • inf_set_64bit(_v: "bool"=True) -> "bool"
    • inf_set_dll(_v: "bool"=True) -> "bool"
    • inf_set_flat_off32(_v: "bool"=True) -> "bool"
    • inf_set_be(_v: "bool"=True) -> "bool"
    • inf_set_wide_high_byte_first(_v: "bool"=True) -> "bool"
    • inf_set_dbg_no_store_path(_v: "bool"=True) -> "bool"
    • inf_set_snapshot(_v: "bool"=True) -> "bool"
    • inf_set_pack_idb(_v: "bool"=True) -> "bool"
    • inf_set_compress_idb(_v: "bool"=True) -> "bool"
    • inf_set_kernel_mode(_v: "bool"=True) -> "bool"
    • inf_set_app_bitness(bitness: "uint") -> "void"
    • inf_set_database_change_count(_v: "uint32") -> "bool"
    • inf_set_filetype(_v: "filetype_t") -> "bool"
    • inf_set_ostype(_v: "ushort") -> "bool"
    • inf_set_apptype(_v: "ushort") -> "bool"
    • inf_set_asmtype(_v: "uchar") -> "bool"
    • inf_set_specsegs(_v: "uchar") -> "bool"
    • inf_set_af(_v: "uint32") -> "bool"
    • inf_set_trace_flow(_v: "bool"=True) -> "bool"
    • inf_set_mark_code(_v: "bool"=True) -> "bool"
    • inf_set_create_jump_tables(_v: "bool"=True) -> "bool"
    • inf_set_noflow_to_data(_v: "bool"=True) -> "bool"
    • inf_set_create_all_xrefs(_v: "bool"=True) -> "bool"
    • inf_set_del_no_xref_insns(_v: "bool"=True) -> "bool"
    • inf_set_create_func_from_ptr(_v: "bool"=True) -> "bool"
    • inf_set_create_func_from_call(_v: "bool"=True) -> "bool"
    • inf_set_create_func_tails(_v: "bool"=True) -> "bool"
    • inf_set_should_create_stkvars(_v: "bool"=True) -> "bool"
    • inf_set_propagate_stkargs(_v: "bool"=True) -> "bool"
    • inf_set_propagate_regargs(_v: "bool"=True) -> "bool"
    • inf_set_should_trace_sp(_v: "bool"=True) -> "bool"
    • inf_set_full_sp_ana(_v: "bool"=True) -> "bool"
    • inf_set_noret_ana(_v: "bool"=True) -> "bool"
    • inf_set_guess_func_type(_v: "bool"=True) -> "bool"
    • inf_set_truncate_on_del(_v: "bool"=True) -> "bool"
    • inf_set_create_strlit_on_xref(_v: "bool"=True) -> "bool"
    • inf_set_check_unicode_strlits(_v: "bool"=True) -> "bool"
    • inf_set_create_off_using_fixup(_v: "bool"=True) -> "bool"
    • inf_set_create_off_on_dref(_v: "bool"=True) -> "bool"
    • inf_set_op_offset(_v: "bool"=True) -> "bool"
    • inf_set_data_offset(_v: "bool"=True) -> "bool"
    • inf_set_use_flirt(_v: "bool"=True) -> "bool"
    • inf_set_append_sigcmt(_v: "bool"=True) -> "bool"
    • inf_set_allow_sigmulti(_v: "bool"=True) -> "bool"
    • inf_set_hide_libfuncs(_v: "bool"=True) -> "bool"
    • inf_set_rename_jumpfunc(_v: "bool"=True) -> "bool"
    • inf_set_rename_nullsub(_v: "bool"=True) -> "bool"
    • inf_set_coagulate_data(_v: "bool"=True) -> "bool"
    • inf_set_coagulate_code(_v: "bool"=True) -> "bool"
    • inf_set_final_pass(_v: "bool"=True) -> "bool"
    • inf_set_af2(_v: "uint32") -> "bool"
    • inf_set_handle_eh(_v: "bool"=True) -> "bool"
    • inf_set_handle_rtti(_v: "bool"=True) -> "bool"
    • inf_set_macros_enabled(_v: "bool"=True) -> "bool"
    • inf_set_merge_strlits(_v: "bool"=True) -> "bool"
    • inf_set_baseaddr(_v: "uval_t") -> "bool"
    • inf_set_start_ss(_v: "sel_t") -> "bool"
    • inf_set_start_cs(_v: "sel_t") -> "bool"
    • inf_set_start_ip(_v: "ea_t") -> "bool"
    • inf_set_start_ea(_v: "ea_t") -> "bool"
    • inf_set_start_sp(_v: "ea_t") -> "bool"
    • inf_set_main(_v: "ea_t") -> "bool"
    • inf_set_min_ea(_v: "ea_t") -> "bool"
    • inf_set_max_ea(_v: "ea_t") -> "bool"
    • inf_set_omin_ea(_v: "ea_t") -> "bool"
    • inf_set_omax_ea(_v: "ea_t") -> "bool"
    • inf_set_lowoff(_v: "ea_t") -> "bool"
    • inf_set_highoff(_v: "ea_t") -> "bool"
    • inf_set_maxref(_v: "uval_t") -> "bool"
    • inf_set_netdelta(_v: "sval_t") -> "bool"
    • inf_set_xrefnum(_v: "uchar") -> "bool"
    • inf_set_type_xrefnum(_v: "uchar") -> "bool"
    • inf_set_refcmtnum(_v: "uchar") -> "bool"
    • inf_set_xrefflag(_v: "uchar") -> "bool"
    • inf_set_show_xref_seg(_v: "bool"=True) -> "bool"
    • inf_set_show_xref_tmarks(_v: "bool"=True) -> "bool"
    • inf_set_show_xref_fncoff(_v: "bool"=True) -> "bool"
    • inf_set_show_xref_val(_v: "bool"=True) -> "bool"
    • inf_set_max_autoname_len(_v: "ushort") -> "bool"
    • inf_set_nametype(_v: "char") -> "bool"
    • inf_set_short_demnames(_v: "uint32") -> "bool"
    • inf_set_long_demnames(_v: "uint32") -> "bool"
    • inf_set_demnames(_v: "uchar") -> "bool"
    • inf_set_listnames(_v: "uchar") -> "bool"
    • inf_set_indent(_v: "uchar") -> "bool"
    • inf_set_cmt_indent(_v: "uchar") -> "bool"
    • inf_set_margin(_v: "ushort") -> "bool"
    • inf_set_lenxref(_v: "ushort") -> "bool"
    • inf_set_outflags(_v: "uint32") -> "bool"
    • inf_set_show_void(_v: "bool"=True) -> "bool"
    • inf_set_show_auto(_v: "bool"=True) -> "bool"
    • inf_set_gen_null(_v: "bool"=True) -> "bool"
    • inf_set_show_line_pref(_v: "bool"=True) -> "bool"
    • inf_set_line_pref_with_seg(_v: "bool"=True) -> "bool"
    • inf_set_gen_lzero(_v: "bool"=True) -> "bool"
    • inf_set_gen_org(_v: "bool"=True) -> "bool"
    • inf_set_gen_assume(_v: "bool"=True) -> "bool"
    • inf_set_gen_tryblks(_v: "bool"=True) -> "bool"
    • inf_set_cmtflg(_v: "uchar") -> "bool"
    • inf_set_show_repeatables(_v: "bool"=True) -> "bool"
    • inf_set_show_all_comments(_v: "bool"=True) -> "bool"
    • inf_set_hide_comments(_v: "bool"=True) -> "bool"
    • inf_set_show_src_linnum(_v: "bool"=True) -> "bool"
    • inf_set_show_hidden_insns(_v: "bool"=True) -> "bool"
    • inf_set_show_hidden_funcs(_v: "bool"=True) -> "bool"
    • inf_set_show_hidden_segms(_v: "bool"=True) -> "bool"
    • inf_set_limiter(_v: "uchar") -> "bool"
    • inf_set_limiter_thin(_v: "bool"=True) -> "bool"
    • inf_set_limiter_thick(_v: "bool"=True) -> "bool"
    • inf_set_limiter_empty(_v: "bool"=True) -> "bool"
    • inf_set_bin_prefix_size(_v: "short") -> "bool"
    • inf_set_prefflag(_v: "uchar") -> "bool"
    • inf_set_prefix_show_segaddr(_v: "bool"=True) -> "bool"
    • inf_set_prefix_show_funcoff(_v: "bool"=True) -> "bool"
    • inf_set_prefix_show_stack(_v: "bool"=True) -> "bool"
    • inf_set_prefix_truncate_opcode_bytes(_v: "bool"=True) -> "bool"
    • inf_set_strlit_flags(_v: "uchar") -> "bool"
    • inf_set_strlit_names(_v: "bool"=True) -> "bool"
    • inf_set_strlit_name_bit(_v: "bool"=True) -> "bool"
    • inf_set_strlit_serial_names(_v: "bool"=True) -> "bool"
    • inf_set_unicode_strlits(_v: "bool"=True) -> "bool"
    • inf_set_strlit_autocmt(_v: "bool"=True) -> "bool"
    • inf_set_strlit_savecase(_v: "bool"=True) -> "bool"
    • inf_set_strlit_break(_v: "uchar") -> "bool"
    • inf_set_strlit_zeroes(_v: "char") -> "bool"
    • inf_set_strtype(_v: "int32") -> "bool"
    • inf_set_strlit_sernum(_v: "uval_t") -> "bool"
    • inf_set_datatypes(_v: "uval_t") -> "bool"
    • inf_set_abibits(_v: "uint32") -> "bool"
    • inf_set_mem_aligned4(_v: "bool"=True) -> "bool"
    • inf_set_pack_stkargs(_v: "bool"=True) -> "bool"
    • inf_set_big_arg_align(_v: "bool"=True) -> "bool"
    • inf_set_stack_ldbl(_v: "bool"=True) -> "bool"
    • inf_set_stack_varargs(_v: "bool"=True) -> "bool"
    • inf_set_hard_float(_v: "bool"=True) -> "bool"
    • inf_set_abi_set_by_user(_v: "bool"=True) -> "bool"
    • inf_set_use_gcc_layout(_v: "bool"=True) -> "bool"
    • inf_set_map_stkargs(_v: "bool"=True) -> "bool"
    • inf_set_huge_arg_align(_v: "bool"=True) -> "bool"
    • inf_set_appcall_options(_v: "uint32") -> "bool"
    • inf_set_privrange_start_ea(_v: "ea_t") -> "bool"
    • inf_set_privrange_end_ea(_v: "ea_t") -> "bool"
    • inf_set_cc_id(_v: "comp_t") -> "bool"
    • inf_set_cc_cm(_v: "cm_t") -> "bool"
    • inf_set_cc_size_i(_v: "uchar") -> "bool"
    • inf_set_cc_size_b(_v: "uchar") -> "bool"
    • inf_set_cc_size_e(_v: "uchar") -> "bool"
    • inf_set_cc_defalign(_v: "uchar") -> "bool"
    • inf_set_cc_size_s(_v: "uchar") -> "bool"
    • inf_set_cc_size_l(_v: "uchar") -> "bool"
    • inf_set_cc_size_ll(_v: "uchar") -> "bool"
    • inf_set_cc_size_ldbl(_v: "uchar") -> "bool"
    • inf_set_procname(*args) -> "bool"
    • inf_set_strlit_pref(*args) -> "bool"
    • inf_set_cc(_v: "compiler_info_t") -> "bool"
    • inf_set_privrange(_v: "range_t") -> "bool"
    • inf_set_af_low(saf: "ushort") -> "void"
    • inf_set_af_high(saf2: "ushort") -> "void"
    • inf_set_af2_low(saf: "ushort") -> "void"
    • inf_set_pack_mode(pack_mode: "int") -> "int"
    • inf_inc_database_change_count(cnt: "int"=1) -> "void"

    ida_idaapi

    Removed functions

    ida_idd

    Added functions

    • cpu2ieee(ieee_out: "fpvalue_t *", cpu_fpval: "void const *", size: "int") -> "int"
    • ieee2cpu(cpu_fpval: "void *", ieee_out: "fpvalue_t const &", size: "int") -> "int"

    ida_idp

    See also IDB events below.

    Removed methods

    _processor_t

    • has_realcvt

    processor_t

    • get_uFlag

    Modified methods

    _processor_t

    8.49.0
    gen_stkvar_def(ctx: "outctx_t &", mptr: "member_t const *", v: : "sval_t") -> ssize_tgen_stkvar_def(ctx: "outctx_t &", mptr: "udm_t", v: "sval_t", tid: "tid_t") -> "ssize_t"

    IDP_Hooks

    8.49.0
    ev_gen_stkvar_def(self, *args) -> "int"ev_gen_stkvar_def(self, outctx: "outctx_t *", stkvar: "udm_t", v: "sval_t", tid: "tid_t") -> "int"

    Added methods

    IDB_Hooks

    • lt_udm_created(self, udtname: "char const *", udm: "udm_t") -> "void"
    • lt_udm_deleted(self, udtname: "char const *", udm_tid: "tid_t", udm: "udm_t") -> "void"
    • lt_udm_renamed(self, udtname: "char const *", udm: "udm_t", oldname: "char const *") -> "void"
    • lt_udm_changed(self, udtname: "char const *", udm_tid: "tid_t", udmold: "udm_t", udmnew: "udm_t") -> "void"
    • lt_udt_expanded(self, udtname: "char const *", udm_tid: "tid_t", delta: "adiff_t") -> "void"
    • frame_created(self, func_ea: "ea_t") -> "void"
    • frame_udm_created(self, func_ea: "ea_t", udm: "udm_t") -> "void"
    • frame_udm_deleted(self, func_ea: "ea_t", udm_tid: "tid_t", udm: "udm_t") -> "void"
    • frame_udm_renamed(self, func_ea: "ea_t", udm: "udm_t", oldname: "char const *") -> "void"
    • frame_udm_changed(self, func_ea: "ea_t", udm_tid: "tid_t", udmold: "udm_t", udmnew: "udm_t") -> "void"
    • frame_expanded(self, func_ea: "ea_t", udm_tid: "tid_t", delta: "adiff_t") -> "void"

    Removed functions

    All the _processor_t functions have been removed from ida_idp.

    ida_ieee

    Removed methods

    fpvalue_t

    • _get_10bytes
    • _set_10bytes

    ida_kernwin

    Removed functions

    • place_t_as_enumplace_t
    • place_t_as_structplace_t
    • open_enums_window
    • open_structs_window
    • choose_struc
    • choose_enum(title, default_id) -> "enum_t"
    • choose_enum_by_value(title, default_id, value, nbytes) -> "enum_t"

    Modified function

    • place_t_as_idaplace_t has been made an alias of place_t.as_idaplace_t
    • place_t_as_simpleline_place_t has been made an alias of place_t.as_simpleline_place_t
    • place_t_as_tiplace_t has been made an alias of place_t.as_tiplace_t

    Removed classes

    • enumplace_t
    • structplace_t

    Removed methods

    place_t

    • as_enumplace_t
    • as_structplace_t

    twinpos_t

    • place_as_enumplace_t
    • place_as_structplace_t

    tagged_line_sections_t

    • find_in

    Added methods

    tagged_line_sections_t

    • nearest_before(self, range: "tagged_line_section_t", start: "cpidx_t", tag: "color_t"=0) -> "tagged_line_section_t const *"
    • nearest_after(self, range: "tagged_line_section_t", start: "cpidx_t", tag: "color_t"=0) -> "tagged_line_section_t const *"

    chooser_base_t

    • has_widget_lifecycle(self) -> "bool"

    Added functions

    • is_ida_library(path: "char *", pathsize: "size_t", handle: "void **") -> "bool"

    ida_lines

    Removed functions

    • set_user_defined_prefix

    ida_moved

    Modified functions

    • bookmarks_t_mark has been made an alias of bookmarks_t.mark
    • bookmarks_t_get_desc has been made an alias of bookmarks_t.get_desc
    • bookmarks_t_find_index has been made an alias of bookmarks_t.find_index
    • bookmarks_t_size has been made an alias of bookmarks_t.size
    • bookmarks_t_erase has been made an alias of bookmarks_t.erase
    • bookmarks_t_get_dirtree_id has been made an alias of bookmarks_t.get_dirtree_id
    • bookmarks_t_get has been made an alias of bookmarks_t.get

    ida_nalt

    Removed functions

    • validate_idb_names

    ida_netnode

    Modified functions

    • netnode.exist has been made an alias of netnode.exist

    ida_pro

    Removed functions

    • uchar_array_frompointer
    • tid_array_frompointer
    • ea_array_frompointer
    • sel_array_frompointer
    • int_pointer_frompointer
    • sel_pointer_frompointer
    • ea_pointer_frompointer

    See Added classes below

    Added classes

    plugin_options_t

    • erase(self, name: "char const *") -> "bool"

    uchar_pointer

    • assign(self, value: "uchar") -> "void"
    • value(self) -> "uchar"
    • cast(self) -> "uchar *"
    • frompointer(t: "uchar *") -> "uchar_pointer *"

    ushort_pointer

    • assign(self, value: "ushort") -> "void"
    • value(self) -> "ushort"
    • cast(self) -> "ushort *"
    • frompointer(t: "ushort *") -> "ushort_pointer *"

    uint_pointer

    • assign(self, value: "uint") -> "void"
    • value(self) -> "uint"
    • cast(self) -> "uint *"
    • frompointer(t: "uint *") -> "uint_pointer *"

    sint8_pointer

    • assign(self, value: "sint8") -> "void"
    • value(self) -> "sint8"
    • cast(self) -> "sint8 *"
    • frompointer(t: "sint8 *") -> "sint8_pointer *"

    int8_pointer

    • assign(self, value: "int8") -> "void"
    • value(self) -> "int8"
    • cast(self) -> "int8 *"
    • frompointer(t: "int8 *") -> "int8_pointer *"

    uint8_pointer

    • assign(self, value: "uint8") -> "void"
    • value(self) -> "uint8"
    • cast(self) -> "uint8 *"
    • frompointer(t: "uint8 *") -> "uint8_pointer *"

    int16_pointer

    • assign(self, value: "int16") -> "void"
    • value(self) -> "int16"
    • cast(self) -> "int16 *"
    • frompointer(t: "int16 *") -> "int16_pointer *"

    uint16_pointer

    • assign(self, value: "uint16") -> "void"
    • value(self) -> "uint16"
    • cast(self) -> "uint16 *"
    • frompointer(t: "uint16 *") -> "uint16_pointer *"

    int32_pointer

    • assign(self, value: "int32") -> "void"
    • value(self) -> "int32"
    • cast(self) -> "int32 *"
    • frompointer(t: "int32 *") -> "int32_pointer *"

    uint32_pointer

    • assign(self, value: "uint32") -> "void"
    • value(self) -> "uint32"
    • cast(self) -> "uint32 *"
    • frompointer(t: "uint32 *") -> "uint32_pointer *"

    int64_pointer

    • assign(self, value: "int64") -> "void"
    • value(self) -> "int64"
    • cast(self) -> "int64 *"
    • frompointer(t: "int64 *") -> "int64_pointer *"

    uint64_pointer

    • assign(self, value: "uint64") -> "void"
    • value(self) -> "uint64"
    • cast(self) -> "uint64 *"
    • frompointer(t: "uint64 *") -> "uint64_pointer *"

    ssize_pointer

    • assign(self, value: "ssize_t") -> "void"
    • value(self) -> "ssize_t"
    • cast(self) -> "ssize_t *"
    • frompointer(t: "ssize_t *") -> "ssize_pointer *"

    bool_pointer

    • assign(self, value: "bool") -> "void"
    • value(self) -> "bool"
    • cast(self) -> "bool *"
    • frompointer(t: "bool *") -> "bool_pointer *"

    short_pointer

    • assign(self, value: "short") -> "void"
    • value(self) -> "short"
    • cast(self) -> "short *"
    • frompointer(t: "short *") -> "short_pointer *"

    char_pointer

    • assign(self, value: "char") -> "void"
    • value(self) -> "char"
    • cast(self) -> "char *"
    • frompointer(t: "char *") -> "char_pointer *"

    sel_pointer

    • assign(self, value: "sel_t") -> "void"
    • value(self) -> "sel_t"
    • cast(self) -> "sel_t *"
    • frompointer(t: "sel_t *") -> "sel_pointer *"

    asize_pointer

    • assign(self, value: "asize_t") -> "void"
    • value(self) -> "asize_t"
    • cast(self) -> "asize_t *"
    • frompointer(t: "asize_t *") -> "asize_pointer *"

    adiff_pointer

    • assign(self, value: "adiff_t") -> "void"
    • value(self) -> "adiff_t"
    • cast(self) -> "adiff_t *"
    • from_pointer(t: "adiff_t*") -> "adiff_pointer *"

    uval_pointer

    • assign(self, value: "uval_t") -> "void"
    • value(self) -> "uval_t"
    • cast(self) -> "uval_t *"
    • frompointer(t: "uval_t *") -> "uval_pointer *"

    ea32_pointer

    • assign(self, value: "ea32_t") -> "void"
    • value(self) -> "ea32_t"
    • cast(self) -> "ea32_t *"
    • frompointer(t: "ea32_t *") -> "ea32_pointer *"

    ea64_pointer

    • assign(self, value: "ea64_t") -> "void"
    • value(self) -> "ea64_t"
    • cast(self) -> "ea64_t *"
    • frompointer(t: "ea64_t *") -> "ea64_pointer *"

    flags_pointer

    • assign(self, value: "flags_t") -> "void"
    • value(self) -> "flags_t"
    • cast(self) -> "flags_t *"
    • frompointer(t: "flags_t *") -> "flags_pointer *"

    flags64_pointer

    • assign(self, value: "flags64_t") -> "void"
    • value(self) -> "flags64_t"
    • cast(self) -> "flags64_t *"
    • frompointer(t: "flags64_t *") -> "flags64_pointer *"

    tid_pointer

    • assign(self, value: "tid_t") -> "void"
    • value(self) -> "tid_t"
    • cast(self) -> "tid_t *"
    • frompointer(t: "tid_t *") -> "tid_pointer *"

    Added functions

    • get_login_name() -> "qstring *"

    ida_regfinder

    Removed functions

    • reg_value_info_t_make_dead_end
    • reg_value_info_t_make_aborted
    • reg_value_info_t_make_badinsn
    • reg_value_info_t_make_unkinsn
    • reg_value_info_t_make_unkfunc
    • reg_value_info_t_make_unkloop
    • reg_value_info_t_make_unkmult
    • reg_value_info_t_make_num
    • reg_value_info_t_make_initial_sp

    Modified functions

    8.49.0
    invalidate_regfinder_cache(ea: "ea_t") -> "void"invalidate_regfinder_cache(from=BADADDR: "ea_t", to=BADADDR: "ea_t") -> "void"

    Added methods

    reg_value_info_t

    • movt(self, r: "reg_value_info_t", insn: "insn_t const &") -> "void"

    ida_registry

    Removed functions

    • reg_load
    • reg_flush

    Removed functions

    • find_binary

    ida_ua

    Removed Function

    • construct_macro(insn: "insn_t *", enable: "bool", build_macro: "PyObject *") -> bool (See [Modified functions](#modified-functions-4))

    Modified functions

    8.49.0
    construct_macro2(_this: "macro_constructor_t *", insn: "insn_t *", enable: "bool") -> "bool"construct_macro(_this: "macro_constructor_t *", insn: "insn_t *", enable: "bool") -> "bool"

    Added methods

    macro_constructor_t

    • construct_macro(self, insn: "insn_t", enable: "bool") -> "bool"

    idautils

    Modified functions

    8.49.0
    Structs() -> [(idx, sid, name)]Structs() -> [(ordinal, sid, name)]
    StructMembers(sid) -> [(offset, name, size)]StructMembers(sid) -> [(offset_in_bytes, name, size_in_bytes)]

    IDB events

    The following table provide a list of IDB events that have been replaced or, in some cases, removed.

    Since 7In 9.0
    truc_createdlocal_types_changed
    deleting_strucnone
    struc_deletedlocal_types_changed
    changing_struc_alignnone
    struc_align_changedlocal_types_changed
    renaming_strucnone
    struc_renamedlocal_types_changed
    expanding_strucnone
    struc_expandedlt_udt_expanded, frame_expanded, local_types_changed
    struc_member_createdlt_udm_created, frame_udm_created, local_types_changed
    deleting_struc_membernone
    struc_member_deletedlt_udm_deleted, frame_udm_deleted, local_types_changed
    renaming_struc_membernone
    struc_member_renamedlt_udm_renamed, frame_udm_renamed, local_types_changed
    changing_struc_membernone
    struc_member_changedlt_udm_changed, frame_udm_changed, local_types_changed
    changing_struc_cmtnone
    struc_cmt_changedlocal_types_changed
    enum_createdlocal_types_changed
    deleting_enumnone
    enum_deletedlocal_types_changed
    renaming_enumnone
    enum_renamedlocal_types_changed
    changing_enum_bflocal_types_changed
    enum_bf_changedlocal_types_changed
    changing_enum_cmtnone
    enum_cmt_changedlocal_types_changed
    enum_member_createdlocal_types_changed
    deleting_enum_membernone
    enum_member_deletedlocal_types_changed
    enum_width_changedlocal_types_changed
    enum_flag_changedlocal_types_changed
    enum_ordinal_changed`none

    Type information error codes

    Following is the list of error values returned by the type info module. It can also be found in typeinf.hpp in the IDASDK:

    Error nameVal.Meaning
    TERR_OK0ok
    TERR_STABLE1it means no errors occurred but nothing has changed (this code is internal: should never be returned to caller) -*
    TERR_SAVE_ERROR-1failed to save
    TERR_SERIALIZE-2failed to serialize
    TERR_BAD_NAME-3name is not acceptable
    TERR_BAD_ARG-4bad argument
    TERR_BAD_TYPE-5bad type
    TERR_BAD_SIZE-6bad size
    TERR_BAD_INDEX-7bad index
    TERR_BAD_ARRAY-8arrays are forbidden as function arguments
    TERR_BAD_BF-9bitfields are forbidden as function arguments
    TERR_BAD_OFFSET-10bad member offset
    TERR_BAD_UNIVAR-11unions cannot have variable sized members
    TERR_BAD_VARLAST-12variable sized member must be the last member in the structure
    TERR_OVERLAP-13the member overlaps with other members that cannot be deleted
    TERR_BAD_SUBTYPE-14recursive structure nesting is forbidden
    TERR_BAD_VALUE-15value is not acceptable
    TERR_NO_BMASK-16bitmask is not found
    TERR_BAD_BMASK-17Bad enum member mask. The specified mask should not intersect with any existing mask in the enum. Zero masks are prohibited too
    TERR_BAD_MSKVAL-18bad bmask and value combination
    TERR_BAD_REPR-19bad or incompatible field representation
    TERR_GRP_NOEMPTY-20could not delete group mask for not empty group
    TERR_DUPNAME-21duplicate name
    TERR_UNION_BF-22unions cannot have bitfields
    TERR_BAD_TAH-23bad bits in the type attributes (TAH bits)
    TERR_BAD_BASE-24bad base class
    TERR_BAD_GAP-25bad gap
    TERR_NESTED-26recursive structure nesting is forbidden
    TERR_NOT_COMPAT-27the new type is not compatible with the old type
    TERR_BAD_LAYOUT-28failed to calculate the structure/union layout
    TERR_BAD_GROUPS-29bad group sizes for bitmask enum
    TERR_BAD_SERIAL-30enum value has too many serials
    TERR_ALIEN_NAME-31enum member name is used in another enum
    TERR_STOCK-32stock type info cannot be modified
    TERR_ENUM_SIZE-33bad enum size
    TERR_NOT_IMPL-34not implemented
    TERR_TYPE_WORSE-35the new type is worse than the old type
    TERR_BAD_FX_SIZE-36cannot extend struct beyond fixed size

    Alternative examples

    This section gives examples of how to port some ida_struct and ida_enum functions using ida_typeinf.

    del_struct_members

    The following code can be used as an example of how to replace ida_struct.del_struct_members.

    def del_struct_members(sid, offset1, offset2):
        tif = ida_typeinf.tinfo_t()
        if tif.get_type_by_tid(sid) and tif.is_udt():
            udm = ida_typeinf.udm_t()
            udm.offset = offset1 * 8
            idx1 = tif.find_udm(udm, ida_typeinf.STRMEM_OFFSET)
            udm = ida_typeinf.udm_t()
            udm.offset = offset2 * 8
            idx2 = tif.find_udm(udm, ida_typeinf.STRMEM_OFFSET)
            return tif.del_udms(idx1, idx2)
    

    get_member_by_fullname

    The following code can be used as an example of how to replace ida_struct.get_member_by_fullname.

    def get_member_by_fullname(fullname):
        udm = ida_typeinf.udm_t()
        idx = ida_typeinf.get_udm_by_fullname(udm, fullname)
        if  idx == -1:
            return None
        else:
            return udm
    

    get_struc_qty

    The following code can be used as an example of how to replace ida_struct.get_struc_qty.

    def get_struc_qty():
        count = 0
        limit = ida_typeinf.get_ordinal_limit()
        for i in range(1, limit):
            tif = ida_typeinf.tinfo_t()
            if not tif.get_numbered_type(i, ida_typeinf.BTF_STRUCT):
                continue
            else:
                count += 1
        return count
    

    is_special_member

    The following code can be used as an example of how to replace ida_struct.is_special_member.

    def is_special_member(member_id):
        tif = ida_typeing.tinfo_t()
        udm = ida_typeinf.udm_t()
        if tif.get_udm_by_tid(udm, member_id) != -1:
            return udm.is_special_member()
        return False
    

    get_sptr

    The following code can be used as an example of how to replace ida_struct.get_sptr.

    def get_sptr(udm):
        tif = udm.type
        if tif.is_udt() and tif.is_struct():
            return tif
        else:
            return None
    

    How to examples

    List structure members

    Example 1

    def list_enum_members(name)
        tid = idc.get_struc_id(name)
        if not tid == ida_idaapi.BADADDR:
            for (offset, name, size) in idautils.StructMembers(tid):
                print(f'Member {name} at offset {offset} of size {size}')
    

    Example 2

    def list_struct_members2(name):
        til = ida_typeinf.get_idati()
        tif = ida_typeinf.tinfo_t()
        if not tif.get_named_type(til, name, ida_typeinf.BTF_STRUCT, True, False):
            print(f"'{name}' is not a structure")
        elif  tif.is_typedef():
            print(f"'{name}' is not a (non typedefed) structure.")
        else:
            udt = ida_typeinf.udt_type_data_t()
            if tif.get_udt_details(udt):
                idx = 0
                print(f'Listing the {name} structure {udt.size()} field names:')
                for udm in udt:
                    print(f'Field {idx}: {udm.name}')
                    idx += 1
            else:
                print(f"Unable to get udt details for structure '{name}'")
    

    List enum members

    def list_enum_members(name):
        til = ida_typeinf.get_idati()
        tif = ida_typeinf.tinfo_t()
        if not tif.get_named_type(til, name, ida_typeinf.BTF_ENUM, True, False):
            print(f"'{name}' is not an enum")
        elif tif.is_typedef():
            print(f"'{name}' is not a (non typedefed) enum.")
        else:
            edt = ida_typeinf.enum_type_data_t()
            if tif.get_enum_details(edt):
                idx = 0
                bitfield = ''
                if edt.is_bf():
                    bitfield = '(bitfield)'
                print(f"Listing the '{name}' {bitfield} enum {edt.size()} field names:")
                for edm in edt:
                    print(f'Field {idx}: {edm.name} = {edm.value}')
                    idx += 1
            else:
                print(f"Unable to get udt details for enum '{name}'")
    

    List frame information

    func = ida_funcs.get_func(here())
    if func:
        func_name = ida_funcs.get_func_name(func.start_ea)
        frame_tif = ida_typeinf.tinfo_t()
        if ida_frame.get_func_frame(frame_tif, func):
            frame_udt = ida_typeinf.udt_type_data_t()
            if frame_tif.get_udt_details(frame_udt):
                print('List frame information:')
                print('-----------------------')
                print(f'{func_name} @ {func.start_ea:x} framesize {frame_tif.get_size():x}')
                print(f'Local variable size: {func.frsize:x}')
                print(f'Saved registers: {func.frregs:x}')
                print(f'Argument size: {func.argsize:x}')
                print('{')
                idx = 0
                for udm in frame_udt:
                    print(f'\t[{idx}] {udm.name}: soff={udm.offset//8:x} eof={udm.end()//8:x} {udm.type.dstr()}')
                    idx += 1
                print('}')
    else:
        print(f'{here():x} is not inside a function.')
    

    List stack variables xrefs

    func = ida_funcs.get_func(here())
    if func:
        print(f'Function @ {func.start_ea:x}')
    
        frame_tif = ida_typeinf.tinfo_t()
        if ida_frame.get_func_frame(frame_tif, func):
            print('Frame found')
            nmembers = frame_tif.get_udt_nmembers()
            print(f'Frame has {nmembers} members')
    
            if nmembers > 0:
                frame_udt = ida_typeinf.udt_type_data_t()
                if frame_tif.get_udt_details(frame_udt):
    
                    for frame_udm in frame_udt:
                        start_off = frame_udm.begin() // 8
                        end_off = frame_udm.end() // 8
                        xreflist = ida_frame.xreflist_t()
                        ida_frame.build_stkvar_xrefs(xreflist, func, start_off, end_off)
                        size = xreflist.size()
                        print(f'{frame_udm.name} stack variable starts @ {start_off:x}, ends @ {end_off:x}, xref size: {size}')
    
                        for idx in range(size):
                            match xreflist[idx].type:
                                case ida_xref.dr_R:
                                    type = 'READ'
                                case ida_xref.dr_W:
                                    type = 'WRITE'
                                case _:
                                    type = 'UNK'
                            print(f'\t[{idx}]: xref @ {xreflist[idx].ea:x} of type {type}')
                else:
                    print('Unable to get the frame details.')
            else:
                print('No members found.')
    else:
        print('No function under the cursor')
    

    Create a structure with parsing

    struct_str = """struct pcap_hdr_s {
            uint32_t magic_number;   /* magic number */
            uint16_t version_major;  /* major version number */
            uint16_t version_minor;  /* minor version number */
            int32_t  thiszone;       /* GMT to local correction */
            uint32_t sigfigs;        /* accuracy of timestamps */
            uint32_t snaplen;        /* max length of captured packets, in octets */
            uint32_t network;        /* data link type */
    };"""
    tif = ida_typeinf.tinfo_t()
    if tif.get_named_type(None, 'pcap_hdr_s'):
        ida_typeinf.del_named_type(None, 'pcap_hdr_s', ida_typeinf.NTF_TYPE)
    ida_typeinf.idc_parse_types(struct_str, 0)
    if not tif.get_named_type(None, 'pcap_hdr_s'):
        print('Unable to retrieve pcap_hdr_s structure')
    

    Create a structure member by member

    tif = ida_typeinf.tinfo_t()
    if tif.get_named_type(None, 'pcaprec_hdr_s'):
        ida_typeinf.del_named_type(None, 'pcaprec_hdr_s', ida_typeinf.NTF_TYPE)
    field_list = [('ts_sec', ida_typeinf.BTF_UINT32),
                 ('ts_usec', ida_typeinf.BTF_UINT32),
                 ('incl_len', ida_typeinf.BTF_UINT32),
                 ('orig_len', ida_typeinf.BTF_UINT32)]
    udt = ida_typeinf.udt_type_data_t()
    udm = ida_typeinf.udm_t()
    for (name, type) in field_list:
        udm.name = name
        udm.type = ida_typeinf.tinfo_t(type)
        udt.push_back(udm)
    if tif.create_udt(udt):
        tif.set_named_type(None, 'pcaprec_hdr_s')
    
    

    Create a union member by member

    tif = ida_typeinf.tinfo_t()
    if tif.get_named_type(None, 'my_union'):
        ida_typeinf.del_named_type(None, 'my_union', ida_typeinf.NTF_TYPE)
    tif = ida_typeinf.tinfo_t()
    udt = ida_typeinf.udt_type_data_t()
    field_list = [('member1', ida_typeinf.BTF_INT32),
                  ('member2', ida_typeinf.BTF_CHAR),
                  ('member3', ida_typeinf.BTF_FLOAT)]
    udt.is_union = True
    udm = ida_typeinf.udm_t()
    for (name, type) in field_list:
        udm.name = name
        udm.type = ida_typeinf.tinfo_t(type)
        udt.push_back(udm)
    tif.get_named_type(None, 'pcap_hdr_s')
    if tif.create_ptr(tif):
        udm.name = 'header_ptr'
        udm.type = tif
        udt.push_back(udm)
        tif.clear()
        tif.create_udt(udt, ida_typeinf.BTF_UNION)
        tif.set_named_type(None, 'my_union')
    

    Create a bitmask enum

    edt = ida_typeinf.enum_type_data_t()
    edm = ida_typeinf.edm_t()
    for name, value in [('field1', 1), ('field2', 2), ('field3', 4)]:
        edm.name = name
        edm.value = value
        edt.push_back(edm)
    
    tif = ida_typeinf.tinfo_t()
    if tif.create_enum(edt):
        tif.set_enum_is_bitmask(ida_typeinf.tinfo_t.ENUMBM_ON)
        tif.set_named_type(None, 'bmenum')
    

    Create an array

    Example 1

    tif = ida_typeinf.tinfo_t(ida_typeinf.BTF_INT)
    if tif.create_array(tif, 5, 0):
        type = tif._print()
        tif.set_named_type(None, 'my_int_array1')
    

    Example 2

    atd = ida_typeinf.array_type_data_t()
    atd.base = 0
    atd.nelems = 5
    atd.elem_type = ida_typeinf.tinfo_t(ida_typeinf.BTF_INT)
    tif = ida_typeinf.tinfo_t()
    if tif.create_array(atd):
        type = tif._print()
        tif.set_named_type(None, 'my_int_array2')
    

    Log local type events

    class lt_logger_hooks_t(ida_idp.IDB_Hooks):
        def __init__(self):
            ida_idp.IDB_Hooks.__init__(self)
            self.inhibit_log = 0
    
        def _format_value(self, v):
            return str(v)
    
        def _log(self, msg=None):
            if self.inhibit_log <= 0:
                if msg:
                    print(f'>>> lt_logger_hooks_f: {msg}')
                else:
                    stack = inspect.stack()
                    frame, _, _, _, _, _ = stack[1]
                    args, _, _, values = inspect.getargvalues(frame)
                    method_name = inspect.getframeinfo(frame)[2]
                    argstrs = []
                    for arg in args[1:]:
                        argstrs.append("%s=%s" % (arg, self._format_value(values[arg])))
                    print(f'>>> lt_logger_hooks_t.{method_name}: {", ".join(args)}')
            return 0
    
        def lt_udm_created(self, udtname, udm):
            msg = f'UDM {udm.name} has been created in UDT {udtname}'
            return self._log(msg)
    
        def lt_udm_deleted(self, udtname, udm_tid):
            msg = f'UDM tid {udm_tid:x} has been deleted from {udtname}'
            return self._log(msg)
    
        def lt_udm_renamed(self, udtname, udm, oldname):
            msg = f'UDM {oldname} from UDT {udtname} has been renamed to {udm.name}'
            return self._log(msg)
    
        def lt_udm_changed(self, udtname, udm_tid, udmold, udmnew):
            return self._log()
    
    
    
    # Remove an existing hook on second run
    try:
        idp_hook_stat = "un"
        print("Local type IDB hook: checking for hook...")
        lthook
        print("Local type IDB hook: unhooking....")
        idp_hook_stat2 = ""
        lthook.unhook()
        del lthook
    except:
        print("local type IDB hook: not installed, installing now....")
        idp_hook_stat = ""
        idp_hook_stat2 = "un"
        lthook = lt_logger_hooks_t()
        lthook.hook()
    
    print(f'Local type IDB hook {idp_hook_stat}installed. Run the script again to {idp_hook_stat2}install')
    

    Log frame events

    class frame_logger_hooks_t(ida_idp.IDB_Hooks):
        def __init__(self):
            ida_idp.IDB_Hooks.__init__(self)
            self.inhibit_log = 0
    
        def _format_value(self, v):
            return str(v)
    
        def _log(self, msg=None):
            if self.inhibit_log <= 0:
                if msg:
                    print(f'>>> frame_logger_hooks_f: {msg}')
                else:
                    stack = inspect.stack()
                    frame, _, _, _, _, _ = stack[1]
                    args, _, _, values = inspect.getargvalues(frame)
                    method_name = inspect.getframeinfo(frame)[2]
                    argstrs = []
                    for arg in args[1:]:
                        argstrs.append("%s=%s" % (arg, self._format_value(values[arg])))
                    print(f'>>> frame_logger_hooks_t.{method_name}: {", ".join(args)}')
            return 0
    
        def frame_udm_created(self, func_ea, udm):
            return self._log()
    
        def frame_udm_deleted(self, func_ea, udm_tid, udm):
            return self._log()
    
        def frame_udm_renamed(self, func_ea, udm, oldname):
            return self._log()
    
        def frame_udm_changed(self, func_ea, udm_tid, udmold, udmnew):
            return self._log()
    
    
    
    # Remove an existing hook on second run
    try:
        frame_idp_hook_stat = "un"
        print("Frame IDP hook: checking for hook...")
        framehook
        print("Frame IDP hook: unhooking....")
        frame_idp_hook_stat2 = ""
        framehook.unhook()
        del framehook
    except:
        print("Frame IDP hook: not installed, installing now....")
        frame_idp_hook_stat = ""
        frame_idp_hook_stat2 = "un"
        framehook = frame_logger_hooks_t()
        framehook.hook()
    
    print(f'Frame IDB hook {frame_idp_hook_stat}installed. Run the script again to {frame_idp_hook_stat2}install')
    

    IDC

    IDC is an IDA native, embedded scripting language semantically similar to C/C++.

    Typical use cases

    With IDC, you can write simple scripts for automating repetitive tasks and extending out-of-the-box IDA functionality (for example, for getting the list of all functions or marked positions) without creating more complex plugins with C++ SDK or IDAPython.

    What to check next?

    IDC Getting StartedLearn core concepts of IDC.core-concepts.md
    IDC ReferenceCheck the list of all IDC functions with detailsidc-api-reference.md
    IDC ExamplesExplore ready-to-use samples.idc-examples.md

    Core concepts

    IDC language is a C-like language. It has the same lexical tokens as C does: character set, constants, identifiers, keywords, etc. However, since it is a scripting language, there are no pointers, and all variable types can be handled by the interpreter. Any variable may hold any value; variables are declared without specifying their type;

    auto myvar;

    An IDC program consists of function declarations. By default, execution starts from a function named ‘main’.

    Select a topic to read:

    Expressions

    In the IDC expressions you can use almost all C operations except:

      complex assignment operations as '+='
    

    Constants are defined more or less like in C, with some minor differences.

    There are four type conversion operations:

      long(expr)  floating point numbers are truncated during conversion
      char(expr)
      float(expr)
      __int64(expr)
    

    However, explicit type conversions are rarely required because all type conversions are made automatically:

      - addition:
            if both operands are strings,
              string addition is performed (strings are concatenated);
            if both operands are objects,
              object combination is performed (a new object is created)
            if floating point operand exists,
              both operands are converted to floats;
            otherwise
              both operands are converted to longs;
    
      - subtraction/multiplication/division:
            if floating point operand exists,
              both operands are converted to floats;
            if both operands are objects and the operation is subtraction,
              object subtraction is performed (a new object is created)
            otherwise
              both operands are converted to longs;
    
      - comparisons (==,!=, etc):
            if both operands are strings, string comparison is performed;
            if floating point operand exists,
              both operands are converted to floats;
            otherwise
              both operands are converted to numbers;
    
      - all other operations:
            operand(s) are converted to longs;
    

    If any of the long operands is 64bit, the other operand is converted to 64bit too.

    There is one notable exception concerning type conversions: if one operand is a string and the other is zero (0), then a string operation is performed. Zero is converted to an empty string in this case.

    The & operator is used to take a reference to a variable. References themselves cannot be modified once created. Any assignment to them will modify the target variable. For example:

            auto x, r;
            r = &x;
            r = 1;   // x is equal to 1 now
    

    References to references are immediately resolved:

            auto x, r1, r2;
            r1 = &x;
            r2 = &r1; // r2 points to x
    

    Since all non-object arguments are passed to functions by value, references are a good way to pass arguments by reference.

    Statements

    In IDC there are the following statements:

    expression; (expression-statement) if (expression) statement
    if (expression) statement else statement
    for ( expr1; expr2; expr3 ) statement
    while (expression) statement
    do statement while (expression);
    break;
    continue;
    return ;
    return; the same as ‘return 0;’
    { statements… }
    try statement catch ( var ) statement
    throw ;
    ; (empty statement)

    Please note that the ‘switch’ statement is not supported.

    Functions

    An IDC function always returns a value. There are 2 kinds of functions:

    • built-in functions
    • user-defined functions A user-defined function is declared this way: static func(arg1,arg2,arg3) { statements … } It is not necessary to specify the parameter types because all necessary type conversions are performed automatically.

    By default all function arguments are passed by value, except:

      - objects are always passed by reference
      - functions are always passed by reference
      - it is possible to pass a variable by reference using the & operator
    

    If the function to call does not exist, IDA tries to resolve the name using the debugged program labels. If it succeeds, an dbg_appcall is performed.

    Variables

    There are two kinds of variables in IDC:

      - local variables: they are created at the function entry
        and destroyed at the exit
    
      - global variables: they are created at the compilation time
        and destroyed when the database is closed
    

    A variable can contain:

    • LONG: a 32-bit signed long integer (64-bit in 64-bit version of IDA)
    • INT64: a 64-bit signed long integer
    • STR: a character string
    • FLOAT: a floating point number (extra precision, up to 25 decimal digits)
    • OBJECT: an object with attributes and methods (a concept very close to C++ class) more
    • REF: a reference to another variable
    • FUNC: a function reference

    A local variable is declared this way:

      auto var1;
      auto var2 = <expr>;
    

    Global variables are declared like this:

      extern var;
    

    Global variables can be redefined many times. IDA will silently ignore subsequent declarations. Please note that global variables cannot be initialized at the declaration time.

    All C and C++ keywords are reserved and cannot be used as a variable name.

    While it is possible to declare a variable anywhere in the function body, all variables are initialized at the function entry and all of them are destroyed only at the exit. So, a variable declared in a loop body will not be reinitialized at each loop iteration, unless explicitly specified with an assignment operator.

    If a variable or function name cannot be recognized, IDA tries to resolve them using the names from the disassembled application. In it succeeds, the name is replaced by its value in the disassembly listing.
    For example:

      .data:00413060 errtable        dd 1   ; oscode
      .data:00413060                 dd 16h ; errnocode
    
            msg("address is: %x\n", _errtable);
    

    will print 413060. If the label denotes a structure, it is possible to refer to its fields:

            msg("address is: %x\n", _errtable.errnocode);
    

    will print 413064. Please note that IDA does not try to read the data but just returns the address of the structure field. The field address can also be calculated using the get_field_ea function.

    NOTE: The processor register names can be used in the IDC scripts when the debugger is active. Reading from such a variable return the corresponding register value. Writing to such a variable modifies the register value in the debugged process. Such variables are accessible only when the application is in the suspended mode.

    NOTE: another way to emulate global scope variables is to use array functions and create global persistent arrays.

    Constants

    The following constants can be used in IDC:

     - long numbers (32-bit for 32-bit version of IDA
                and 64-bit for 64-bit version of IDA)
    
        12345 - decimal constants
        0x444 - hex constants
        01236 - octal constants
        0b110 - binary constants
        'c'   - character constants
    
      Any numeric constant may have 'u' and 'l' suffixes, they are ignored.
    
     - 64-bit numbers. To declare a 64-bit constant, use 'i64' suffix:
    
       123i64
    
       Also, if a constant does not fit 32-bits, it will automatically be
       stored as a 64-bit constant.
    
     - strings. Strings are declared using the double quotes. The backslash
       character can be used to as an escape:
    
       "string"
       "string\nwith four embedded \x0\x00\000\0 zeroes"
    
       Multiple string constants in a row will be automatically concatenated:
    
       "this" " is" " one " "string"
    

    Exceptions

    Any runtime error generates an exception. Exceptions terminate the execution. It is possible to catch an exception instead of terminating the execution:

        auto e;
        try
        {
          ... some statements that cause a runtime error...
        }
        catch ( e )
        {
          // e holds the exception information
          // it is an instance of the exception class
        }
    

    See the details of classes.

    The try/catch blocks can be nested. If the current function has no try/catch blocks, the calling function will be examined, and so on, until we find a try/catch block or exit the main function. If no try/catch block is found, an unhandled exception is reported.

    It is also possible to throw an exception explicitly. Any object can be thrown. For example:

        throw 5;
    

    will throw value ‘5’.

    Classes

    Classes can be declared the following way:

      class name
      {
        method1(...) {}
        ...
      };
    

    Inside the class, method functions are declared without the ‘static’ keyword. The method with the name of the class is the class constructor. For example:

      class myclass
      {
         myclass(x,y)
         {
           print("myclass constructor has been called with two arguments: ", x, y);
           this.x = x;
           this.y = x;
         }
         ~myclass()
         {
           print("destructor has been called: ", this);
         }
      };
    

    Inside the class methods, the ‘this’ variable can be used to refer to the current object.

    Only one constructor per class is allowed.

    Class instances are created like this:

      o = myclass(1, 2);
    

    And object attributes (or fields) are accessed like this:

      print(o.x);
      o.y = o.x + 1;
    

    A new attribute is created upon assigning to it:

      o.new_attr = 1;
    

    Accessing an unexisting attribute generates an exception, which can be caught.

    The following special method names exist:

      __setattr__(attr, value)
        This method is called when an object attribute is assigned a new value.
        Instead of assigning a value, this method can do something else.
        To modify a class attribute from this method, please use the setattr()
        global function.
        Compare with: Python _setattr_ method
    
      __getattr__(attr)
        This method is called when an object attribute is accessed for reading.
        Instead of simply returning a value, this method can do something else,
        for example to calculate the attribute on the fly. To retrieve a
        attribute from this function, use the getattr() global function.
        Compare with: Python _getattr_ method
    

    Simple class inheritance is support. Derived classed are declared like this:

      class derived : base
      {
        ...
      };
    

    Here we declare the ‘derived’ class that is derived from the ‘base’ class. For derived classes, the base class constructor can be called explicitly:

      class derived : base
      {
        derived() : base(args...)
        {
        }
      };
    

    If the base class constructor is not called explicitly, IDA will call it implicitly, without any arguments.

    It is possible to call base class methods using full names:

        base::func(this, args...);
    

    The ‘this’ argument must be passed explicitly in this case.

    When there are no more references to an object, it is automatically destroyed. We use a simple reference count algorithm to track the object use. Circularly dependent objects are not detected: they are never destroyed.

    The following built-in object classes exist:

      - object: the default base class for all new classes. When the base class
        is not specified, the new class will inherit from 'object'
        This class has no fields and no special constructor. It has the following
        methods:
    
    • void object.store(typeinfo, ea, flags)

    • void object.retrieve(typeinfo, ea, flags)

      - exception: class used to report exceptions. It has the following attributes:
      
        file - source file name where the exception occurred
        func - current function name
        line - line number
        pc   - program counter value (internal to idc)
      
        Runtime errors are reported as exceptions too. They are two more fields:
      
        qerrno      - runtime error code
        description - printable error description
      
        This class has no special constructor and has no methods.
      
      - typeinfo: class used to represent type info. It has the following attributes:
      
        type        - binary encoded type string
        fields      - field names for the type (e.g. structure member names)
        name        - (optional) variable/function name
      

    Human readable form of the typeinfo can be obtained by calling the print() method. The type size can be calculated using the size() method.

    Predefined symbols

    The following symbols are predefined in the IDC preprocessor:

      _NT_           IDA is running under MS Windows
      _LINUX_        IDA is running under Linux
      _MAC_          IDA is running under Mac OS X
      _UNIX_         IDA is running under Unix (linux or mac)
      _EA64_         64-bit version IDA
      _QT_           GUI version of IDA (Qt)
      _GUI           GUI version of IDA
      _TXT_          Text version of IDA
      _IDA_VERSION_  The current IDA version. For example: "9.1"
      _IDAVER_       The current, numerical IDA version. For example: "900" means v9.0
    

    These symbols are also defined when parsing C header files.

    loader_input_t class

    The loader_input_t class can read from input files. It has the following methods:

    Instances of this class can be created by calling the open_loader_input function.

    See other IDC classes.

    Slices

    The slice operator can be applied IDC objects are strings.

    For strings, the slice operator denotes a substring:

      str[i1:i2] - substring from i1 to i2. i2 is excluded
      str[idx]   - one character substring at 'idx'.
                   this is equivalent to str[idx:idx+1]
      str[:idx]  - substring from the beginning of the string to idx
                   this is equivalent to str[0:idx]
      str[idx:]  - substring from idx to the end of the string
                   this is equivalent to str[idx:0x7fffffff]
    

    Any indexes that are out of bounds are silently adjusted to correct values. If i1 >= i2, empty string is returned. Negative indexes are used to denote positions counting from the end of the string.

    String slices can be used on the right side of an assignment. For example:

      str[0:2] = "abc";
    

    will replace 2 characters at the beginning of the string by “abc”.

    For objects, the slice operator denotes a subset of attributes. It can be used to emulate arrays:

      auto x = object();
      x[0] = value1;
      x[1] = "value2";
    

    x[i1:i2] denotes all attributes with numeric values between i1 and i2 (i2 is excluded).

    Any non-numeric attributes are ignored by the slice operator.

    Reference

    IDC examples

    The following examples demonstrate the usage of native IDA scripting language in more complex scripts. Our selection illustrates how IDC can help you automate everyday tasks and speed up your learning efforts while learning IDC scripting.

    Where can I find all the examples?

    The full library of our examples is shipped with your IDA instance in the idc folder.

    Before you start

    Some of the examples shows below used an imports another scripts, like idc.idc: the file that contains IDA built-in function declarations and internal bit definitions. It is recommend to check the idc folder for all sample scripts.

    How to run the examples?

    Load the script via File Loader

    1. Navigate to File -> Script file…
    2. In the new dialog, select the .idc script you want to run and click Open.

    Load the script via Script command

    1. Navigate to File -> Script command….
    2. Change the scripting language to IDC.
    3. Paste the code into Please enter script body field and click Run.

    Sample scripts

    You can also find the scripts below in the idc folder inside your IDA directory.

    analysis

    Sample IDC program to automate IDA.

    //
    // Sample IDC program to automate IDA.
    //
    // IDA can be run from the command line in the batch (non-interactive) mode.
    //
    // If IDA is started with
    //
    //         ida -A -Sanalysis.idc file
    //
    // then this IDC file will be executed. It performs the following:
    //
    //   - analyzes the input file
    //   - creates the output file
    //   - exits to the operating system
    //
    // Feel free to modify this file as you wish
    // (or write your own script/plugin to automate IDA)
    //
    // Since the script calls the qexit() function at the end,
    // it can be used in the batch files (use text mode idat)
    //
    // NB: "ida -B file" is a shortcut for the command line above
    //
    
    #include <idc.idc>
    
    static main()
    {
      // turn on coagulation of data in the final pass of analysis
      set_inf_attr(INF_AF, get_inf_attr(INF_AF) | AF_DODATA | AF_FINAL);
      // .. and plan the entire address space for the final pass
      auto_mark_range(0, BADADDR, AU_FINAL);
    
      msg("Waiting for the end of the auto analysis...\n");
      auto_wait();
    
      msg("\n\n------ Creating the output file.... --------\n");
      auto file = get_idb_path()[0:-4] + ".asm";
    
      auto fhandle = fopen(file, "w");
      gen_file(OFILE_ASM, fhandle, 0, BADADDR, 0); // create the assembler file
      msg("All done, exiting...\n");
    
      // the following line instructs IDA to quit without saving the database
      // process_config_directive("ABANDON_DATABASE=YES");
    
      qexit(0); // exit to OS, error code 0 - success
    }
    

    arraytst

    Sample demonstration on how to use array manipulation functions.

    //
    //      This example shows how to use array manipulation functions.
    //
    
    #include <idc.idc>
    
    #define MAXIDX  100
    
    static main() {
      auto id,idx,code;
    
      id = create_array("my array");
      if ( id == -1 ) {
        warning("Can't create array!");
      } else {
    
        msg("Filling array of longs...\n");
        for ( idx=0; idx < MAXIDX; idx=idx+10 )
          set_array_long(id,idx,2*idx);
    
        msg("Displaying array of longs...\n");
        for ( idx=get_first_index(AR_LONG,id);
              idx != -1;
              idx=get_next_index(AR_LONG,id,idx) )
          msg("%d: %d\n",idx,get_array_element(AR_LONG,id,idx));
    
        msg("Filling array of strings...\n");
        for ( idx=0; idx < MAXIDX; idx=idx+10 )
          set_array_string(id, idx, sprintf("This is %d-th element of array", idx));
    
        msg("Displaying array of strings...\n");
        for ( idx=0; idx < MAXIDX; idx=idx+10 )
          msg("%d: %s\n",idx,get_array_element(AR_STR,id,idx));
    
      }
    
    }
    

    bds

    Sample executed when IDA detects Delphi 6-7 or BDS.

    //
    // This file is executed when IDA detects Delphi6-7 or BDS2005-BDS2006
    // invoked from pe_bds.pat
    //
    // Feel free to modify this file as you wish.
    //
    
    #include <idc.idc>
    
    static main()
    {
      // Set Delphi-Style string
      //set_inf_attr(INF_STRTYPE,STRTYPE_LEN4);
    
      // Set demangled names to display
      //set_inf_attr(INF_DEMNAMES,DEMNAM_NAME);
    
      // Set compiler to Borland
      set_inf_attr(INF_COMPILER, COMP_BC);
    }
    
    
    // Add old borland signatures
    static bor32(ea)
    {
      AddPlannedSig("bh32rw32");
      AddPlannedSig("b32vcl");
      SetOptionalSigs("bdsext/bh32cls/bh32owl/bh32ocf/b5132mfc/bh32dbe/b532cgw");
      return ea;
    }
    
    // Add latest version of Borland Cbuilder (Embarcadero)
    static emb(ea)
    {
      AddPlannedSig("bds8rw32");
      AddPlannedSig("bds8vcl");
      SetOptionalSigs("bdsboost/bds8ext");
      return ea;
    }
    
    static has_Emb(ea)
    {
      ea = ea & 0xFFFFFFFF;
      return ea+2 < 0xFFFFFFFF
          && get_wide_byte(ea    ) == 'E'
          && get_wide_byte(ea + 1) == 'm'
          && get_wide_byte(ea + 2) == 'b';
    }
    
    // Detect the latest version of Borland Cbuilder (Embarcadero)
    static detect(ea)
    {
      // Use version string to detect which signatures to use. Both bds08
      // and bds10 (up to xe10) have two null bytes after the string we are
      // testing for, which comes immediately before the argument ea.
      //
      // bds06: Borland C++ - Copyright 2005 Borland Corporation
      // bds08: CodeGear C++ - Copyright 2008 Embarcadero Technologies
      // bds10: Embarcadero RAD Studio - Copyright 2009 Embarcadero Technologies, Inc.
    
      if ( has_Emb(ea-0x1A) || has_Emb(ea-0x20) )
      {
        ResetPlannedSigs();
        emb(ea);
      }
      return ea;
    }
    
    

    biosdata

    Sample that makes comments to BIOS data area.

    //
    //      This script creates a segment at paragraph 0x40 and
    //      makes comments to BIOS data area. To see mnemonical names of
    //      BIOS data area variables, please use this file:
    //
    //        - press F2 when running IDA
    //        - select this file
    //
    
    #include <idc.idc>
    
    //-------------------------------------------------------------------------
    static CW(off,name,cmt) {
      auto x;
      x = 0x400 + off;
      create_word(x);
      set_name(x,name);
      set_cmt(x,cmt, 1);
    }
    
    //-------------------------------------------------------------------------
    static CD(off,name,cmt) {
      auto x;
      x = 0x400 + off;
      create_dword(x);
      set_name(x,name);
      set_cmt(x,cmt, 1);
    }
    
    //-------------------------------------------------------------------------
    static CB(off,name,cmt) {
      auto x;
      x = 0x400 + off;
      create_byte(x);
      set_name(x,name);
      set_cmt(x,cmt, 1);
    }
    
    //-------------------------------------------------------------------------
    static CmtBdata() {
     CW(0x000,"com_port_1","Base I/O address of 1st serial I/O port");
     CW(0x002,"com_port_2","Base I/O address of 2nd serial I/O port");
     CW(0x004,"com_port_3","Base I/O address of 3rd serial I/O port");
     CW(0x006,"com_port_4","Base I/O address of 4th serial I/O port");
    
     CW(0x008,"prn_port_1","Base I/O address of 1st parallel I/O port");
     CW(0x00A,"prn_port_2","Base I/O address of 2nd parallel I/O port");
     CW(0x00C,"prn_port_3","Base I/O address of 3rd parallel I/O port");
     CW(0x00E,"prn_port_4","Base I/O address of 4th parallel I/O port");
    
     CW(0x010,"equip_bits",         "Equipment installed info bits\n"
                                    "15  14  13   12   11  10   9   8\n"
                                    "\\    /      game  \\       /\n"
                                    "# of print  port  # of RS-232\n"
                                    "ports 0-3   used   ports 0-4\n"
                                    "\n"
                                    "7   6    5    4    3   2   1   0\n"
                                    "\\   /    \\    /    \\   / Math  |\n"
                                    "# of   video mode  RAM    uP  no\n"
                                    "disk-  at boot up  00=16K    dsk\n"
                                    "ettes  00=EGA/VGA  01=32K   driv\n"
                                    " 1-4   01=CGA-40   10=48K   if 0\n"
                                    "if bit 10=CGA-80   11=64K\n"
                                    "0 = 1  11=MDA-80   (old PCs)\n"
                                    "\n"
                                    "Note: bit 13=modem on PC lap-tops\n"
                                    "      bit 2=mouse on MCA & others");
    
     CB(0x012,"manufactr_test",     "Manufacturing Test get_wide_byte\n"
                                    "bit 0 = 1 while in test mode\n"
                                    "MCA systems use other bits\n"
                                    "  during POST operations");
     CW(0x013,"base_ram_size",      "Base memory size in KBytes (0-640)");
    
     CB(0x015,"mtest_scratchpad",   "[AT] {Manufacturing test scratch pad}\n"
                                    "[Compaq Deskpro 386] previous scan code");
     CB(0x016,"error_codes",        "[AT] {Manufacturing test scratch pad}\n"
                                    "[PS/2 Mod 30] {BIOS control flags}\n"
                                    "[Compaq Deskpro 386] keyclick loudness (00h-7Fh)");
     CB(0x017,"keybd_flags_1",      "Keyboard flag bits\n"
                                    "  7   6   5   4    3   2   1   0\n"
                                    "ins- cap num scrl alt ctl lef rig\n"
                                    "sert --toggles--- --shifts down--");
     CB(0x018,"keybd_flags_2",      "Keyboard flag bits\n"
                                    "   7     6     5     4   \n"
                                    "insert  caps  num  scroll\n"
                                    "------now depressed------\n"
                                    "\n"
                                    "   3     2     1     0\n"
                                    " pause  sys   left right\n"
                                    " lock request -alt-down-");
     CB(0x019,"keybd_alt_num",      "Alt-nnn keypad workspace");
     CW(0x01A,"keybd_q_head",       "pointer to next character in keyboard buffer");
     CW(0x01C,"keybd_q_tail",       "pointer to first free slot in keyboard buffer");
     CW(0x01E,"keybd_queue",        "Keyboard circular buffer");
     make_array(0x41E, 16 );
     CB(0x03E,"dsk_recal_stat",     "Recalibrate floppy drive bits\n"
                                    "   3       2       1       0\n"
                                    "drive-3 drive-2 drive-1 drive-0\n"
                                    "\n"
                                    "bit 7 = interrupt flag");
     CB(0x03F,"dsk_motor_stat",     "Motor running status & disk write\n"
                                    " bit 7=1 disk write in progress\n"
                                    " bits 6&5 = drive selected 0 to 3\n"
                                    "    3       2       1       0\n"
                                    " drive-3 drive-2 drive-1 drive-0\n"
                                    " --------- 1=motor on-----------");
     CB(0x040,"dsk_motor_timer",    "Motor timer, at 0, turn off motor");
     CB(0x041,"dsk_ret_code",       "Controller return code\n"
                                    " 00h = ok\n"
                                    " 01h = bad command or parameter\n"
                                    " 02h = can't find address mark\n"
                                    " 03h = can't write, protected dsk\n"
                                    " 04h = sector not found\n"
                                    " 08h = DMA overrun\n"
                                    " 09h = DMA attempt over 64K bound\n"
                                    " 10h = bad CRC on disk read\n"
                                    " 20h = controller failure\n"
                                    " 40h = seek failure\n"
                                    " 80h = timeout, no response");
    
     CB(0x042,"dsk_status_1",       "Status bytes-disk controller chip\n"
                                    " Note: 7 info bytes returned from\n"
                                    " controller are saved here. Refer\n"
                                    " to the NEC uPD 765 chip manual\n"
                                    " for the specific info, depending\n"
                                    " on the previous command issued.");
     CB(0x043,"dsk_status_2",       "");
     CB(0x044,"dsk_status_3",       "");
     CB(0x045,"dsk_status_4",       "");
     CB(0x046,"dsk_status_5",       "");
     CB(0x047,"dsk_status_6",       "");
     CB(0x048,"dsk_status_7",       "");
    
     CB(0x049,"video_mode",         "Present display mode");
     CW(0x04A,"video_columns",      "Number of columns");
     CW(0x04C,"video_buf_size",     "Video buffer size in bytes\n"
                                    "  Note: size may be rounded up to\n"
                                    "  the nearest 2K boundary.  For\n"
                                    "  example, 80x25 mode=4000 bytes,\n"
                                    "  but value may be 4096.");
     CW(0x04E,"video_pageoff",      "Video page offset of the active\n"
                                    "  page, from start of current \n"
                                    "  video segment.");
     CW(0x050,"vid_curs_pos0",      "Cursor position page 0\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x052,"vid_curs_pos1",      "Cursor position page 1\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x054,"vid_curs_pos2",      "Cursor position page 2\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x056,"vid_curs_pos3",      "Cursor position page 3\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x058,"vid_curs_pos4",      "Cursor position page 4\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x05A,"vid_curs_pos5",      "Cursor position page 5\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x05C,"vid_curs_pos6",      "Cursor position page 6\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x05E,"vid_curs_pos7",      "Cursor position page 7\n"
                                    "  bits 15-8=row, bits 7-0=column");
     CW(0x060,"vid_curs_mode",      "Active cursor, start & end lines \n"
                                    "  bits 12 to 8 for starting line\n"
                                    "  bits 4  to 0 for ending line");
     CB(0x062,"video_page",         "Present page");
     CW(0x063,"video_port",         "Video controller base I/O address");
     CB(0x065,"video_mode_reg",     "Hardware mode register bits");
     CB(0x066,"video_color",        "Color set in CGA modes");
     CW(0x067,"gen_use_ptr",        "General use offset pointer");
     CW(0x069,"gen_use_seg",        "General use segment pointer");
     CB(0x06B,"gen_int_occurd",     "Unused interrupt occurred\n"
                                    "  value holds the IRQ bit 7-0 of\n"
                                    "  the interrupt that occurred");
     CW(0x06C,"timer_low",          "Timer, low word, cnts every 55 ms");
     CW(0x06E,"timer_high",         "Timer, high word");
     CB(0x070,"timer_rolled",       "Timer overflowed, set to 1 when\n"
                                    " more than 24 hours have elapsed");
     CB(0x071,"keybd_break",        "Bit 7 set if break key depressed");
     CW(0x072,"warm_boot_flag",     "Boot (reset) type\n"
                                    "  1234h=warm boot, no memory test       \n"
                                    "  4321h=boot & save memory");
     CB(0x074,"hdsk_status_1",      "Hard disk status\n"
                                    " 00h = ok\n"
                                    " 01h = bad command or parameter\n"
                                    " 02h = can't find address mark\n"
                                    " 03h = can't write, protected dsk\n"
                                    " 04h = sector not found\n"
                                    " 05h = reset failure\n"
                                    " 07h = activity failure\n"
                                    " 08h = DMA overrun\n"
                                    " 09h = DMA attempt over 64K bound\n"
                                    " 0Ah = bad sector flag\n"
                                    " 0Bh = removed bad track\n"
                                    " 0Dh = wrong # of sectors, format\n"
                                    " 0Eh = removed control data addr\n"
                                    "        mark\n"
                                    " 0Fh = out of limit DMA\n"
                                    "        arbitration level\n"
                                    " 10h = bad CRC or ECC, disk read\n"
                                    " 11h = bad ECC corrected data\n"
                                    " 20h = controller failure\n"
                                    " 40h = seek failure\n"
                                    " 80h = timeout, no response\n"
                                    " AAh = not ready\n"
                                    " BBh = error occurred, undefined\n"
                                    " CCh = write error, selected dsk\n"
                                    " E0h = error register = 0\n"
                                    " FFh = disk sense failure");
     CB(0x075,"hdsk_count",         "Number of hard disk drives");
     CB(0x076,"hdsk_head_ctrl",     "Head control (XT only)");
     CB(0x077,"hdsk_ctrl_port",     "Hard disk control port (XT only)");
     CB(0x078,"prn_timeout_1",      "Countdown timer waits for printer\n"
                                    "  to respond (printer 1)");
     CB(0x079,"prn_timeout_2",      "Countdown timer waits for printer\n"
                                    "  to respond (printer 2)");
     CB(0x07A,"prn_timeout_3",      "Countdown timer waits for printer\n"
                                    "  to respond (printer 3)");
     CB(0x07B,"prn_timeout_4",      "Countdown timer waits for printer\n"
                                    "  to respond (printer 4)");
     CB(0x07C,"rs232_timeout_1",    "Countdown timer waits for RS-232 (1)");
     CB(0x07D,"rs232_timeout_2",    "Countdown timer waits for RS-232 (2)");
     CB(0x07E,"rs232_timeout_3",    "Countdown timer waits for RS-232 (3)");
     CB(0x07F,"rs232_timeout_4",    "Countdown timer waits for RS-232 (4)");
     CW(0x080,"keybd_begin",        "Ptr to beginning of keybd queue");
     CW(0x082,"keybd_end",          "Ptr to end of keyboard queue");
     CB(0x084,"video_rows",         "Rows of characters on display - 1");
     CW(0x085,"video_pixels",       "Number of pixels per charactr * 8");
     CB(0x087,"video_options",      "Display adapter options\n"
                                    "  bit 7 = clear RAM\n"
                                    "  bits 6,5 = memory on adapter\n"
                                    "              00 - 64K\n"
                                    "              01 - 128K\n"
                                    "              10 - 192K\n"
                                    "              11 - 256K\n"
                                    "  bit 4 = unused\n"
                                    "  bit 3 = 0 if EGA/VGA active\n"
                                    "  bit 2 = wait for display enable\n"
                                    "  bit 1 = 1 - mono monitor\n"
                                    "        = 0 - color monitor\n"
                                    "  bit 0 = 0 - handle cursor, CGA");
     CB(0x088,"video_switches",     "Switch setting bits from adapter\n"
                                    "  bits 7-4 = feature connector\n"
                                    "  bits 3-0 = option switches");
     CB(0x089,"video_1_save",       "Video save area 1-EGA/VGA control\n"
                                    "  bit 7 = 200 line mode\n"
                                    "  bits 6,5 = unused\n"
                                    "  bit 4 = 400 line mode\n"
                                    "  bit 3 = no palette load\n"
                                    "  bit 2 = mono monitor\n"
                                    "  bit 1 = gray scale\n"
                                    "  bit 0 = unused");
     CB(0x08A,"video_2_save",       "Video save area 2");
    
     CB(0x08B,"dsk_data_rate",      "Last data rate for diskette\n"
                                    " bits 7 & 6 = 00 for 500K bit/sec\n"
                                    "            = 01 for 300K bit/sec\n"
                                    "            = 10 for 250K bit/sec\n"
                                    "            = 11 for 1M bit/sec\n"
                                    " bits 5 & 4 = step rate"
                                    "Rate at start of operation\n"
                                    " bits 3 & 2 = 00 for 500K bit/sec\n"
                                    "            = 01 for 300K bit/sec\n"
                                    "            = 10 for 250K bit/sec\n"
                                    "            = 11 for 1M bit/sec");
     CB(0x08C,"hdsk_status_2",      "Hard disk status");
     CB(0x08D,"hdsk_error",         "Hard disk error");
     CB(0x08E,"hdsk_complete",      "When the hard disk controller's\n"
                                    " task is complete, this byte is\n"
                                    " set to FFh (from interrupt 76h)");
     CB(0x08F,"dsk_options",        "Diskette controller information\n"
                                    " bit 6 = 1 Drv 1 type determined\n"
                                    "     5 = 1 Drv 1 is multi-rate\n"
                                    "     4 = 1 Drv 1 change detect\n"
                                    "     2 = 1 Drv 0 type determined\n"
                                    "     1 = 1 Drv 0 is multi-rate\n"
                                    "     0 = 1 Drv 0 change detect");
     CB(0x090,"dsk0_media_st",      "Media state for diskette drive 0\n"
                                    "    7      6      5      4\n"
                                    " data xfer rate  two   media\n"
                                    "  00=500K bit/s  step  known\n"
                                    "  01=300K bit/s\n"
                                    "  10=250K bit/s\n"
                                    "  11=1M bit/sec\n"
                                    "    3      2      1      0\n"
                                    " unused  -----state of drive-----\n"
                                    "         bits floppy  drive state\n"
                                    "         000=  360K in 360K, ?\n"
                                    "         001=  360K in 1.2M, ?\n"
                                    "         010=  1.2M in 1.2M, ?\n"
                                    "         011=  360K in 360K, ok\n"
                                    "         100=  360K in 1.2M, ok\n"
                                    "         101=  1.2M in 1.2M, ok\n"
                                    "         111=  720K in 720K, ok\n"
                                    "           or 1.44M in 1.44M\n"
                                    "        (state not used for 2.88)");
     CB(0x091,"dsk1_media_st",      "Media state for diskette drive 1\n"
                                    " (see dsk0_media_st)");
     CB(0x092,"dsk0_start_st",      "Starting state for drive 0");
     CB(0x093,"dsk1_start_st",      "Starting state for drive 1");
     CB(0x094,"dsk0_cylinder",      "Current track number for drive 0");
     CB(0x095,"dsk1_cylinder",      "Current track number for drive 1");
     CB(0x096,"keybd_flags_3",      "Special keyboard type and mode\n"
                                    " bit 7 Reading ID of keyboard\n"
                                    "     6 last char is 1st ID char\n"
                                    "     5 force num lock\n"
                                    "     4 101/102 key keyboard\n"
                                    "     3 right alt key down\n"
                                    "     2 right ctrl key down\n"
                                    "     1 E0h hidden code last\n"
                                    "     0 E1h hidden code last");
     CB(0x097,"keybd_flags_4",      "Keyboard Flags (advanced keybd)\n"
                                    "  7      6       5     4  3 2 1 0\n"
                                    "xmit   char   Resend  Ack   \   /\n"
                                    "error was ID  Rec'd  Rec'd   LEDs");
    
     CW(0x098,"timer_waitoff",      "Ptr offset to wait done flag");
     CW(0x09A,"timer_waitseg",      "Ptr segment to wait done flag");
     CW(0x09C,"timer_clk_low",      "Timer low word, 1 microsecond clk");
     CW(0x09E,"timer_clk_high",     "Timer high word");
     CB(0x0A0,"timer_clk_flag",     "Timer flag 00h = post acknowledgd\n"
                                    "           01h = busy\n"
                                    "           80h = posted");
     CB(0x0A1,"lan_bytes",          "Local area network bytes (7)");
     make_array(0x4A1, 7);
    
     CD(0x0A8,"video_sav_tbl",      "Pointer to a save table of more\n"
                                    "pointers for the video system \n"
                                    "           SAVE TABLE\n"
                                    " offset type    pointer to\n"
                                    " ------ ---- --------------------\n"
                                    "   0     dd  Video parameters\n"
                                    "   4     dd  Parms save area\n"
                                    "   8     dd  Alpha char set\n"
                                    "  0Ch    dd  Graphics char set\n"
                                    "  10h    dd  2nd save ptr table\n"
                                    "  14h    dd  reserved (0:0)\n"
                                    "  18h    dd  reserved (0:0)\n"
                                    " \n"
                                    " 2ND SAVE TABLE (from ptr above)\n"
                                    " offset type functions & pointers\n"
                                    " ------ ---- --------------------\n"
                                    "   0     dw  Bytes in this table\n"
                                    "   2     dd  Combination code tbl\n"
                                    "   6     dd  2nd alpha char set\n"
                                    "  0Ah    dd  user palette tbl\n"
                                    "  0Eh    dd  reserved (0:0)\n"
                                    "  12h    dd  reserved (0:0)\n"
                                    "  16h    dd  reserved (0:0)");
     CW(0x0CE,"days_since1_80",     "Days since 1-Jan-1980 counter");
     make_array(0x4AC,0xCE-0xAC);
    }
    
    //-------------------------------------------------------------------------
    static main() {
      if ( !add_segm_ex(0x400, 0x4D0, 0x40, 0, 0, 2, ADDSEG_NOSREG) ) {
        warning("Can't create BIOS data segment.");
        return;
      }
      set_segm_name(0x400, "bdata");
      set_segm_class(0x400, "BIOSDATA");
      CmtBdata();
    }
    

    entrytst

    Sample that shows how to get list of entry points.

    //
    //      This example shows how to get list of entry points.
    //
    
    #include <idc.idc>
    
    static main() {
      auto i;
      auto ord,ea;
    
      msg("Number of entry points: %ld\n",get_entry_qty());
      for ( i=0; ; i++ ) {
        ord = get_entry_ordinal(i);
        if ( ord == 0 ) break;
        ea = get_entry(ord);
        msg("Entry point %08lX at %08lX (%s)\n",ord,ea,Name(ea));
      }
    }
    

    find_insn

    Script to be used with the ‘grep’ plugins.

    #include <idc.idc>
    
    // This script is to be used with the 'grep' ida plugin
    // It looks for the specified instruction mnemonics and saves all matches
    
    static find_insn(mnem)
    {
      auto ea;
      for ( ea=get_inf_attr(INF_MIN_EA); ea != BADADDR; ea=next_head(ea, BADADDR) )
      {
        if ( print_insn_mnem(ea) == mnem )
          save_match(ea, "");
      }
    }
    

    fixuptst

    Sample that gets fixup information about the file.

    //
    //      This example shows how to get fixup information about the file.
    //
    
    #include <idc.idc>
    
    static main() {
      auto ea;
      for ( ea = get_next_fixup_ea(get_inf_attr(INF_MIN_EA));
            ea != BADADDR;
            ea = get_next_fixup_ea(ea) ) {
        auto type,sel,off,dis,x;
        type = get_fixup_target_type(ea);
        sel  = get_fixup_target_sel(ea);
        off  = get_fixup_target_off(ea);
        dis  = get_fixup_target_dis(ea);
        msg("%08lX: ",ea);
        x = type & FIXUP_MASK;
             if ( x == FIXUP_BYTE  ) msg("BYTE ");
        else if ( x == FIXUP_OFF16 ) msg("OFF16");
        else if ( x == FIXUP_SEG16 ) msg("SEG16");
        else if ( x == FIXUP_PTR32 ) msg("PTR32");
        else if ( x == FIXUP_OFF32 ) msg("OFF32");
        else if ( x == FIXUP_PTR48 ) msg("PTR48");
        else if ( x == FIXUP_HI8   ) msg("HI8  ");
        else                         msg("?????");
        msg((type & FIXUP_EXTDEF) ? " EXTDEF" : " SEGDEF");
        msg(" [%s,%X]",get_segm_name(get_segm_by_sel(sel)),off);
        if ( type & FIXUP_EXTDEF  ) msg(" (%s)",Name([sel2para(sel),off]));
        if ( type & FIXUP_SELFREL ) msg(" SELF-REL");
        if ( type & FIXUP_UNUSED  ) msg(" UNUSED");
        msg("\n");
      }
    }
    

    functest

    Sample that gets list of funcions.

    //
    //      This example shows how to get list of functions.
    //
    
    #include <idc.idc>
    
    static main() {
      auto ea,x;
    
      for ( ea=get_next_func(0); ea != BADADDR; ea=get_next_func(ea) ) {
        msg("Function at %08lX: %s",ea,get_func_name(ea));
        x = get_func_flags(ea);
        if ( x & FUNC_NORET ) msg(" Noret");
        if ( x & FUNC_FAR   ) msg(" Far");
        msg("\n");
      }
      ea = choose_func("Please choose a function");
      msg("The user chose function at %08lX\n",ea);
    }
    
    

    kernel

    Sample that insert custom comments for the imported DLLs.

    //
    //      This file show how to insert you own comments for the imported DLLs.
    //      This file inserts a comment for the kernel function #23 'LOCKSEGMENT'.
    //      You may add your own comments for other functions and DLLs.
    //      To execute this file your should choose 'Execute IDC file' command
    //      from the IDA menu. Usually the  hotkey is F2.
    //
    
    #include <idc.idc>
    
    static main(void)
    {
      auto faddr;
      auto fname;
    
      msg("Loading comments...\n");
      fname = sprintf("KERNEL_%ld", 23);        // build the function name
      faddr = get_name_ea_simple(fname);             // get function address
      if ( faddr != -1 ) {                  // if the function exists
        update_extra_cmt(faddr,E_PREV + 0,";ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ");
        update_extra_cmt(faddr,E_PREV + 1,"; LockSegment (2.x)");
        update_extra_cmt(faddr,E_PREV + 2,"; ");
        update_extra_cmt(faddr,E_PREV + 3,"; In: AX - segment to lock");
        update_extra_cmt(faddr,E_PREV + 4,";     LockSegment function locks the specified discardable");
        update_extra_cmt(faddr,E_PREV + 5,"; segment. The segment is locked into memory at the given");
        update_extra_cmt(faddr,E_PREV + 6,"; address and its lock count is incremented (increased by one).");
        update_extra_cmt(faddr,E_PREV + 7,"; Returns");
        update_extra_cmt(faddr,E_PREV + 8,"; The return value specifies the data segment if the function is");
        update_extra_cmt(faddr,E_PREV + 9,"; successful. It is NULL if the segment has been discarded or an");
        update_extra_cmt(faddr,E_PREV + 10,"; error occurs.");
      }
      msg("Comment(s) are loaded.\n");
    }
    

    loaddef

    Sample that loads DEF file with dialog.

    // Load a DEF file with Dialog
    // Saved the last browsed path in the Database
    
    // This file is donated by Dietrich Teickner.
    
    #include <idc.idc>
    
    #define	VERBOSE	1
    #define WITHSELFEDITED 1
    
    static main(void)
    {
    	auto	defFileName, defFile, w, p, modulImport;
    
    	defFileName = AskFileEx(0,"*.def","Choose a definition-file");
    	modulImport = defFileName;
    	while (1) {
    		p = strstr(modulImport,"\\");
    		if (-1 == p) break;
    		modulImport = substr(modulImport,p+1,-1);
    	};
    	p = strstr(modulImport,".");
    	if (-1 < p)
    		modulImport = substr(modulImport,0,p);
    	modulImport = translate(modulImport);
    
    	if(VERBOSE)	msg("Opening definition file %s\n", defFileName);
    
    	defFile = fopen(defFileName, "rb");
    
    	if (0 != defFile)
    	{
    		auto defline, ea, bea, sea, eea, newName, oldName, badName, x, z, id;
    
    		//
    		// Process all of the DEF's in this file.
    		//
    		if(VERBOSE)	msg("Processing %s\n", defFileName);
    
    		defline = "";
    
    		do
    		{
    			defline = ReadDefLine(defFile);
    			if (strlen(defline) == 0) break;
    			w = wordn(defline,1);
    			w = translate(w);
    			if ("LIBRARY" == w) {
    				w = wordn(substr(defline,strlen(w)+1,-1),1);
    				if (strlen(w) > 0) modulImport = w;
    				continue;
    			}
    			if ("EXPORTS" != w) continue;
    			if (strlen(modulImport) == 0) break;
    			sea = get_first_seg();
    			while ((-1 != sea) & (get_segm_name(sea) != modulImport)) {
    				sea = get_next_seg(sea);
    			}
    			if (-1 == sea) break;
    			w = get_segm_name(sea);
    			eea = get_segm_end(sea);
    			do
    			{
    				defline = ReadDefLine(defFile);
    				if (strlen(defline) == 0) break;
    				p = strstr(defline," @");
    				if (0 > p) continue;
    				w = substr(defline,p+2,-1);
    				defline = substr(defline,0,p);
    				w = wordn(w,1); /* import-number */
    				w = translate(modulImport)+"_"+w;
    				newName = w+"_"+wordn(defline,1);
    				if (WITHSELFEDITED) {
    					z = wordn(defline,1);
    					badName = z+"_"+w;
    					p = strstr(z,"@");
    					if (p != -1) {
    						x = substr(z,0,p);
    						badName = badName+" "+x+" "+w+"_"+x+" "+x+"_"+w;
    					}
    					while (substr(z,0,1) == "_") {
    						z = substr(z,1,-1);
    						badName = badName+" "+z+" "+w+"_"+z+" "+z+"_"+w;
    						if (p != -1) {
    							x = substr(x,1,-1);
    							badName = badName+" "+x+" "+w+"_"+x+" "+x+"_"+w;
    						}
    					}
    					z = " "+newName+" "+w+" "+defline+" "+badName+" ";
    				} else {
    					z = " "+newName+" "+w+" "+defline+" ";
    				}
    				x = "__imp_";
    				p = strlen(x);
    				for (ea = sea;ea < eea;ea++) {
    					oldName = Name(ea);
    					if (strstr(z," "+oldName+" ") != -1) break;
    					if (strstr(oldName,x) != 0) continue;
    					if (strstr(z," "+substr(oldName,p,-1)+" ") != -1) break;
    				}
    				if (ea == eea) continue;
    				p = strstr(defline,"@");
    				if (-1 != p) {
    					z = substr(defline,p+1,-1);
    					z = wordn(z,1);
    					z = atol(z);
    					p = get_frame_args_size(ea);
    					if (p != z) {
    						set_frame_size(ea,get_frame_lvar_size(ea),get_frame_regs_size(ea),z);
    						auto_wait();
    					}
    				}
    				if (oldName != newName)	{
    					set_name(ea ,newName);
    					if(VERBOSE)	msg("--> %x,%s->%s\n", ea, oldName, newName);
    				}
    			}
    			while (strlen(defline) > 0);
    		}
    		while (strlen(defline) > 0);
        	fclose(defFile);
    	}
    }
    
    static wordn(c,i) {
    	auto t, l, p, s;
    	p = 0;
    	l = strlen(c);
    	t = "";
    	while (0 < i) {
    		i = i-1;
    		while ((p < l) & (" " == substr(c,p,p+1))) p++;
    		while (p < l) {
    			s = substr(c,p,++p);
    			if (s == " ") break;
    			if (i == 0) t = t + s;
    		}
    	}
    	return (t);
    }
    
    static translate(c) {
    	auto s,t;
    	s = "abcdefghijklmnopqrst";
    	t = "ABCDEFGHIJKLMNOPQRST";
    	return translate2(c,s,t);
    }
    
    static translate2(c,s,t) {
    	auto i,j,k,l;
    	l = strlen(s) - strlen(t);
    	for (i = 0;i < l;i++) {
    		t = t + " ";
    	}
    	l = strlen(c);
    	for (i = 0;i < l;i++) {
    		k = substr(c,i,i+1);
    		j = strstr(s,k);
    		if (0 <= j) {
    			c = substr(c,0,i) + substr(t,j,j+1) + substr(c,i+1,-1);
    		}
    	}
    	return c;
    }
    
    static ReadDefLine(defFile)
    {
    	auto line, wordstr, c, delim, i, first;
    
    	delim = ""+0x0d+" "+0x09+0x0a;
    
    	do {
    
    		line = "";
    		i = 0;
    		first = 1;
    
    		do {
    			wordstr = "";
    			c = "";
    			do {
    				wordstr = wordstr + c;
    				c = fgetc(defFile);
    				if (-1 != c) {
    					i = strstr(delim,c);
    				} else i = - 2;
    			} while (-1 == i);
    			if (strlen(wordstr) > 0) {
    				if (!first) line = line + " ";
    				first = 0;
    				line = line + wordstr;
    			};
    		} while (0 < i);
    		if ((strlen(line) > 0) & (substr(line,0,1) == ";")) line = "";
    	} while ((strlen(line) == 0) & (0 == i));
    	return(line);
    }
    
    static getPath(fileName) {
    	auto	pos, path;
    	path = "";
    	while (1) {
    		pos = strstr(fileName,"\\");
    		if (-1 == pos) break;
    		path = path + substr(fileName,0,pos+1);
    		fileName = substr(fileName,pos+1,-1);
    	}
    	return path;
    }
    
    static AskFileEx(forSave, ext, dialogText) {
    	auto	fileName, w, p, extArrayId, lastPath, newPath, extKey;
    	w = ext;
    	if (substr(w,0,1) == "*") w = substr(w,1,-1);
    	if (substr(w,0,1) == ".") w = substr(w,1,-1);
    /* is case-sensitive */
    	extKey = "DT#"+w;
    	extArrayId = get_array_id("DT#EXT#Array");
    	if (-1 == extArrayId)
    		extArrayId = create_array("DT#EXT#Array");
    	lastPath = get_hash_string(extArrayId,extKey);
    /* without this, we have at first only '*' as Mask, but not "*.ext". IDA 4.20 */
    	if ("" == lastPath)
    		lastPath = getPath(get_root_filename());
    	w = lastPath+"*."+w;
    	if(VERBOSE)	msg("--> lastPath %s\n", w);
    	fileName = askfile(forSave,w,dialogText);
    	if (("" == fileName) | (-1 == extArrayId))
    		return fileName;
    	newPath = getPath(fileName);
    	if (("" != newPath) & (lastPath != newPath))
    // Save the new path, associated with the extension in the Database
    		set_hash_string(extArrayId, extKey, newPath);
    	return fileName;
    }
    
    

    loadsym

    Sample that loads a SYM file with dialog.

    //
    // Load a SYM file with Dialog
    // Saved the last browsed path associated with the extension in the Database
    // (use with dbg2map and mapsym)
    //
    // History:
    //
    // v1.00 - This file is originally donated by David Cattley.
    // v1.07 - Bugfix, improved interface, handles larger SegDefs
    // v1.08 - extended for save tha last used path associaded with *.sym in the current database
    //         set VAC to 0 for aktivating v1.07
    //         set VAC to 1 for sym-files from IBM/Microsoft MAPSYM for OS/2 (Loadsym V1.00)
    //
    
    #include <idc.idc>
    
    #define VERBOSE 1
    
    // set to version before IDA 4.30, for mapsym.exe VAC, not found any informations about the last changes
    #define VAC 1
    
    static main(void)
    {
            auto    symFileName, symFile;
    
            symFileName = AskFileEx(0,"*.sym","Choose the symbol-file");
    
            if(symFileName=="")
              { if(VERBOSE) msg("Operation cancelled by user.\n");
                return -1; }
    
            if(VERBOSE)     msg("Opening symbol file %s\n", symFileName);
            symFile = fopen(symFileName, "rb");
    
            if (0 != symFile)
            {
                    auto nextMapDef;
    
                    //
                    // Process all of the MAPDEF's in this file.
                    //
                    // if(VERBOSE)     msg("%0.4x: ", ftell(symFile));
                    if(VERBOSE)     msg("Processing %s\n", symFileName);
    
                    nextMapDef = 0;
    
                    do
                    {
                            nextMapDef = DoMapDef(symFile, nextMapDef);
                    }
                    while (0 != nextMapDef);
            }
            else
            { if(VERBOSE) msg("Can't open symbol file:\n%s\n", symFileName);
              return -1;
            }
            if(VERBOSE) msg("Symbol file has been loaded successfully.\n");
    }
    
    
    static DoMapDef(File, Position)
    {
            auto    ppNextMap;
    
            //
            // Process the specified MAPDEF structure.
            //
            fseek(File, Position, 0);
    
            if(VERBOSE)     msg("%0.4x: ", ftell(File));
    
            ppNextMap = readshort(File, 0);
    
            if (0 == ppNextMap)
            {
                    //
                    // This is the last one!  It is special.
                    //
                    auto release, version;
    
                    release = fgetc(File);
                    version = fgetc(File);
    
                    if(VERBOSE)     msg("VERSION Next:%x Release:%x Version:%x\n",
                                    ppNextMap,
                                    release,
                                    version
                                    );
            }
            else
            {
                    auto    bFlags, bReserved1, pSegEntry,
                                    cConsts, pConstDef, cSegs, ppSegDef,
                                    cbMaxSym, achModName;
    
                    auto i, nextSegDef;
    
                    bFlags = fgetc(File);
                    bReserved1 = fgetc(File);
                    pSegEntry = readshort(File, 0);
                    cConsts = readshort(File, 0);
                    pConstDef = readshort(File, 0);
                    cSegs = readshort(File, 0);
                    ppSegDef = readshort(File, 0);
                    cbMaxSym = fgetc(File);
                    achModName = ReadSymName(File);
    
                    if(VERBOSE)     msg("MAPDEF Next:%x Flags:%x Entry:%x Con:%d@%x Seg:%d@%x Max:%d Mod:%s\n",
                                    ppNextMap,
                                    bFlags,
                                    pSegEntry,
                                    cConsts, pConstDef,
                                    cSegs, ppSegDef,
                                    cbMaxSym,
                                    achModName
                                    );
    
                    //
                    // Process the SEGDEFs in this MAPDEF
                    //
                    nextSegDef = ppSegDef << 4;
    
                    for (i=0; i<cSegs; i=i+1)
                    {
                            nextSegDef = DoSegDef(File, nextSegDef);
                    }
            }
    
            //
            // Return the file position of the next MAPDEF
            //
            return (ppNextMap << 4);
    }
    
    
    static DoSegDef(File, Position)
    {
            auto    ppNextSeg, cSymbols, pSymDef,
                            wSegNum, wReserved2, wReserved3, wReserved4,
                            bFlags, bReserved1, ppLineDef, bReserved2,
                            bReserved3, achSegName;
    
            auto i, n, symPtr, segBase;
    
            //
            // Process the specified SEGDEF structure.
            //
            fseek(File, Position, 0);
    
            if(VERBOSE)     msg("%0.4x: ", ftell(File));
    
            ppNextSeg = readshort(File, 0);
            cSymbols = readshort(File, 0);
            pSymDef = readshort(File, 0);
            wSegNum = readshort(File, 0);
            wReserved2 = readshort(File, 0);
            wReserved3 = readshort(File, 0);
            wReserved4 = readshort(File, 0);
            bFlags = fgetc(File);
            bReserved1 = fgetc(File);
            ppLineDef = readshort(File, 0);
            bReserved2 = fgetc(File);
            bReserved3 = fgetc(File);
            achSegName = ReadSymName(File);
    
            if (VAC) {
              segBase = get_segm_by_sel(wSegNum);
           // the others will access the externals, sym-files from MAPSYM contains only internals
            } else {
           // segBase = get_segm_by_sel(wSegNum); //fixed
              segBase = get_first_seg();
              for (i=wSegNum; i > 1; i=i-1) { segBase = get_next_seg(segBase); }
            }
            if(VERBOSE)     msg("SEGDEF Next:%x Sym:(%d)@%x Flags:%x Lines:%x Seg:%s [%04x %08x]\n",
                            ppNextSeg,
                            cSymbols, pSymDef,
                            bFlags,
                            ppLineDef,
                            achSegName, wSegNum, segBase
                            );
    
            //
            // Process the symbols in this SEGDEF
            //
            n = 2;
            if (!VAC) {
           // sym-files from MAPSYM (VAC) works with unshifted pSymDef
               pSymDef = pSymDef << (bFlags & 0xFE);
               if ((bFlags & 0xFE) != 0) n++;
            }
            for (i=0; i<cSymbols; i=i+1)
            {
                 // fseek(File, Position+pSymDef+(i*2), 0); //fixed
                    fseek(File, Position+pSymDef+(i*n), 0);
                    if (n>2) symPtr = Position+(readlong(File, 0)&0xFFFFFF);
                    else symPtr = Position+readshort(File, 0);
                    DoSymDef(File, symPtr, (bFlags & 1), wSegNum);
            }
    
            //
            //  Return the position of the next SEGDEF
            //
            return (ppNextSeg << 4);
    }
    
    
    static DoSymDef(File, Position, Size, Segment)
    {
            auto dwSymVal, achSymName, ea, i;
    
            fseek(File, Position, 0);
    
            if(VERBOSE)     msg("%0.4x: ", ftell(File));
    
            if (0 == Size)
                    dwSymVal = readshort(File, 0);
            else
                    dwSymVal = readlong(File, 0);
    
            achSymName = ReadSymName(File);
    
            //
            // Calculate the EA of this symbols.
            //
            if (VAC) {
              ea = get_segm_by_sel(Segment) + dwSymVal;
         // sym-files from MAPSYM contains only internals
            } else {
           // ea = get_segm_by_sel(Segment) + dwSymVal; // fixed
              ea = get_first_seg(); // This points to the externals ???
              for (i=Segment; i > 1; i=i-1) { ea = get_next_seg(ea); }
              ea = ea + dwSymVal;
            }
    
            if(VERBOSE)     msg("SYM%d: %04x:%08x [%08x] %s\n",
                            (16+Size*16),
                            Segment, dwSymVal, ea,
                            achSymName);
    
            //
            // Now go and name the location!
            //
            set_name(ea, "");
            set_name(ea, achSymName);
    }
    
    
    static ReadSymName(symFile)
    {
            auto i, nameLen, name;
    
            name = "";
            nameLen = fgetc(symFile);
    
            for (i=0; i<nameLen; i=i+1)
            {
                    name = name + fgetc(symFile);
            }
    
            return(name);
    }
    
    static getPath(fileName) {
    	auto	pos, path;
    	path = "";
    	while (1) {
    		pos = strstr(fileName,"\\");
    		if (-1 == pos) break;
    		path = path + substr(fileName,0,pos+1);
    		fileName = substr(fileName,pos+1,-1);
    	}
    	return path;
    }
    
    static AskFileEx(forSave, ext, dialogText) {
    	auto	fileName, w, p, extArrayId, lastPath, newPath, extKey;
    	w = ext;
    	if (substr(w,0,1) == "*") w = substr(w,1,-1);
    	if (substr(w,0,1) == ".") w = substr(w,1,-1);
    /* is case-sensitive */
    	extKey = "DT#"+w;
    	extArrayId = get_array_id("DT#EXT#Array");
    	if (-1 == extArrayId)
    		extArrayId = create_array("DT#EXT#Array");
    	lastPath = get_hash_string(extArrayId,extKey);
    /* without this, we have at first only '*' as Mask, but not "*.ext". IDA 4.20 */
    	if ("" == lastPath)
    		lastPath = getPath(get_input_file_path());
    	w = lastPath+"*."+w;
    	if(VERBOSE)	msg("--> lastPath %s\n", w);
    	fileName = askfile(forSave,w,dialogText);
    	if (("" == fileName) | (-1 == extArrayId))
    		return fileName;
    	newPath = getPath(fileName);
    	if (("" != newPath) & (lastPath != newPath))
    // Save the new path, associated with the extension in the Database
    		set_hash_string(extArrayId, extKey, newPath);
    	return fileName;
    }
    
    

    marktest

    Sample that shows how to get list of marked positions.

    //
    //      This example shows how to get list of marked positions.
    //
    
    #include <idc.idc>
    
    static main() {
      auto x;
    
      put_bookmark(get_screen_ea(),10,5,5,6,"Test of Mark Functions");
      for ( x=0; x<10; x++ )
        msg("%d: %a %s\n",x,get_bookmark(x),get_bookmark_desc(x));
    }
    

    memcpy

    Sample that demonstrates how to copy memory blocks.

    //
    //      This file demonstrates how to copy blocks of memory
    //      using IDC. To use it, press F2 and select this file.
    //      Once loaded and compiled all IDC functions stay in memory
    //      so afterwards you can copy blocks simply pressing Shift-F2
    //      and entering something like:
    //
    //              memcpy(0x30000, 0x20000, 0x100);
    //
    //      This construction copies 0x100 bytes from 0x20000 to 0x30000.
    //
    //      Also, you can delete main() function below.
    //      When you try to execute this file, you'll get an error:
    //      can find function 'main', don't pay attention.
    //      You will get memcpy() function in the memory.
    //      In this case you should create a segment youself (if nesessary).
    //
    
    #include <idc.idc>
    
    //------------------------------------------------------------------------
    static memcpy(to, from, size)
    {
      auto i;
      for ( i=0; i < size; i=i+1 )
      {
        auto b = get_wide_byte(from);
        patch_byte(to, b);
        from = from + 1;
        to = to + 1;
      }
    }
    
    //------------------------------------------------------------------------
    static main(void)
    {
      auto from = ask_addr(here, "Please enter the source address");
      if ( from == BADADDR )
        return;
      auto to = ask_addr(BADADDR, "Please enter the target address");
      if ( to == BADADDR )
        return;
      auto size = ask_long(0, "Please enter the number of bytes to copy");
      if ( size == 0 )
        return;
    
      memcpy(to, from, size);
    }
    
    

    ndk

    Android bionic lib.

    #include <idc.idc>
    
    static main()
    {
    }
    
    // Android Bionic libc
    //
    // These functions are called while loading startup signatures from
    // elf.sig to obtain the address of main.
    
    static get_main_ea(ea, got_ldr, got_off, main_off)
    {
      auto got_ea = 0;
    
      if ( got_off != 0 )
      {
        auto _ea = TRUNC(ea + got_ldr);
        create_insn(_ea);
        got_ea = get_first_dref_from(_ea);
        if ( got_ea == BADADDR )
          return BADADDR;
        got_ea = get_wide_dword(got_ea);
        if ( got_ea == BADADDR )
          return BADADDR;
        got_ea = TRUNC(got_ea + ea + got_off + 8);
    
        ea = TRUNC(ea + main_off);
        create_insn(ea);
        ea = get_first_dref_from(ea);
        if ( ea == BADADDR )
          return BADADDR;
    
        ea = get_wide_dword(ea);
        if ( ea == BADADDR )
          return BADADDR;
      }
    
      ea = TRUNC(got_ea + ea);
    
      ea = get_wide_dword(ea);
      if ( ea == BADADDR )
        return BADADDR;
    
      // Check that segment is executable
      if ( (get_segm_attr(ea, SEGATTR_PERM) & SEGPERM_EXEC) == 0 )
        return BADADDR;
    
      return ea;
    }
    
    static get_main_ea_pic(ea, got_ldr, got_off, main_off)
    {
      return get_main_ea(ea, long(got_ldr), long(got_off), long(main_off));
    }
    
    static get_main_ea_abs(ea)
    {
      return get_main_ea(ea, 0, 0, 0);
    }
    

    onload

    File called after a new file is loaded into IDA.

    //
    //      This IDC file is called after a new file is loaded into IDA
    //      database.
    //      IDA calls "OnLoad" function from this file.
    //
    //      You may use this function to read extra information (such as
    //      debug information) from the input file, or for anything else.
    //
    
    #include <idc.idc>
    
    //      If you want to add your own processing of newly created databases,
    //      you may create a file named "userload.idc":
    //
    //      #define USERLOAD_IDC
    //      static userload(input_file,real_file,filetype) {
    //              ... your processing here ...
    //      }
    //
    
    #softinclude <userload.idc>
    
    // Input parameteres:
    //      input_file - name of loaded file
    //      real_file  - name of actual file that contains the input file.
    //                   usually this parameter is equal to input_file,
    //                   but is different if the input file is extracted from
    //                   an archive.
    //      filetype   - type of loaded file. See FT_.. definitions in idc.idc
    
    static OnLoad(input_file, real_file, filetype)
    {
    #ifdef USERLOAD_IDC             // if user-defined IDC file userload.idc
                                    // exists...
      if ( userload(input_file, real_file, filetype) )
        return;
    #endif
      if ( filetype == FT_DRV )
        DriverLoaded();
    //  msg("File %s is loaded into the database.\n",input_file);
    }
    
    
    //--------------------------------------------------------------------------
    //      This function is executed when a new device driver is loaded.
    //              Device drivers have extensions DRV or SYS.
    //
    // History:
    //
    // 08/12/95 20:16 by Alexey Kulentsov:
    // + Check for Device Request Block
    // + Kludge with Drv/Com supported
    // 04/01/96 04:21 by ig:
    // + 0000:0000 means end of devices chain too.
    // 16/05/96 16:01 by ig:
    // + modified to work with the new version of IDA (separate operand types)
    
    static DriverLoaded(void)
    {
      auto x,i,base;
      auto intr,strt;
      auto attr,cmt;
      auto nextbase;
      auto DevReq;
    
      i = 0;
      x = get_inf_attr(INF_MIN_EA);
      base = (x >> 4);   // The segment base
    
      while ( 1 )
      {
        msg("Device driver block at %04X\n",x);
    
        set_name(x, sprintf("NextDevice_%ld",i));
        create_word(x);
        op_num(x,0);
        if ( get_wide_word(x) == 0xFFFF ) {
          set_cmt(x, "The last device", 0);
        } else {
          nextbase = base + get_wide_word(x+2);
          op_plain_offset(x,0,nextbase<<4);
          set_cmt(x, "Offset to the next device", 0);
        }
    
        create_word(x+2);
        op_num(x+2,0);
    
        set_name(x+4, sprintf("DevAttr_%ld",i));
        create_word(x+4);
        op_num(x+4,0);
        attr = get_wide_word(x+4);
        cmt = "";
        if ( attr & (1<< 0) ) cmt = cmt + "stdin device\n";
        if ( attr & (1<< 1) ) cmt = cmt + ((attr & (1<<15)) ? "stdout device\n" : ">32M\n");
        if ( attr & (1<< 2) ) cmt = cmt + "stdnull device\n";
        if ( attr & (1<< 3) ) cmt = cmt + "clock device\n";
        if ( attr & (1<< 6) ) cmt = cmt + "supports logical devices\n";
        if ( attr & (1<<11) ) cmt = cmt + "supports open/close/RM\n";
        if ( attr & (1<<13) ) cmt = cmt + "non-IBM block device\n";
        if ( attr & (1<<14) ) cmt = cmt + "supports IOCTL\n";
        cmt = cmt + ((attr & (1<<15)) ? "character device" : "block device");
        set_cmt(x+4, cmt, 0);
    
        set_name(x+6, sprintf("Strategy_%ld",i));
        create_word(x+6);
        op_plain_offset(x+6,0,get_inf_attr(INF_MIN_EA));
    
        set_name(x+8, sprintf("Interrupt_%ld",i));
        create_word(x+8);
        op_plain_offset(x+8, -1, get_inf_attr(INF_MIN_EA));
    
        set_name(x+0xA, sprintf("DeviceName_%ld",i));
        create_strlit (x+0xA,8);
        set_cmt(x+0xA, "May be device number", 0);
    
        strt = (base << 4) + get_wide_word(x+6);
        intr = (base << 4) + get_wide_word(x+8);
        create_insn( strt );
        create_insn( intr );
        auto_mark_range(strt, strt+1, AU_PROC);
        auto_mark_range(intr, intr+1, AU_PROC );
        set_name( strt, sprintf("Strategy_Routine_%ld",i));
        set_name( intr, sprintf("Interrupt_Routine_%ld",i));
        set_cmt( strt, "ES:BX -> Device Request Block", 0);
        set_cmt( intr, "Device Request Block:\n"
                 "0 db length\n"
                 "1 db unit number\n"
                 "2 db command code\n"
                 "5 d? reserved\n"
                 "0D d? command specific data", 0);
    
        if( get_wide_byte( strt )==0x2E && get_wide_word(strt+1)==0x1E89
         && get_wide_byte(strt+5)==0x2E && get_wide_word(strt+6)==0x068C
         && get_wide_word(strt+3)==get_wide_word(strt+8)-2)
        {
         DevReq=get_wide_word(strt+3);
         msg("DevReq at %x\n",DevReq);
         del_items(x+DevReq);
         del_items(x+DevReq+2);
         create_dword(x+DevReq);
         set_name(x+DevReq, sprintf("DevRequest_%ld",i));
        }
    
        if ( get_wide_word(x) == 0xFFFF ||
           ((get_wide_byte(x)==0xE9 || get_wide_byte(x)==0xEB) && i==0) ) break;
        if ( get_wide_dword(x) == 0 ) break; // 04.01.96
        x = (nextbase << 4) + get_wide_word(x);
        i = i + 1;
      }
    }
    

    opertest

    Sample demonstrates how to use get_operand_value() function.

    //
    //      This example shows how to use get_operand_value() function.
    //
    
    #include <idc.idc>
    
    static main() {
      auto ea;
    
      for ( ea = get_inf_attr(INF_MIN_EA); ea != BADADDR; ea=find_code(ea,1) ) {
        auto x;
        x = get_operand_value(ea,0);
        if ( x != -1 ) msg("%08lX: operand 1 = %08lX\n",ea,x);
        x = get_operand_value(ea,1);
        if ( x != -1 ) msg("%08lX: operand 2 = %08lX\n",ea,x);
        x = get_operand_value(ea,2);
        if ( x != -1 ) msg("%08lX: operand 3 = %08lX\n",ea,x);
      }
    }
    

    pilot

    File executed when a PalmPilot program is loaded.

    //
    //	This file is executed when a PalmPilot program is loaded.
    //	You may customize it as you wish.
    //
    //	TODO:
    //		- decompilation of various resource types
    //		  (we don't have any information on the formats)
    //
    
    #include <idc.idc>
    
    //-----------------------------------------------------------------------
    //
    // Process each resource and make some routine tasks
    //
    static process_segments()
    {
      auto ea,segname,prefix;
    
      for ( ea=get_first_seg(); ea != BADADDR; ea=get_next_seg(ea) )
      {
        segname = get_segm_name(ea);
        prefix = substr(segname,0,4);
        if ( segname == "data0000" )
        {
          if ( get_wide_dword(ea) == 0xFFFFFFFF )
          {
            create_dword(ea);
            set_cmt(ea,"Loader stores SysAppInfoPtr here", 0);
          }
          continue;
        }
        if ( prefix == "TRAP" )
        {
          create_word(ea);
          op_hex(ea,0);
          set_cmt(ea,"System trap function code", 0);
          continue;
        }
        if ( prefix == "tSTR" )
        {
          create_strlit(ea,get_segm_end(ea));
          set_cmt(ea,"String resource", 0);
          continue;
        }
        if ( prefix == "tver" )
        {
          create_strlit(ea,get_segm_end(ea));
          set_cmt(ea,"Version number string", 0);
          continue;
        }
        if ( prefix == "tAIN" )
        {
          create_strlit(ea,get_segm_end(ea));
          set_cmt(ea,"Application icon name", 0);
          continue;
        }
        if ( prefix == "pref" )
        {
          auto flags,cmt;
          flags = get_wide_word(ea);
          create_word(ea); op_hex(ea,0); set_name(ea,"flags");
    #define sysAppLaunchFlagNewThread  0x0001
    #define sysAppLaunchFlagNewStack   0x0002
    #define sysAppLaunchFlagNewGlobals 0x0004
    #define sysAppLaunchFlagUIApp      0x0008
    #define sysAppLaunchFlagSubCall    0x0010
          cmt = "";
          if ( flags & sysAppLaunchFlagNewThread ) cmt = cmt + "sysAppLaunchFlagNewThread\n";
          if ( flags & sysAppLaunchFlagNewStack  ) cmt = cmt + "sysAppLaunchFlagNewStack\n";
          if ( flags & sysAppLaunchFlagNewGlobals) cmt = cmt + "sysAppLaunchFlagNewGlobals\n";
          if ( flags & sysAppLaunchFlagUIApp     ) cmt = cmt + "sysAppLaunchFlagUIApp\n";
          if ( flags & sysAppLaunchFlagSubCall   ) cmt = cmt + "sysAppLaunchFlagSubCall";
          set_cmt(ea,cmt, 0);
          ea = ea + 2;
          create_dword(ea); op_hex(ea,0); set_name(ea,"stack_size");
          ea = ea + 4;
          create_dword(ea); op_hex(ea,0); set_name(ea,"heap_size");
        }
      }
    }
    
    //-----------------------------------------------------------------------
    //
    //	Create a enumeration with system action codes
    //
    static make_actions()
    {
      auto ename = "SysAppLaunchCmd";
      auto id = get_named_type_tid(ename);
      if ( id == BADADDR )
      {
        auto ei = enum_type_data_t();
        ei.bte = ei.bte | BTE_UDEC;
        ei.add_constant("sysAppLaunchCmdNormalLaunch",         0, "Normal Launch");
        ei.add_constant("sysAppLaunchCmdFind",                 1, "Find string");
        ei.add_constant("sysAppLaunchCmdGoTo",                 2, "Launch and go to a particular record");
        ei.add_constant("sysAppLaunchCmdSyncNotify",           3, "Sent to apps whose databases changed\n"
                                                                  "during HotSync after the sync has\n"
                                                                  "been completed");
        ei.add_constant("sysAppLaunchCmdTimeChange",           4, "The system time has changed");
        ei.add_constant("sysAppLaunchCmdSystemReset",          5, "Sent after System hard resets");
        ei.add_constant("sysAppLaunchCmdAlarmTriggered",       6, "Schedule next alarm");
        ei.add_constant("sysAppLaunchCmdDisplayAlarm",         7, "Display given alarm dialog");
        ei.add_constant("sysAppLaunchCmdCountryChange",        8, "The country has changed");
        ei.add_constant("sysAppLaunchCmdSyncRequest",          9, "The \"HotSync\" button was pressed");
        ei.add_constant("sysAppLaunchCmdSaveData",            10, "Sent to running app before\n"
                                                                  "sysAppLaunchCmdFind or other\n"
                                                                  "action codes that will cause data\n"
                                                                  "searches or manipulation");
        ei.add_constant("sysAppLaunchCmdInitDatabase",        11, "Initialize a database; sent by\n"
                                                                  "DesktopLink server to the app whose\n"
                                                                  "creator ID matches that of the database\n"
                                                                  "created in response to the \"create db\" request");
        ei.add_constant("sysAppLaunchCmdSyncCallApplication", 12, "Used by DesktopLink Server command\n"
                                                                  "\"call application\"");
    
        id = create_enum_type(ename, ei, 0, TYPE_SIGN_NO_SIGN, 0, "Action codes");
      }
    }
    
    //-----------------------------------------------------------------------
    //
    //	Create a enumeration with event codes
    //
    static make_events()
    {
      auto ename = "events";
      auto id = get_named_type_tid(ename);
      if ( id == BADADDR )
      {
        auto ei = enum_type_data_t();
        ei.bte = ei.bte | BTE_UDEC;
        ei.add_constant( "nilEvent",              0);
        ei.add_constant("penDownEvent",           1);
        ei.add_constant("penUpEvent",             2);
        ei.add_constant("penMoveEvent",           3);
        ei.add_constant("keyDownEvent",           4);
        ei.add_constant("winEnterEvent",          5);
        ei.add_constant("winExitEvent",           6);
        ei.add_constant("ctlEnterEvent",          7);
        ei.add_constant("ctlExitEvent",           8);
        ei.add_constant("ctlSelectEvent",         9);
        ei.add_constant("ctlRepeatEvent",        10);
        ei.add_constant("lstEnterEvent",         11);
        ei.add_constant("lstSelectEvent",        12);
        ei.add_constant("lstExitEvent",          13);
        ei.add_constant("popSelectEvent",        14);
        ei.add_constant("fldEnterEvent",         15);
        ei.add_constant("fldHeightChangedEvent", 16);
        ei.add_constant("fldChangedEvent",       17);
        ei.add_constant("tblEnterEvent",         18);
        ei.add_constant("tblSelectEvent",        19);
        ei.add_constant("daySelectEvent",        20);
        ei.add_constant("menuEvent",             21);
        ei.add_constant("appStopEvent",          22);
        ei.add_constant("frmLoadEvent",          23);
        ei.add_constant("frmOpenEvent",          24);
        ei.add_constant("frmGotoEvent",          25);
        ei.add_constant("frmUpdateEvent",        26);
        ei.add_constant("frmSaveEvent",          27);
        ei.add_constant("frmCloseEvent",         28);
        ei.add_constant("tblExitEvent",          29);
        id = create_enum_type(ename, ei, 0, TYPE_SIGN_NO_SIGN, 0, "Event codes");
      }
    }
    
    //-----------------------------------------------------------------------
    static main()
    {
      process_segments();
      make_actions();
      make_events();
    }
    
    //-----------------------------------------------------------------------
    #ifdef __undefined_symbol__
    	// WE DO NOT USE IDC HOTKEYS, JUST SIMPLE KEYBOARD MACROS
    	// (see IDA.CFG, macro Alt-5 for mc68k)
    //-----------------------------------------------------------------------
    //
    //	Register Ctrl-R as a hotkey for "make offset from A5" command
    //	(not used, simple keyboard macro is used instead, see IDA.CFG)
    //
    //	There is another (manual) way to convert an operand to an offset:
    //	  - press Ctrl-R
    //	  - enter "A5BASE"
    //	  - press Enter
    //
    static setup_pilot()
    {
      auto h0,h1;
      h0 = "Alt-1";
      h1 = "Alt-2";
      add_idc_hotkey(h0,"a5offset0");
      add_idc_hotkey(h1,"a5offset1");
      msg("Use %s to convert the first operand to an offset from A5\n",h0);
      msg("Use %s to convert the second operand to an offset from A5\n",h1);
    }
    
    static a5offset0(void) { op_plain_offset(get_screen_ea(),0,get_name_ea_simple("A5BASE")); }
    static a5offset1(void) { op_plain_offset(get_screen_ea(),1,get_name_ea_simple("A5BASE")); }
    
    #endif // 0
    

    renimp

    Script that renames imports.

    /*
       Rename imports.
    
       This script renames entries of a dynamically built import table.
       For example, from a table like this:
    
          dd offset ntdll_NtPowerInformation
          dd offset ntdll_NtInitiatePowerAction
          dd offset ntdll_NtSetThreadExecutionState
          dd offset ntdll_NtRequestWakeupLatency
          dd offset ntdll_NtGetDevicePowerState
          dd offset ntdll_NtIsSystemResumeAutomatic
          dd offset ntdll_NtRequestDeviceWakeup
          dd offset ntdll_NtCancelDeviceWakeupRequest
          dd offset ntdll_RtlQueryRegistryValues
    
    
       it will create a table like this:
    
          NtPowerInformation dd offset ntdll_NtPowerInformation
          NtInitiatePowerAction dd offset ntdll_NtInitiatePowerAction
          NtSetThreadExecutionState dd offset ntdll_NtSetThreadExecutionState
          NtRequestWakeupLatency dd offset ntdll_NtRequestWakeupLatency
          NtGetDevicePowerState dd offset ntdll_NtGetDevicePowerState
          NtIsSystemResumeAutomatic dd offset ntdll_NtIsSystemResumeAutomatic
          NtRequestDeviceWakeup dd offset ntdll_NtRequestDeviceWakeup
          NtCancelDeviceWakeupRequest dd offset ntdll_NtCancelDeviceWakeupRequest
          RtlQueryRegistryValues dd offset ntdll_RtlQueryRegistryValues
    
       Usage: select the import table and run the script.
    
       Known problems: if the dll name contains an underscore, the function
       names might be incorrect. Special care is taken for the ws2_32.dll but
       other dlls will have wrong function names.
    
    */
    
    #include <idc.idc>
    
    static main()
    {
      auto ea1, ea2, idx, dllname, name;
    
      ea1 = read_selection_start();
      ea2 = read_selection_end();
      if ( ea1 == BADADDR )
      {
        warning("Please select the import table before running the renimp script");
        return;
      }
    
      auto ptrsz, DeRef;
      auto bitness = get_segm_attr(ea1, SEGATTR_BITNESS);
      if ( bitness == 1 )
      {
        ptrsz = 4;
        DeRef = get_wide_dword;
      }
      else if ( bitness == 2 )
      {
        ptrsz = 8;
        DeRef = get_qword;
      }
      else
      {
        warning("Unsupported segment bitness!");
        return;
      }
    
      while ( ea1 < ea2 )
      {
        name = Name(DeRef(ea1));
        idx = strstr(name, "_");
        dllname = substr(name, 0, idx);
    
        // Most likely the dll name is ws2_32
        if ( dllname == "ws2" )
          idx = idx + 3;
    
        // Extract the function name
        name = substr(name, idx+1, -1);
        if ( !set_name(ea1, name, SN_CHECK|SN_NOWARN) )
        {
          // failed to give a name - it could be that the name has already been
          // used in the program. add a suffix
          for ( idx=0; idx < 99; idx++ )
          {
            if ( set_name(ea1, name + "_" + ltoa(idx, 10), SN_CHECK|SN_NOWARN) )
              break;
          }
        }
        ea1 = ea1 + ptrsz;
      }
    }
    

    resource

    Sample that demonstrates how new executable format can be analyzed.

    //
    //      This is an example how New Executable Format resources can be
    //      analyzed. In this example we analyze Version Information resource
    //      type only.
    //      It is possible to write functions to analyze other types too.
    //
    //
    
    #include <idc.idc>
    //-------------------------------------------------------------------
    static nextResource(ea) {       // find next resource
      auto next;
      auto name;
    
      next = ea;
      while ( (next=get_next_seg(next)) != -1 ) {
        name = get_segm_name(next);
        if ( substr(name,0,3) == "res" ) break;     // Yes, this is a resource
      }
      return next;
    }
    
    //-------------------------------------------------------------------
    static getResourceType(cmt) {
      auto i;
      i = strstr(cmt,"(");
      if ( i != -1 ) {
        i = i + 1;
        return xtol(substr(cmt,i,i+4));     // get type of the resource
      }
      return 0;                             // couldn't determine rsc type
    }
    
    //-------------------------------------------------------------------
    static getResourceID(cmt) {
      auto i;
      i = strstr(cmt,":");
      if ( i != -1 ) {
        i = i + 1;
        return long(substr(cmt,i,-1));      // get ID of the resource
      }
      return 0;                             // couldn't determine rsc ID
    }
    
    //-------------------------------------------------------------------
    static ResourceCursor(ea,id) {
      msg("Cursor, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceBitmap(ea,id) {
      msg("Bitmap, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceIcon(ea,id) {
      msg("Icon, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceMenu(ea,id) {
      msg("Menu, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceDbox(ea,id) {
      msg("Dbox, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceStrT(ea,id) {
      msg("String Table, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceFontDir(ea,id) {
      msg("FontDir, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceFont(ea,id) {
      msg("Font, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceAccl(ea,id) {
      msg("Accelerator, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceData(ea,id) {
      msg("Resource Data, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceCurDir(ea,id) {
      msg("Cursor Dir, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceIconDir(ea,id) {
      msg("Icon Dir, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceName(ea,id) {
      msg("Cursor, id: %ld\n",id);
    }
    
    //-------------------------------------------------------------------
    static ResourceVersion(ea,id) {
    
      msg("Version info, id: %ld\n",id);
    
      ea = AnalyzeVBlock(ea,0);
    }
    
    //-------------------------------------------------------------------
    static ConvertToStr(vea,len) {
      auto ea;
      auto slen;
      ea = vea;
      for ( ea=vea; len > 0; vea = ea ) {
        while ( get_wide_byte(ea) != 0 ) ea = ea + 1;
        ea = ea + 1;
        slen = ea - vea;
        create_strlit(vea,slen);
        len = len - slen;
      }
    }
    
    //-------------------------------------------------------------------
    static Pad32(ea) {
      auto vea;
      vea = (ea + 3) & ~3;                  // align to 32-bit boundary
      if ( vea != ea ) {                    // extra bytes found
        make_array(ea,vea-ea);
        set_cmt(ea, "Padding bytes", 0);
      }
      return vea;
    }
    
    //-------------------------------------------------------------------
    static AnalyzeVBlock(ea,blnum) {
      auto key,block,vsize,x,vea,keyea;
      auto blstart,blend;
    
      blstart = ea;                         // save block start
    
      block = get_wide_word(ea);
      set_name(ea, sprintf("rscVinfoBlSize_%ld", blnum));
      create_word(ea);
      op_num(ea,0);
    
      ea = ea + 2;
      vsize = get_wide_word(ea);
      set_name(ea, sprintf("rscVinfoValSize_%ld", blnum));
      create_word(ea);
      op_num(ea,0);
    
      ea = ea + 2;
      keyea = ea;
      set_name(key, sprintf("rscVinfoKey_%ld", blnum));
      key = "";
      while ( get_wide_byte(ea) != 0 ) {
        key = key + char(get_wide_byte(ea));
        ea = ea + 1;
      }
      ea = ea + 1;
      create_strlit(keyea,ea-keyea);
    
      vea = Pad32(ea);
    
      set_name(vea, sprintf("rscVinfoValue_%ld", blnum));
    
      blend = vea + vsize;                  // find block end
    
    //  msg("At %lX key is: %s\n",keyea,key);
    
      if      ( key == "VS_VERSION_INFO" ) {
    
            ;       // nothing to do
    
      } else if ( key == "VarFileInfo"     ) {
    
            ;       // nothing to do
    
      } else if ( key == "Translation"     ) {
    
        for ( ea=vea; ea < blend; ea=ea+4 ) {
          auto lang,charset;
    
          lang = get_wide_word(ea);
          charset = get_wide_word(ea+2);
    
            if      ( lang == 0x0401 ) lang = "Arabic";
            else if ( lang == 0x0402 ) lang = "Bulgarian";
            else if ( lang == 0x0403 ) lang = "Catalan";
            else if ( lang == 0x0404 ) lang = "Traditional Chinese";
            else if ( lang == 0x0405 ) lang = "Czech";
            else if ( lang == 0x0406 ) lang = "Danish";
            else if ( lang == 0x0407 ) lang = "German";
            else if ( lang == 0x0408 ) lang = "Greek";
            else if ( lang == 0x0409 ) lang = "U.S. English";
            else if ( lang == 0x040A ) lang = "Castilian Spanish";
            else if ( lang == 0x040B ) lang = "Finnish";
            else if ( lang == 0x040C ) lang = "French";
            else if ( lang == 0x040D ) lang = "Hebrew";
            else if ( lang == 0x040E ) lang = "Hungarian";
            else if ( lang == 0x040F ) lang = "Icelandic";
            else if ( lang == 0x0410 ) lang = "Italian";
            else if ( lang == 0x0411 ) lang = "Japanese";
            else if ( lang == 0x0412 ) lang = "Korean";
            else if ( lang == 0x0413 ) lang = "Dutch";
            else if ( lang == 0x0414 ) lang = "Norwegian - Bokmal";
            else if ( lang == 0x0415 ) lang = "Polish";
            else if ( lang == 0x0416 ) lang = "Brazilian Portuguese";
            else if ( lang == 0x0417 ) lang = "Rhaeto-Romanic";
            else if ( lang == 0x0418 ) lang = "Romanian";
            else if ( lang == 0x0419 ) lang = "Russian";
            else if ( lang == 0x041A ) lang = "Croato-Serbian (Latin)";
            else if ( lang == 0x041B ) lang = "Slovak";
            else if ( lang == 0x041C ) lang = "Albanian";
            else if ( lang == 0x041D ) lang = "Swedish";
            else if ( lang == 0x041E ) lang = "Thai";
            else if ( lang == 0x041F ) lang = "Turkish";
            else if ( lang == 0x0420 ) lang = "Urdu";
            else if ( lang == 0x0421 ) lang = "Bahasa";
            else if ( lang == 0x0804 ) lang = "Simplified Chinese";
            else if ( lang == 0x0807 ) lang = "Swiss German";
            else if ( lang == 0x0809 ) lang = "U.K. English";
            else if ( lang == 0x080A ) lang = "Mexican Spanish";
            else if ( lang == 0x080C ) lang = "Belgian French";
            else if ( lang == 0x0810 ) lang = "Swiss Italian";
            else if ( lang == 0x0813 ) lang = "Belgian Dutch";
            else if ( lang == 0x0814 ) lang = "Norwegian - Nynorsk";
            else if ( lang == 0x0816 ) lang = "Portuguese";
            else if ( lang == 0x081A ) lang = "Serbo-Croatian (Cyrillic)";
            else if ( lang == 0x0C0C ) lang = "Canadian French";
            else if ( lang == 0x100C ) lang = "Swiss French";
    
            if      ( charset == 0    ) charset = "7-bit ASCII";
            else if ( charset == 932  ) charset = "Windows, Japan (Shift - JIS X-0208)";
            else if ( charset == 949  ) charset = "Windows, Korea (Shift - KSC 5601)";
            else if ( charset == 950  ) charset = "Windows, Taiwan (GB5)";
            else if ( charset == 1200 ) charset = "Unicode";
            else if ( charset == 1250 ) charset = "Windows, Latin-2 (Eastern European)";
            else if ( charset == 1251 ) charset = "Windows, Cyrillic";
            else if ( charset == 1252 ) charset = "Windows, Multilingual";
            else if ( charset == 1253 ) charset = "Windows, Greek";
            else if ( charset == 1254 ) charset = "Windows, Turkish";
            else if ( charset == 1255 ) charset = "Windows, Hebrew";
            else if ( charset == 1256 ) charset = "Windows, Arabic";
    
            set_cmt(ea, "Language: " + lang, 0);
            create_word(ea);
            op_num(ea,0);
            set_cmt(ea+2, "Character set: " + charset, 0);
            create_word(ea+2);
            op_num(ea+2,0);
    
        }
      } else if ( key == "StringFileInfo"  ) {
    
            ConvertToStr(vea,vsize);
    
      } else {
            ConvertToStr(vea,vsize);
      }
    
      blend = Pad32(blend);
      update_extra_cmt(blend,E_NEXT + 0,";------------------------------------------------------");
      blnum = (blnum+1) * 10;               // nested block number
      while ( (blend-blstart) < block ) {   // nested block exist
        msg("Nested block at %lX\n",blend);
        set_cmt(blend, sprintf("Nested block...%ld",blnum), 0);
        blend = AnalyzeVBlock(blend,blnum);
        blnum = blnum + 1;
      }
      return blend;
    }
    
    //-------------------------------------------------------------------
    static main(void) {
      auto ea;
      auto type,id;
    
      msg("Searching for resources...\n");
      ea = get_first_seg();
      while ( (ea=nextResource(ea)) != -1 ) {
        msg("Found a resource at %08lX, name: %s\n",ea,get_segm_name(ea));
        type = getResourceType(get_extra_cmt(ea,E_PREV + 0));        // get rsc type
        id   = getResourceID(get_extra_cmt(ea,E_PREV + 3));          // get rsc id
        if      ( type == 0x8001 )  ResourceCursor(ea,id);
        else if ( type == 0x8002 )  ResourceBitmap(ea,id);
        else if ( type == 0x8003 )  ResourceIcon(ea,id);
        else if ( type == 0x8004 )  ResourceMenu(ea,id);
        else if ( type == 0x8005 )  ResourceDbox(ea,id);
        else if ( type == 0x8006 )  ResourceStrT(ea,id);
        else if ( type == 0x8007 )  ResourceFontDir(ea,id);
        else if ( type == 0x8008 )  ResourceFont(ea,id);
        else if ( type == 0x8009 )  ResourceAccl(ea,id);
        else if ( type == 0x800A )  ResourceData(ea,id);
    
        else if ( type == 0x800C )  ResourceCurDir(ea,id);
    
        else if ( type == 0x800E )  ResourceIconDir(ea,id);
        else if ( type == 0x800F )  ResourceName(ea,id);
        else if ( type == 0x8010 )  ResourceVersion(ea,id);
        else msg("Unknown resource type %04lX\n",type);
      }
      msg("Done.\n");
    }
    

    struct2

    Sample that demonstrates structure manipulation functions.

    //
    //      This example shows how to use structure manipulation functions.
    //
    
    #include <idc.idc>
    
    #define MAXSTRUCT       200
    
    // Create MAXSTRUT structures.
    // Each structure will have 3 fields:
    //      - a byte array field
    //      - a word field
    //      - a structure field
    
    static main()
    {
      auto i, idx, name, id2;
    
      for ( i=0; i < MAXSTRUCT; i++ )
      {
        name = sprintf("str_%03d", i);
        idx = add_struc(-1, name, 0);               // create a structure
        if ( idx == -1 )                            // if not ok
        {
          warning("Can't create structure %s, giving up",name);
          break;
        }
        else
        {
          add_struc_member(idx,
                         "bytemem",
                         get_struc_size(idx),
                         FF_DATA|FF_BYTE,
                         -1,
                         5*1);                      // char[5]
          add_struc_member(idx,
                         "wordmem",
                         get_struc_size(idx),
                         FF_DATA|FF_WORD,
                         -1,
                         1*2);                      // short
          id2 = get_struc_id(sprintf("str_%03d",i-1));
          if ( i != 0 ) add_struc_member(idx,
                         "inner",
                         get_struc_size(idx),
                         FF_DATA|FF_STRUCT,
                         id2,
                         get_struc_size(id2));        // sizeof(str_...)
          msg("Structure %s is successfully created, idx=%08lX, prev=%08lX\n",
                                                            name, idx, id2);
        }
      }
      msg("Done, total number of structures: %d\n",get_struc_qty());
    }
    

    structst

    Sample that demonstrates structure access functions.

    //
    //      This example shows how to use structure access functions.
    //
    
    #include <idc.idc>
    
    // Create a simple structure
    // dump layout of all structures (including the created one)
    // dump current function's frame (if it exists)
    
    
    static dump_struct(id)
    {
      auto m;
      msg("Structure %s (id 0x%X):\n",get_struc_name(id), id);
      msg("  Regular    comment: %s\n",get_struc_cmt(id,0));
      msg("  Repeatable comment: %s\n",get_struc_cmt(id,1));
      msg("  Size              : %d\n",get_struc_size(id));
      msg("  Number of members : %d\n",get_member_qty(id));
      for ( m = 0;
            m != get_struc_size(id);
            m = get_next_offset(id,m) ) 
      {
        auto mname;
        mname = get_member_name(id,m);
        if ( mname == "" ) 
        {
          msg("  Hole (%d bytes)\n",get_next_offset(id,m)-m);
        } 
        else 
        {
          auto type;
          msg("  Member name   : %s\n",get_member_name(id,m));
          msg("    Regular cmt : %s\n",get_member_cmt(id,m,0));
          msg("    Rept.   cmt : %s\n",get_member_cmt(id,m,1));
          msg("    Member size : %d\n",get_member_size(id,m));
          type = get_member_flag(id,m) & DT_TYPE;
               if ( type == FF_BYTE     ) type = "Byte";
          else if ( type == FF_WORD     ) type = "Word";
          else if ( type == FF_DWORD    ) type = "Double word";
          else if ( type == FF_QWORD    ) type = "Quadro word";
          else if ( type == FF_TBYTE    ) type = "Ten bytes";
          else if ( type == FF_STRLIT   ) type = "ASCII string";
          else if ( type == FF_STRUCT   ) type = sprintf("Structure '%s'",get_struc_name(get_member_strid(id,m)));
          else if ( type == FF_FLOAT    ) type = "Float";
          else if ( type == FF_DOUBLE   ) type = "Double";
          else if ( type == FF_PACKREAL ) type = "Packed Real";
          else                            type = sprintf("Unknown type %08X",type);
          msg("    Member type : %s",type);
          type = get_member_flag(id,m);
               if ( is_off0(type)  ) msg(" Offset");
          else if ( is_char0(type) ) msg(" Character");
          else if ( is_seg0(type)  ) msg(" Segment");
          else if ( is_dec0(type)  ) msg(" Decimal");
          else if ( is_hex0(type)  ) msg(" Hex");
          else if ( is_oct0(type)  ) msg(" Octal");
          else if ( is_bin0(type)  ) msg(" Binary");
          msg("\n");
        }
      }
    }
    
    static main() {
      auto idx,code;
    
      idx = add_struc(-1, "str1_t", 0);     // create a structure
      if ( idx != -1 ) {                    // if ok
        auto id2;
            // add member: offset from struct start 0, type - byte, 5 elements
        add_struc_member(idx,"bytemem",0,FF_DATA|FF_BYTE,-1,5*1);
        add_struc_member(idx,"wordmem",5,FF_DATA|FF_WORD,-1,1*2);
        set_member_cmt(idx,0,"This is 5 element byte array",0);
        set_member_cmt(idx,5,"This is 1 word",0);
        id2 = add_struc(-1, "str2_t", 0); // create another structure
        add_struc_member(id2,"first", 0,FF_DATA|FF_BYTE,-1,1*1);
        add_struc_member(id2,"strmem",1,FF_DATA|FF_STRUCT,idx,get_struc_size(idx));
        set_member_cmt(id2,1,"This is structure member",0);
      }
    
      msg("Total number of structures: %d\n",get_struc_qty());
      auto id;
      for ( idx=get_first_struc_idx(); idx != -1; idx=get_next_struc_idx(idx) ) {
        id = get_struc_by_idx(idx);
        if ( id == -1 ) error("Internal IDA error, get_struc_by_idx returned -1!");
        dump_struct(id);
      }
      // dump current function's stack frame
      id = get_func_attr(here, FUNCATTR_FRAME);
      if ( id != -1 )
      {
        msg("current function frame layout:\n");
        dump_struct(id);
      }
    }
    

    tpdll

    Example executed when IDA detects Turbo Pascal DLL.

    //
    // This file is executed when IDA detects Turbo Pascal DLL
    //
    
    #include <idc.idc>
    
    static main()
    {
      // Set pascal type strings. Just in case
      set_inf_attr(INF_STRTYPE, STRTYPE_PASCAL);
    
      // System unit used protected commands so
      // set protected mode processor
      set_processor_type("80386p", SETPROC_USER);
    
      auto start = get_inf_attr(INF_START_EA);
    
      // Give pascal style name to the entry point
      // and delete the bogus one-instruction function
      // which was created by the startup signature
      set_name(start, "LIBRARY");
      del_func(start);
    
      // Plan to create a good PROGRAM function instead of
      // the deleted one
      auto_mark_range(start, start+1, AU_PROC);
    
      // Get address of the initialization subrountine
      auto init = get_first_fcref_from(start+5);
      set_name(init, "@__SystemInit$qv");
    
      // Delete the bogus function which was created by the secondary
      // startup signature.
      del_func(init);
    
      // Create a good initialization function
      add_func(init);
      set_func_flags(init, FUNC_LIB|get_func_flags(init));
    
      // Check for presence of LibExit() function
      auto exit = get_name_ea_simple("@__LibExit$qv");
    
      // If we have found function then define it
      // with FUNC_NORET attribute
      if ( exit != BADADDR )
      {
        add_func(exit);
        set_func_flags(exit, FUNC_NORET|FUNC_LIB|get_func_flags(exit));
      }
    }
    

    tpdos

    Example executed when IDA detects Turbo Pascal DOS app.

    //
    // This file is executed when IDA detects Turbo Pascal DOS application.
    //
    
    #include <idc.idc>
    
    static main()
    {
      // Set pascal type strings. Just in case
      set_inf_attr(INF_STRTYPE, STRTYPE_PASCAL);
    
      auto start = get_inf_attr(INF_START_EA);
    
      // Give pascal style name to the entry point
      // and delete the bogus one-instruction function
      // which was created by the startup signature
      set_name(start,"PROGRAM");
      del_func(start);
    
      // Plan to create a good PROGRAM function instead of
      // the deleted one
      auto_mark_range(start, start+1, AU_PROC);
    
      // Get address of the initialization subrountine
      auto init = get_first_fcref_from(start);
      set_name(init, "@__SystemInit$qv");
    
      // Delete the bogus function which was created by the secondary
      // startup signature.
      del_func(init);
    
      // Create a good initialization function
      add_func(init);
      set_func_flags(init, FUNC_LIB|get_func_flags(init));
    
      // find sequence of
      //      xor     cx, cx
      //      xor     bx, bx
      // usually Halt() starts with these instructions
    
      auto halt = find_binary(init,1,"33 c9 33 db");
    
      // If we have found the sequence then define Halt() function
      // with FUNC_NORET attribute
      if ( halt != BADADDR )
      {
        set_name(halt, "@Halt$q4Word");
        add_func(halt);
        set_func_flags(halt, FUNC_NORET|FUNC_LIB|get_func_flags(halt));
      }
    }
    

    tpne

    Example executed when IDA detects Windows or DPMI app.

    //
    // This file is executed when IDA detects Turbo Pascal Windows
    // or DPMI application.
    //
    
    #include <idc.idc>
    
    static main()
    {
      // Set pascal type strings. Just in case
      set_inf_attr(INF_STRTYPE, STRTYPE_PASCAL);
    
      // System unit used protected commands so
      // set protected mode processor
      set_processor_type("80386p", SETPROC_USER);
    
      auto start = get_inf_attr(INF_START_EA);
    
      // Give pascal style name to the entry point
      // and delete the bogus one-instruction function
      // which was created by the startup signature
      set_name(start, "PROGRAM");
      del_func(start);
    
      // Plan to create a good PROGRAM function instead of
      // the deleted one
      auto_mark_range(start, start+1, AU_PROC);
    
      // Get address of the initialization subrountine
      auto init = get_first_fcref_from(start+5);
      set_name(init, "@__SystemInit$qv");
    
      // Delete the bogus function which was created by the secondary
      // startup signature.
      del_func(init);
    
      // find sequence of
      //      xor     cx, cx
      //      xor     bx, bx
      // usually Halt() starts with these instructions
    
      auto halt = find_binary(init, 1, "33 c9 33 db");
    
      // If we have found the sequence then define Halt() function
      // with FUNC_NORET attribute
      if ( halt != BADADDR )
      {
        set_name(halt, "@Halt$q4Word");
        add_func(halt);
        set_func_flags(halt, FUNC_NORET|FUNC_LIB|get_func_flags(halt));
      }
    
      // Create a good initialization function
      add_func(init);
      set_func_flags(init, FUNC_LIB|get_func_flags(init));
    }
    

    xrefs

    Example shows how to use cross-reference related functions.

    //
    //
    //      This example shows how to use cross-reference related functions.
    //      It displays xrefs to the current location.
    //
    
    #include <idc.idc>
    
    static main() {
      auto ea,flag,x,y;
      flag = 1;
      ea = get_screen_ea();
    
    //  add_dref(ea,ea1,dr_R);         // set data reference (read)
    //  add_cref(ea,ea1,fl_CN);          // set 'call near' reference
    //  del_cref(ea,ea1,1);
    
    //
    //      Now show all reference relations between ea & ea1.
    //
      msg("\n*** Code references from " + atoa(ea) + "\n");
      for ( x=get_first_cref_from(ea); x != BADADDR; x=get_next_cref_from(ea,x) )
        msg(atoa(ea) + " refers to " + atoa(x) + xrefchar() + "\n");
    
      msg("\n*** Code references to " + atoa(ea) + "\n");
      x = ea;
      for ( y=get_first_cref_to(x); y != BADADDR; y=get_next_cref_to(x,y) )
        msg(atoa(x) + " is referred from " + atoa(y) + xrefchar() + "\n");
    
      msg("\n*** Code references from " + atoa(ea) + " (only non-trivial refs)\n");
      for ( x=get_first_fcref_from(ea); x != BADADDR; x=get_next_fcref_from(ea,x) )
        msg(atoa(ea) + " refers to " + atoa(x) + xrefchar() + "\n");
    
      msg("\n*** Code references to " + atoa(ea) + " (only non-trivial refs)\n");
      x = ea;
      for ( y=get_first_fcref_to(x); y != BADADDR; y=get_next_fcref_to(x,y) )
        msg(atoa(x) + " is referred from " + atoa(y) + xrefchar() + "\n");
    
      msg("\n*** Data references from " + atoa(ea) + "\n");
      for ( x=get_first_dref_from(ea); x != BADADDR; x=get_next_dref_from(ea,x) )
        msg(atoa(ea) + " accesses " + atoa(x) + xrefchar() + "\n");
    
      msg("\n*** Data references to " + atoa(ea) + "\n");
      x = ea;
      for ( y=get_first_dref_to(x); y != BADADDR; y=get_next_dref_to(x,y) )
        msg(atoa(x) + " is accessed from " + atoa(y) + xrefchar() + "\n");
    
    }
    
    static xrefchar()
    {
      auto x, is_user;
      x = get_xref_type();
    
      is_user = (x & XREF_USER) ? ", user defined)" : ")";
    
      if ( x == fl_F )  return " (ordinary flow" + is_user;
      if ( x == fl_CF ) return " (call far"      + is_user;
      if ( x == fl_CN ) return " (call near"     + is_user;
      if ( x == fl_JF ) return " (jump far"      + is_user;
      if ( x == fl_JN ) return " (jump near"     + is_user;
      if ( x == dr_O  ) return " (offset"        + is_user;
      if ( x == dr_W  ) return " (write)"        + is_user;
      if ( x == dr_R  ) return " (read"          + is_user;
      if ( x == dr_T  ) return " (textual"       + is_user;
      return "(?)";
    }
    

    Other sample scripts

    Batch analysis

    This program forces the IDA Disassembler in “batch” analysis mode if it is started in the following way : ida -Sanalysis.idc file.

    static main() {
      auto x,y;
    
      Message("Waiting for the end of auto analys...\n");
      Wait();
    
      x = SegStart(BeginEA());
      y = SegEnd(BeginEA());
      Message("Analysing area %08X - %08X...\n",x,y);
      AnalyseArea(x,y);
      Wait();		// wait for code segment analysis to finish
    
      Message("\n\n------ Creating output file.... --------\n");
      WriteTxt("ida.out",0,0xFFFFFFFF);
      Message("All done, exiting...\n");
      Exit(0);				// exit to OS, error code 0 - success
    }
    

    Device driver analysis

    This program is automatically executed when a new device driver is loaded.

    //
    //      This file is executed when a new device driver is loaded.
    //              Device drivers have extensions DRV or SYS.
    //
    
    #include <idc.idc>
    
    static main(void) {
      auto x,i,base;
      auto intr,strt;
      auto attr,cmt;
      auto nextbase;
      auto DevReq;
    
      i = 0;
      x = MinEA();
      base = (x >> 4);   // The segment base
    
      while ( 1 ) {
        Message("Device driver block at %04X\n",x);
    
        MakeName(x,form("NextDevice_%ld",i));
        MakeWord(x);
        OpNumber(x,0);
        if ( Word(x) == 0xFFFF ) {
          MakeComm(x,"The last device");
        } else {
          nextbase = base + Word(x+2);
          OpOff(x,0,[nextbase,0]);
          MakeComm(x,"Offset to the next device");
        }
    
        MakeWord(x+2);
        OpNumber(x+2,0);
    
        MakeName(x+4,form("DevAttr_%ld",i));
        MakeWord(x+4);
        OpNumber(x+4,0);
        attr = Word(x+4);
        cmt = "";
        if ( attr & (132M\n");
        if ( attr & (1 Device Request Block");
        MakeComm( intr, "Device Request Block:\n"
              "0 db length\n"
          "1 db unit number\n"
          "2 db command code\n"
          "5 d? reserved\n"
          "0D d? command specific data");
    
        if( Byte( strt )==0x2E && Word(strt+1)==0x1E89
         && Byte(strt+5)==0x2E && Word(strt+6)==0x068C
         && Word(strt+3)==Word(strt+8)-2)
        {
         DevReq=Word(strt+3);
         Message("DevReq at %x\n",DevReq);
         MakeUnkn(x+DevReq,0);MakeUnkn(x+DevReq+2,0);
         MakeDword(x+DevReq);MakeName(x+DevReq,form("DevRequest_%ld",i));
        }
    
        if ( Word(x) == 0xFFFF ||
           ((Byte(x)==0xE9 || Byte(x)==0xEB) && i==0) ) break;
        if ( Dword(x) == 0 ) break;	// 04.01.96
        x = [ nextbase, Word(x) ];
        i = i + 1;
      }
    }
              
    

    New file format definition

    //
    //	This is an example how New Executable Format resources can be
    //	analysed. In this example we analyse Version Information resource
    //      type only.
    
    //-------------------------------------------------------------------
    static nextResource(ea) {	// find next resource
      auto next;
      auto name;
    
      next = ea;
      while ( (next=NextSeg(next)) != -1 ) {
        name = SegName(next);
        if ( substr(name,0,3) == "res" ) break;	// Yes, this is a resource
      }
      return next;
    }
    
    //-------------------------------------------------------------------
    static getResourceType(cmt) {
      auto i;
      i = strstr(cmt,"(");
      if ( i != -1 ) {
        i = i + 1;
        return xtol(substr(cmt,i,i+4));	// get type of the resource
      }
      return 0;				// couldn't determine rsc type
    }
    
    //-------------------------------------------------------------------
    static getResourceID(cmt) {
      auto i;
      i = strstr(cmt,":");
      if ( i != -1 ) {
        i = i + 1;
        return long(substr(cmt,i,-1));	// get ID of the resource
      }
      return 0;				// couldn't determine rsc ID
    }
    
    //-------------------------------------------------------------------
    static ResourceCursor(ea,id) {
      Message(form("Cursor, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceBitmap(ea,id) {
      Message(form("Bitmap, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceIcon(ea,id) {
      Message(form("Icon, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceMenu(ea,id) {
      Message(form("Menu, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceDbox(ea,id) {
      Message(form("Dbox, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceStrT(ea,id) {
      Message(form("String Table, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceFontDir(ea,id) {
      Message(form("FontDir, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceFont(ea,id) {
      Message(form("Font, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceAccl(ea,id) {
      Message(form("Accelerator, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceData(ea,id) {
      Message(form("Resource Data, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceCurDir(ea,id) {
      Message(form("Cursor Dir, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceIconDir(ea,id) {
      Message(form("Icon Dir, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceName(ea,id) {
      Message(form("Cursor, id: %ld\n",id));
    }
    
    //-------------------------------------------------------------------
    static ResourceVersion(ea,id) {
    
      Message(form("Version info, id: %ld\n",id));
    
      ea = AnalyseVBlock(ea,0);
    }
    
    //-------------------------------------------------------------------
    static ConvertToStr(vea,len) {
      auto ea;
      auto slen;
      ea = vea;
      for ( ea=vea; len > 0; vea = ea ) {
        while ( Byte(ea) != 0 ) ea = ea + 1;
        ea = ea + 1;
        slen = ea - vea;
        MakeStr(vea,slen);
        len = len - slen;
      }
    }
    
    //-------------------------------------------------------------------
    static Pad32(ea) {
      auto vea;
      vea = (ea + 3) & ~3;			// align to 32-bit boundary
      if ( vea != ea ) {			// extra bytes found
        MakeArray(ea,vea-ea);
        MakeComm(ea,"Padding bytes");
      }
      return vea;
    }
    
    //-------------------------------------------------------------------
    static AnalyseVBlock(ea,blnum) {
      auto key,block,vsize,x,vea,keyea;
      auto blstart,blend;
    
      blstart = ea;				// save block start
    
      block = Word(ea);
      MakeName(ea,form("rscVinfoBlSize_%ld",blnum));
      MakeWord(ea);
      OpNumber(ea,0);
    
      ea = ea + 2;
      vsize = Word(ea);
      MakeName(ea,form("rscVinfoValSize_%ld",blnum));
      MakeWord(ea);
      OpNumber(ea,0);
    
      ea = ea + 2;
      keyea = ea;
      MakeName(key,form("rscVinfoKey_%ld",blnum));
      key = "";
      while ( Byte(ea) != 0 ) {
        key = key + char(Byte(ea));
        ea = ea + 1;
      }
      ea = ea + 1;
      MakeStr(keyea,ea-keyea);
    
      vea = Pad32(ea);
    
      MakeName(vea, form("rscVinfoValue_%ld",blnum));
    
      blend = vea + vsize;			// find block end
    
    //  Message(form("At %lX key is: ",keyea) + key + "\n");
    
      if      ( key == "VS_VERSION_INFO" ) {
    
      	;	// nothing to do
    
      } else if ( key == "VarFileInfo"     ) {
    
      	;	// nothing to do
    
      } else if ( key == "Translation"     ) {
    
        for ( ea=vea; ea 
            
    

    Structures manipulation

    This program demonstrates basic structure manipulation.

    #include <idc.idc>
    
    static main() {
      auto idx;
    
      for ( idx=GetFirstStrucIdx(); idx != -1; idx=GetNextStrucIdx(idx) ) {
        auto id,m;
        id = GetStrucId(idx);
        if ( id == -1 ) Fatal("Internal IDA error, GetStrucId returned -1!");
        Message("Structure %s:\n",GetStrucName(id));
        Message("  Regular    comment: %s\n",GetStrucComment(id,0));
        Message("  Repeatable comment: %s\n",GetStrucComment(id,1));
        Message("  Size              : %d\n",GetStrucSize(id));
        Message("  Number of members : %d\n",GetMemberQty(id));
        for ( m = 0;
    	  m != GetStrucSize(id);
    	  m = GetStrucNextOff(id,m) ) {
          auto mname;
          mname = GetMemberName(id,m);
          if ( mname == "" ) {
            Message("  Hole (%d bytes)\n",GetStrucNextOff(id,m)-m);
          } else {
            auto type;
            Message("  Member name   : %s\n",GetMemberName(id,m));
            Message("    Regular cmt : %s\n",GetMemberComment(id,m,0));
            Message("    Rept.   cmt : %s\n",GetMemberComment(id,m,1));
            Message("    Member size : %d\n",GetMemberSize(id,m));
    	type = GetMemberFlag(id,m) & DT_TYPE;
    	     if ( type == FF_BYTE     ) type = "Byte";
    	else if ( type == FF_WORD     ) type = "Word";
    	else if ( type == FF_DWRD     ) type = "Double word";
    	else if ( type == FF_QWRD     ) type = "Quadro word";
    	else if ( type == FF_TBYT     ) type = "Ten bytes";
    	else if ( type == FF_ASCI     ) type = "ASCII string";
    	else if ( type == FF_STRU     ) type = form("Structure '%s'",GetStrucName(GetMemberStrId(id,m)));
    	else if ( type == FF_XTRN     ) type = "Unknown external?!"; // should not happen
    	else if ( type == FF_FLOAT    ) type = "Float";
    	else if ( type == FF_DOUBLE   ) type = "Double";
    	else if ( type == FF_PACKREAL ) type = "Packed Real";
    	else				type = form("Unknown type %08X",type);
    	Message("    Member type : %s",type);
    	type = GetMemberFlag(id,m);
    	     if ( isOff0(type)  ) Message(" Offset");
    	else if ( isChar0(type) ) Message(" Character");
    	else if ( isSeg0(type)  ) Message(" Segment");
    	else if ( isDec0(type)  ) Message(" Decimal");
    	else if ( isHex0(type)  ) Message(" Hex");
    	else if ( isOct0(type)  ) Message(" Octal");
    	else if ( isBin0(type)  ) Message(" Binary");
    	Message("\n");
          }
        }
      }
      Message("Total number of structures: %d\n",GetStrucQty());
    }
    

    VxD analysis

    This program is automatically executed when a new VxD is loaded.

    static Describe(ddb,i) {
      auto next,x,y;
    
      x = ddb;
      MakeDword(x);
      MakeComm (x,form("Next_%ld",i));
      next = Dword(x);
      if ( next != 0 ) OpOffset(x,0);
      x = x + 4;
    
      MakeWord(x);
      MakeName(x,form("SDK_Version_%ld",i));
      OpNum   (x);
      x = x + 2;
    
      MakeWord(x);
      MakeName(x,form("Req_Device_Number_%ld",i));
      OpNum   (x);
      x = x + 2;
    
      MakeByte(x);
      MakeName(x,form("Dev_Major_Version_%ld",i));
      OpNum(x);
      MakeComm(x,"Major device number");
      x = x + 1;
    
      MakeByte(x);
      MakeName(x,form("Dev_Minor_Version_%ld",i));
      OpNum   (x);
      MakeComm(x,"Minor device number");
      x = x + 1;
    
      MakeWord(x);
      MakeName(x,form("Flags_%ld",i));
      OpNum   (x);
      MakeComm(x,"Flags for init calls complete");
      x = x + 2;
    
      MakeStr (x,8);
      MakeName(x,form("Name_%ld",i));
      MakeComm(x,"Device name");
      x = x + 8;
    
      MakeDword(x);
      MakeName(x,form("Init_Order_%ld",i));
      OpNum   (x);
      MakeComm(x,"Initialization Order");
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("Control_Proc_%ld",i));
      OpOffset(x,0);
      MakeComm(x,"Offset of control procedure");
      MakeCode( Dword(x) );
      MakeName( Dword(x), form("Control_%ld",i) );
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("V86_API_Proc_%ld",i));
      MakeComm(x,"Offset of API procedure (or 0)");
      y = Dword(x);
      if ( y != 0 ) {
        OpOffset(x,0);
        MakeCode( y );
        MakeName( y, form("V86_%ld",i) );
      }
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("PM_API_Proc_%ld",i));
      MakeComm(x,"Offset of API procedure (or 0)");
      y = Dword(x);
      if ( y != 0 ) {
        OpOffset(x,0);
        MakeCode( y );
        MakeName( y, form("PM_%ld",i) );
      }
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("V86_API_CSIP_%ld",i));
      MakeComm(x,"CS:IP of API entry point");
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("PM_API_CSIP_%ld",i));
      MakeComm(x,"CS:IP of API entry point");
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("Reference_Data_%ld",i));
      MakeComm(x,"Reference data from real mode");
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("Service_Table_Ptr_%ld",i));
      MakeComm(x,"Pointer to service table");
      y = Dword(x);
      if ( y != 0 ) {
        OpOffset(x,0);
        MakeName( y, form("Service_Table_%ld",i) );
        MakeDword(y);
        MakeArray( y, Dword(x+4) );
      }
      x = x + 4;
    
      MakeDword(x);
      MakeName(x,form("Service_Size_%ld",i));
      MakeComm(x,"Number of services");
      x = x + 4;
    
      return next;
    }
    
    //-----------------------------------------------------------------------
    static main() {
      auto ea;
      auto i;
    
      i  = 0;
      ea = ScreenEA();
      while ( GetFlags(ea) != 0 ) {	// While ea points to valid address
        ea = Describe(ea,i);
        if ( ea == 0 ) break;
        i = i + 1;
      }
    }
    

    Analyzing encrypted code

    This small tutorial demonstrates how to use IDC to decrypt part of a program at analysis time. The sample file is a portion of the Ripper virus.

    1st step

    The binary image of the virus is loaded into IDA and analysis is started at the entry point

    Obviously, the bytes right after the call don’t make sense, but the call gives us a clue: it is a decryption routine.

    2nd step

    We create a small IDC program that mimicks the decryption routine.

    static decrypt(from, size, key ) {
      auto i, x;           // we define the variables
      for ( i=0; i < size; i=i+1 ) { 
        x = Byte(from);    // fetch the byte
        x = (x^key);       // decrypt it
        PatchByte(from,x); // put it back
        from = from + 1;   // next byte
      } 
    }
                
    

    Save it on disk and press F2 to load it into IDA’s interpreter.

    3rd step

    Then, we press shift-F2 to call it with the appropriate values. Please note the linear address used for the starting point. Pressing OK executes the statement.

    The bytes are now decrypted

    4th step

    We move the cursor to offset 0x50 and press C to inform IDA that there is now code at that location.

    And the code to allocate memory for the virus appears, along with a rather impolite message… The analysis may now resume.

    Admin Guide

    Welcome to the Hex-Rays Admin Guide, designed to support system administrators in managing and configuring servers for IDA add-ons and floating licenses. Inside, you’ll find in-depth guides for:

    Command-Line Administration with HCLI

    For administrators managing multiple IDA licenses and installations, HCLI provides an extensible command-line interface to automate routine administrative tasks.

    HCLI Resources

    Teams server Check how to install and manage Teams server to streamline collaborative work.
    Private Lumina server Discover how to set up and maintain your on-premises Lumina server.
    Floating licenses server Get guidance on installing and managing the floating license server to efficiently handle users access to IDA.
    HCLI Documentationhttps://hcli.docs.hex-rays.com/
    HCLI Source Code on GitHub https://github.com/HexRaysSA/ida-hcli
    HCLI IDA GitHub Actionhttps://github.com/HexRaysSA/ida-hcli-actions

    IDA Pro Lumina server Admin Guide

    Introduction

    This manual describes the installation, management, and interaction with an on-the-premises IDA Pro Lumina server.

    It is primarily intended for administrators, and will focus on the Lumina server component, that can be purchased for IDA Pro.

    While we will (at least superficially) make use of the lc command-line client that is used to access/manage the server, this manual will not offer a detailed explanation of its usage: that is the role of the lc user manual.

    We recommend having the lc user manual ready before starting the installation and configuration of the Lumina server.

    Prerequisites

    After your purchase of Lumina server, go to the customer portal, where you will find an installer for the Lumina server. Please go ahead and download it.

    Quick alternative {% hint style=“success” %}

    HCLI Commands | See HCLI Docs

    • hcli license get
    • hcli download {% endhint %}

    You will also need root access on the host where you will be installing the Lumina server (to install the server, not to run it).

    MySQL server

    The Lumina server stores its data in a MySQL DBMS server. It is therefore necessary to have valid credentials to such a server, as well as a fresh, empty database.

    NOTE: The Lumina server requires a MySQL server version 5.8 or newer.

    For illustration purposes, let’s assume the MySQL database the server will use, is called: "lumina_db".

    Installation

    At installation-time, the Lumina server installer will need information about the MySQL instance the Lumina server will be using (host, port, username, password). Eventually, that information will end up in the lumina.conf file, sitting next to the lumina_server binary:

    CONNSTR="mysql;Server=127.0.0.1;Port=3306;Database=lumina_db;Uid=lumina;Pwd=<snipped>"
    

    Installation in a Teams setup

    When Lumina is installed in a Teams setup, in addition to information about the MySQL database in which the Lumina server will store the metadata, the installer asks for the host+port pair where to find a running Hex-Rays Vault server to which user authentication will be delegated.

    That information will also end up in the lumina.conf file:

    VAULT_HOST="vault.acme.com:65433"
    

    Supported platforms

    The Lumina server can be installed on Linux servers. We have tested it on Debian and Ubuntu, but other major flavors of Linux should be fine too.

    To install the server, run the Lumina installer as root and follow the instructions (the server will not require root permissions; only the installer does.)

    NOTE: If your Linux system is based on systemd (e.g., Debian/Ubuntu, Red-Hat, CentOS, …​), it is recommended to let the installer create systemd units so that the server will start automatically at the next reboot.

    Supported architectures

    Lumina functionality in IDA Pro is currently available only when analyzing binaries compiled for the following architectures:

    • PC (x86/x64)
    • ARM
    • PPC
    • MIPS
    • RISC-V

    If a user loads a binary compiled for an unsupported architecture, the Lumina menu will not appear in IDA Pro and pushing or pulling metadata will not be possible.

    Activating the server license

    In order for the Lumina server license to be activated, it must be bound to a Host ID (an Ethernet MAC address.)

    From a command prompt, run /sbin/ifconfig, and lookup the “ether” address for the network interface through which the server will be accessible.

    >/sbin/ifconfig
    enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            [...snipped...]
            ether bf:e2:91:10:58:d2  txqueuelen 1000  (Ethernet)
            [...snipped...]
    

    In this case, our mac address is: bf:e2:91:10:58:d2

    Go to Hex-Rays customer portal and activate your license for Lumina server. During that process, you will need to provide the MAC address of the device where the Lumina server will be running. Once the activation is complete, you’ll be able to download the following files:

    • lumina server certificate
    • lumina_server_<LID>.hexlic (license key, where LID is your license ID)

    Installing the server license

    Those need to be copied in the Lumina installation directory. As root:

    >cd /opt/lumina
    >cp .../path/to/lumina_server.crt .
    >cp .../path/to/lumina_server.key .
    >cp .../path/to/lumina_server_<LID>.hexlic .
    >chown lumina:lumina lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic
    >chmod 640 lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic
    

    Creating the initial database schema

    At this point, the server should be ready to run.

    NOTE: If your system is already in production and hosts files, skip this section. Using the --recreate-schema option as in the example below, will re-create an empty database and lose all data.

    For the Lumina server to work, it needs to have a proper database schema to work with (at this point, the MySQL database (i.e., "lumina_db") must already exist but is still empty.)

    That is why, on the first install, you will need to initialize the database the server will use as well as specify which user authentication will be used (either lumina or vault, we will use lumina in the example below):

    >sudo -u lumina ./lumina_server --config-file lumina.conf \
                                    --certchain-file lumina_server.crt \
                                    --privkey-file lumina_server.key \
                                    --recreate-schema lumina
    Hex-Rays Lumina Server v8.0 Hex-Rays (c) 2022-2024
    2022-09-02 10:28:30 Database has been initialized; exiting.
    

    If you see “Error: Cannot connect to lumina db” please refer to troubleshooting section.

    Testing the server

    Now that the server is installed and has a database to work with, we can test that it works:

    >sudo -u lumina ./lumina_server --config-file lumina.conf \
                          --certchain-file lumina_server.crt \
                          --privkey-file lumina_server.key
    Hex-Rays Lumina Server v8.0 Hex-Rays (c) 2022-2024
    2022-09-22 12:14:37 Listening on 0.0.0.0:443...
    

    Good, the server appears to run! (If you are observing more worrying messages than this one, please refer to the troubleshooting section.)

    At this point, you may want to either let the server run, or stop it (Ctrl+C will do) and restart it using systemd:

    >systemctl restart lumina.service
    

    …​and make sure it runs:

    >ps aux | grep lumina_server
    lumina  78812  0.0  0.0 ...
    

    or:

    >systemctl status lumina.service
    

    If you don’t see a running lumina_server process or systemctl reports a startup failure, please refer to the systemd diagnostic tools (e.g., journalctl) for more info.

    Initial configuration

    This chapter explains how to perform the initial configuration of the Lumina server, and in particular how to create the first (i.e., “administrator”) user.

    Creating the administrator

    NOTE: The very first user to log into the server becomes the first administrator. S/he can create new administrators and otherwise manage the server.

    Once the server is up and running, login to it using a username and password of your choice using the lc utility.

    NOTE: lc is the Lumina command-line administration client, which comes with the Lumina server installer. We will assume the server has been installed in /opt/lumina/, and thus lc is present in /opt/lumina/lc.

    >cd /opt/lumina
    >./lc -hlumina.acme.com -ualice -psecr3t info
    	Hex-Rays Lumina Server v8.0
    	Lumina time: 2022-09-01 14:28:02, up since 2022-09-01 14:27:58
    	MAC address: <snipped macaddr>
    	Client name: alice *ADMIN*
    	Client host: 127.0.0.1
    

    Since Alice is the first user to login to the server, the credentials she provided, will be used to create the server’s primary administrator.

    You can verify that you are the only user by checking the user list:

    >./lc -hlumina.acme.com -ualice -psecr3t users
    	LastActive          Adm Login License         User name Email
    	------------------- --- ----- --------------- --------- --------------
    	2022-09-01 14:28:04 *   alice AA-A11C-AC8E-01 Alice     [email protected]
    	# Shown 1 results
    

    Useful environment variables

    To facilitate using lc, you may consider defining the following environment variables:

    export LUMINA_HOST=lumina.acme.com
    export LUMINA_USER=alice
    export LUMINA_PASS=secr3t
    

    After that, you can connect to the server effortlessly. For example, this command will print information about the server and the client:

    >./lc info
        Hex-Rays Lumina Server v8.0
        Lumina time: 2022-09-01 14:28:02, up since 2022-09-01 14:27:58
        MAC address: <snipped macaddr>
        Client name: alice *ADMIN*
        Client host: 127.0.0.1
    ...
    

    The lumina server looks up an additional LUMINA_RECV_HELO_TIMEOUT environment variable, which can be used to set the timeout for client login phase (the time between the TLS handshake and the arrival of the first packet). The value is in milliseconds, and setting it to -1 disables the timeout.

    Note that when a client attempts to connect, the lumina server creates a new thread and keeps it running for the entire duration of this timeout. Hence, for publicly exposed lumina servers, it is advised to keep it as short as possible (e.g. 1000 ms).

    Lumina server command-line options

    -p …​ (–port-number …​)Port number (default 443)
    -i …​ (–ip-address …​)IP address to bind to (default to any)
    -c …​ (–certchain-file …​)TLS certificate chain file
    -k …​ (–privkey-file …​)TLS private key file
    -v (–verbose)Verbose mode
    (–recreate-schema [lumina|vault]​)Drop & re-create schema using either lumina or vault user authentication. Note that THIS WILL ERASE ALL DATA
    (–upgrade-schema)Upgrade database schema; then quit. Only necessary when upgrading to a newer version of the Lumina server.
    -C …​ (–connection-string …​)Connection string
    -l …​ (–log-file …​)Log file
    -f …​ (–config-file …​)Config file
    -D …​ (–badreq-dir …​)Directory holding dumps of requests causing internal errors

    Troubleshooting

    The server complains about a “world-accessible” file, and exits

    The following files shouldn’t be readable by everyone on the system, but only by root and lumina:

    • lumina.conf: this file file holds the connection string to the database the server will use, and might contain credentials.
    • lumina_server.crt: the certificate chain
    • lumina_server.key: the private key file
    • lumina_server_<LID>.hexlic: the license file where represents your lumina server license ID.

    As a precaution, the Lumina server will refuse to start if these files are readable by unauthorized users.

    Please make sure they:

    • have lumina:lumina ownership: chown lumina:lumina lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic lumina.conf
    • are not world-accessible: chmod 640 lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic lumina.conf

    MySQL

    Before the first --recreate-schema command can succeed, it is necessary to create the MySQL database, as well as the user that it will be accessed as.

    “Authentication plugin ‘caching_sha2_password’ cannot be loaded”

    Some recent Linux distributions ship versions of MySQL that use the "caching_sha2_password" password-checking plugin (as opposed to the traditional “native password” one.)

    In order for the Lumina server to able to use this strategy, it would have to ship with a libmysqlclient.so file that is linked against libssl.so.3.

    Unfortunately, this library is not yet available on all of the various [versions of] distributions that we currently support, and introducing this dependency would significantly reduce the diversity of platforms on which the Lumina server can run.

    Consequently (for now) we have opted for another approach: the “lumina” MySQL user should use MySQL’s “native password” strategy. This can be accomplished by issuing the following command in a MySQL prompt:

    ALTER USER lumina@localhost IDENTIFIED WITH mysql_native_password BY '<luminauserpassword>';
    

    Once libssl.so.3 is more generally available, Lumina will not require this particular fine-tuning anymore.

    MySQL TLS connections

    For the same reasons as the caching_sha2_passwordissue, the Lumina server does not use TLS connections and thus will negotiate a plain TCP connection to the MySQL server.

    Creating the user and database

    What follows is an example creating a user + database, on a Debian system:

    >sudo mysql -uroot -p
    [sudo] password for aundro:
    Enter password:
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 14306
    Server version: 10.1.48-MySQL-0+deb9u2 Debian 9.13
    
    Copyright (c) 2000, 2018, Oracle, MySQL Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    MySQL [(none)]> create user lumina@localhost;
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> set password for lumina@localhost = PASSWORD('<snipped>');
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> grant all on *.* to lumina@localhost;
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> ALTER USER lumina@localhost IDENTIFIED WITH mysql_native_password BY '<snipped>';
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> create database lumina_db;
    Query OK, 1 row affected (0.00 sec)
    
    MySQL [(none)]> [Ctrl+C] Bye
    

    “Index column size too large. The maximum column size is 767 bytes.”

    The Lumina server cannot create its schema due to a particularly stringent limit on “index prefix sizes” in older versions of MySQL.

    This limit was increased in MySQL version 5.8, and thus this is the minimum version the Lumina server can work with.

    “Error: Cannot connect to lumina db”

    In this case, edit the configuration file, by default /opt/lumina/lumina.conf and replace Server=localhost by Server=127.0.0.1 in CONNSTR.

    Concepts

    What is the Lumina server

    The Lumina server is a “functions metadata” repository.

    It is a place where IDA users can push, and pull such metadata, to ease their reverse-engineering work: metadata can be extracted from existing projects, and re-applied effortlessly to new projects, thereby reducing (sometimes dramatically) the amount of time needed to analyze binaries.

    Functions metadata

    The Lumina server associates “function metadata” to functions, by means of a (md5) hash of those functions: whenever it wants to push information to, or pull information from the server, IDA will first have to compute hashes of the functions it wants to retrieve metadata for, and send those hashes to the Lumina server.

    Similarly, when IDA pushes information to the Lumina server, it will first compute hashes for the corresponding functions, extract the metadata corresponding to those from the .idb file, and send those hash+metadata pairs to the server.

    Metadata contents

    Metadata about functions can include:

    • function name
    • function address
    • function size
    • function prototype
    • function [repeatable] comments
    • instruction-specific [repeatable] comments
    • anterior/posterior (i.e., “extra”) comments
    • user-defined “stack points” in the function’s frame
    • the function frame description and stack variables
    • instructions operands representations

    Pushing & overriding metadata

    When a user pushes metadata about a function whose md5 hash isn’t present in the database, the Lumina server will simply create a new record for it.

    However, when a user pushes metadata about a function whose md5 hash (and associated metadata) is already present in the database, the Lumina server will attempt to “score” the quality of the old metadata and the quality of the new metadata. If the score of the new metadata is higher, the new function metadata will override the previous one.

    {% hint style=“info” %} When a user asks IDA to push all functions to the Lumina server, IDA will automatically skip some functions: those that still have a “dummy” name (e.g., sub_XXXX), or that are below a certain size threshold (i.e., 32 bytes) will be ignored. {% endhint %}

    Metadata history

    The Lumina server retains a history of the metadata associated to functions. Using the lc utility, it is possible to dig into that history, and view changes (detailed diffs, too.)

    File contents

    It’s worth pointing out that when pushing metadata to the Lumina server, IDA will not push the binary file itself. Only the following metadata about the file itself will be sent:

    • the name of the input file
    • the name of the IDB file
    • a md5 hash of the input file

    The Lumina server cannot therefore be used as a backup/repository for binary files & IDBs (that is the role of the vault_server)

    Teams Admin Guide

    Introduction

    This manual describes the installation, management, and interaction with the key server-side components of the Teams deployment.

    It is primarily intended for administrators, and will focus on the different servers that are part of Teams:

    1. The Hex-Rays Vault server
    2. The Lumina server

    While we will (at least superficially) make use of the command-line clients that are used to access/manage those servers, this manual will not offer a detailed explanation of their usage: there are dedicated documents for that (e.g., the hv user manual, the lc user manual, …​).

    Let’s get started

    The first server to install, and the one that is at the center of the Teams deployment, is the Hex-Rays Vault server.

    It is recommended to have the hv user manual ready before proceeding.

    Prerequisites

    After your purchase of Teams server, go to the customer portal, where you will find an installer for the Teams server (also called the “Hex-Rays Vault server”). Please go ahead and download it.

    Quick alternative {% hint style=“success” %}

    HCLI Commands | See HCLI Docs

    • hcli license get
    • hcli download {% endhint %}

    You will also need root access on the host where you will be installing the server.

    Installation

    This chapter explains how to install two parts of Teams: the vault server, and a client.

    We recommend installing a client first, to be able to connect to the server immediately after installation. The very first user to connect to the server becomes the administrator.

    Installing clients

    There are 2 Hex-Rays Vault clients:

    1. hv: a command-line client (which we’ll use in this document)
    2. hvui: a GUI interface to the server

    Vault clients are bundled with IDA installers: simply run the IDA installer (if you haven’t done it yet) and follow the instructions. That will install IDA, and the 2 clients next to it.

    Installing the server

    The Hex-Rays Vault server can be installed on Linux servers. We have tested it on Debian and Ubuntu, but other major flavors of Linux should be fine too.

    To install the server, run the Hex-Rays Vault installer as root and follow the instructions (the server will not require root permissions; only the installer does.)

    If your Linux system is based on systemd (e.g., Debian/Ubuntu, Red-Hat, CentOS, …​), it is recommended to let the installer create systemd units so that the server will start automatically at the next reboot.

    Once the server is installed, it will be necessary to activate its license.

    Activating the server license

    In order for the Hex-Rays Vault server license to be activated, it must be bound to a Host ID (an Ethernet MAC address.)

    From a command prompt, run /sbin/ifconfig, and lookup the “ether” address for the network interface through which the server will be accessible.

    >/sbin/ifconfig
    enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            [...snipped...]
            ether bf:e2:91:10:58:d2  txqueuelen 1000  (Ethernet)
            [...snipped...]
    

    In this case, our mac address is: bf:e2:91:10:58:d2

    You will be able to activate both Hex-Rays Vault server and Lumina server in one activation if you have also the Host ID of your Lumina server.

    Go to Hex-Rays customer portal and activate your license for Teams server. During that process, you will need to provide the MAC address of the device where the Teams server will be running. Once the activation is complete, you’ll be able to download the following files:

    • teams server certificate
    • teams_server_<LID>.hexlic (license key, where <LID> is your teams server license ID)

    Those need to be copied in the Hex-Rays Vault installation directory. As root:

    >cd /opt/hexvault
    >cp .../path/to/hexvault.crt .
    >cp .../path/to/hexvault.key .
    >cp .../path/to/hexvault_*.hexlic .
    >chown hexvault:hexvault hexvault.crt hexvault.key teams_server_<LID>.hexlic
    >chmod 640 hexvault.crt hexvault.key teams_server_<LID>.hexlic
    

    Creating the initial database

    At this point, the server should be ready to run.

    NOTE: If your system is already in production and hosts files, skip this section. Using the --recreate-schema option as in the example below, will re-create an empty database and lose all history.

    On the first install, you will need to initialize the database the server will use:

    >sudo -u hexvault ./vault_server --config-file hexvault.conf \
                                     --vault-dir ./files \
                                     --certchain-file hexvault.crt \
                                     --privkey-file hexvault.key \
                                     --recreate-schema
    >2022-04-14 14:30:28 Vault Server v1.0 Hex-Rays (c) 2022-2024
    >2022-04-14 14:30:28 Database initialized; exiting.
    

    Testing the server

    Now that the server is installed and has a database to work with, we can test that it works:

    >sudo -u hexvault ./vault_server --config-file hexvault.conf \
                                     --certchain-file hexvault.crt \
                                     --privkey-file hexvault.key \
                                     --license-file teams_server_<LID>.hexlic \
                                     --vault-dir ./files
    >2022-04-14 14:35:47 Vault Server v1.0 Hex-Rays (c) 2022-2024
    >2022-04-14 14:35:47 Using a license with 5 seats
    >2022-04-14 14:35:47 Listening on 0.0.0.0:65433...
    

    Good, the server appears to run! (If you are observing more worrying messages than this one, please refer to the troubleshooting section.)

    At this point, you may want to either let the server run, or stop it (Ctrl+C will do) and restart it using systemd:

    >systemctl restart hexvault.service
    

    …​and make sure it runs:

    >ps aux | grep vault_server
    hexvault  58246  0.0  0.0 ...
    

    or:

    >systemctl status hexvault.service
    

    If you don’t see a running vault_server process or a failed systemctl start status, please refer to the systemd diagnostic tools (e.g., journalctl) for more info.

    Initial configuration

    This chapter explains how to perform the initial configuration of the vault server.

    For the sake of the examples below, we’ll imagine the following fictional group of users:

    • Jane Smith, the department admin/IT head
    • Fred Bloggs, senior reverse engineer

    In addition, we’ll assume:

    • the company name is Acme
    • the Hex-Rays Vault server has been installed on the company’s LAN, on the host hexvault.acme.com

    Creating the administrator

    NOTE: The very first user to log into the server becomes the first administrator. S/he can create new administrators and otherwise manage the server.

    Once the server is up and running, login to server using a username and password of your choice (hv is the vault client utility, it is installed as part of the client package.)

    NOTE: We will assume Jane installed IDA (and thus hv) in /home/jane/idateams

    >cd /home/jane/idateams
    >./hv -hhexvault.acme.com -ujane -psecr3t info
    
    Hex-Rays Vault Server v1
    Vault time: 2022-04-14 15:28:03, up since 2022-04-14 15:17:25
    License user : Jane Smith, IDA Ultimate
    License email: [email protected]
    License: IDAULTTM; 1 users out of 5; expires on 2023-04-05
    MAC address: xx:xx:xx:xx:xx:xx
    Vault directory: /opt/hexvault/files
    Client name: jane *ADMIN*
    Client site:
    Client host: 127.0.0.1
    Client root:
    Login time : 2022-04-14 15:28:03
    Last active: 2022-04-14 15:28:03
    

    NOTE: No space between the command line switches and values.

    Since Jane is the first user to login to the server, the credentials she provided, will be used to create the server’s primary administrator.

    You can verify that you are the only user by checking the user list:

    >./hv -hhexvault.acme.com -ujane -psecr3t users
    
    LastActive Adm    Login       License          Email
    ---------- --- ------------ --------------- ------------
    2022-04-14  *  jane          <>
    

    You may also add information (like your real name) to your user record by issuing:

    >./hv -hhexvault.acme.com -ujane -psecr3t user edit jane "Jane Smith" [email protected] 1 "" 48-XXXX-XXXX-XX
    >./hv -hhexvault.acme.com -ujane -psecr3t users
    
    LastActive Adm    Login       License          Email
    ---------- --- ------------ --------------- ------------
    2022-04-14  *  jane         48-XXXX-XXXX-XX Jane Smith <[email protected]>
    

    However, note that having to pass a user name, host name and a password on the command line each time will get very tedious very fast. The next chapter will show how we can make our lives easier.

    hv credentials

    In order to connect to the vault server, hv must at least have:

    • a username
    • a password
    • a hostname

    For example:

    $ hv -hhexvault.acme.com:65433 -uadmin -psecret users
    LastActive Adm    Login        Email
    ---------- --- ------------ ------------
    2022-06-27  *  admin
    2022-06-22     alice       Alice <[email protected]>
    Never          bob         Bob <[email protected]>
    ...
    

    There are 3 ways to specify credentials (in decreasing order of priority):

    All credentials, including usernames, are case-senstive, meaning that “Joe” and “joe” would be different users.

    Command line

    Passing credentials on the command line will always take precedence over environment variables and registry+keychain.

    -uUSERNAMEspecify username
    -pPASSWORDspecify password
    -hHOSTspecify host (server:port) (if port is omitted, defaults to 65433)
    -sSITENAMEspecify site
    --setremember credentials. This option doesn’t require the credentials to be passed through the command line, credentials passed through environment variables will work as well

    Environment variables

    Credentials can also be passed through environment variables. They will take precedence over those possibly found in the registry+keychain.

    VAULT_HOSTthe server host name
    VAULT_PORTthe server port
    VAULT_USERthe username to connect to the server
    VAULT_PASSthe user’s password
    VAULT_SITEthe site to use (most commands need a site to operate)

    Registry + keychain

    Unless environment variables or command-line arguments are provided, hv will look for credentials in the registry (and the OS’s keychain for passwords.)

    Credentials can be stored in the registry (and keychain) like so:

    alice@alice_PC$ hv --set -ualice -palice -hvaultserver -salice_on_alicepc
    

    The user, host (and optional site) will be persisted in the registry, while the password will be saved to the OS’s keychain.

    For this operation to succeed, at least a user and host must be provided

    In order to keep the various commands’ syntax as clear as possible, we will assume that the user has stored credentials (in either the registry+keychain or environment variables) for the rest of this manual.

    Best practices

    We recommend persisting credentials using the registry+keychain method.

    Once that is done, commands will become cleaner:

    >./hv info
    
    Hex-Rays Vault Server v1
    Vault time: 2022-04-14 15:36:29, up since 2022-04-14 15:17:25
    ...
    

    if you login to the server using hvui and save the login information, it will end up in the the registry+keychain method, and thus hv will then be able to use that information as well.

    Adding users

    To be able to connect to the vault server, users need to be added to the server. That can be done with the user add command:

    >./hv user add fred "Fred Bloggs" [email protected] 0 ""
    >./hv users
    
    LastActive Adm    Login        Email
    ---------- --- ------------ ------------
    Never          fred         Fred Bloggs <[email protected]>
    2022-04-14  *  jane         Jane Smith <[email protected]>
    

    Setting the new user’s password

    Then, we need to set the user’s password, using the passwd command:

    >./hv passwd stea1thy fred
    

    Adding groups

    To facilitate user management, sometimes it makes sense to make user groups. All users of a group then can be granted or denied access to certain files on the server.

    Let’s add a few groups:

    >./hv group add org
    >./hv group add analysts
    

    Using the groups command, we can see the new groups are still empty:

    >./hv groups
    analysts:
    org:
    

    We can now add group members:

    >./hv group edit org jane 1
    >./hv group edit org fred 1
    >./hv group edit analysts fred 1
    >./hv groups
    analysts: fred
    org: fred jane
    

    Groups are especially useful for managing permissions.

    Management

    This chapter explains in detail how to perform regular administrator tasks.

    Managing permissions

    If you want to limit access to the files that will be stored on the vault server, you can specify who can access what. By default, the permission table grants all users access to all files:

    >hv perm get
    # The permission for each vault file is determined as the result of applying
    # all matching lines, from the beginning of the permission table to the end.
    # An empty permission table grants all access to everyone.
    # A non-empty permission table starts by denying all access to everyone.
    

    You will need to prepare a new permission table and put it into a file. The permission table consists of lines with the following format:

    ACTION CATEGORY WHO PERM PATH
    

    where:

    ACTION
    one of “grant” or “deny”

    CATEGORY
    one of “user” or “group”

    WHO
    name of the user or group to match

    PERM
    one of “list”, “read”, “write”

    PATH
    path pattern that the rule is for

    Below is a sample permission table:

    We’ll assume the server has been in use for a while, and holds some files in the directories subdir-for-fred/, local-secret/, and subdir/for/idbs/.

    # The permission for each vault file is determined as the result of applying
    # all matching lines, from the beginning of the permission table to the end.
    # An empty permission table grants all access to everyone.
    # A non-empty permission table starts by denying all access to everyone.
    
    # Fred can freely list, read, and modify all files inside "subdir-for-fred"
    grant user fred write //subdir-for-fred/
    
    # The "remote" group cannot even see "local-secret":
    deny group remote list //local-secret
    
    # The analysts can work on IDBs:
    grant group analysts write //subdir/for/idbs/
    
    # Everyone else may read them:
    grant user * read //subdir/for/idbs/
    

    The permissions have the following order:

    • Adding the read permission also adds the list permission.
    • Adding the write permission also adds the list and read permissions.
    • Removing the read permission also removes the write permission.
    • Removing the list permission also removes the read and write permissions.

    Once the permission table is ready and stored in a file, we can install it:

    >hv perm set @path/to/permission-file
    

    After setting the permissions, it is a good idea to verify them. For example, this is how we can get a full list of files that fred can see, with the rw or r- prefixes, depending on the permissions:

    >hv perm check fred //
    rw //subdir-for-fred/afile
    rw //subdir-for-fred/anotherfile
    r- //subdir/for/idbs/malware.idb
    

    Or we could limit our check to a particular file:

    >hv perm check fred //local-secret
    

    The empty output means that fred cannot see local-secret even though it exists.

    Optimizing server storage

    The vault server can store full file copies or deltas between them, or both full files and deltas. With time, the server storage may grow too big, or become inefficient because of too many deltas. To keep the server storage optimal, the admin should periodically run the following command:

    >hv optsrv -y paths...
    

    This command examines the storage of all specified files and optimizes them using the following configuration parameters:

    --full-file-freq After how many deltas create a full file?
    --max-delta-size Size of consecutive deltas compared to the full file size (%)
    --keep-full-files Keep superfluous full files during storage optimization
    --delete-deltas Delete superfluous delta files during storage optimization
    

    These parameters can be specified in the server configuration file.

    The full file frequency parameter specifies after how many deltas there should be a full file. The default value is 10, which means that after 10 deltas the server will create a full file. If you want the server to store only full files, set this parameter to 0. If you want the server to store only deltas during optimization, set this parameter to a very high value, like 100000.

    The max delta size specifies the maximum cumulative size of deltas between full files. It is specified as a percentage of the full file. The default value is 80%. Let us consider this situation: the server stores a full file for the revision #1 and a few deltas:

    - full_file#1, 100MB
    - delta for #1->#2, 30MB
    - delta for #2->#3, 40MB
    - delta for #3->#4, 20MB
    

    During optimization, the last delta will be deleted because the cumulative size of all deltas (30+40+20) is greater than 80% of 100MB.

    If max delta size is specified as 0, then it is ignored.

    Both the full file frequency and max delta size influence creation of full files. By setting max-delta-size=0 and full-file-freq=1000000 we could ensure that during optimization only delta files would be created. However, please note that this would mean that the server may take a really long time to prepare full copies. For example, take the situation where the file has 100 revisions and only the first revision is stored as a full file and 99 other revisions are stored as deltas. If a client asks for the revision 100 of the file and claims that it has no previous revisions of the file, the server will have to apply 99 delta files to the revision 1 and only then send the file to the client.

    By setting full-file-freq=0 we would ensure that during optimization we would always create full files in addition to deltas. This will speed up serving files to clients but eat up lots of disk space.

    Finally, --keep-full-files ensures that after creating a delta file the corresponding full file would be kept on the server disk. By default, the server deletes the full file to optimize the disk space. Also, --delete-deltas ensures that after creating a full file the corresponding delta file would be deleted. By default, the server keeps delta files.

    The above parameters are used only during the optsrv command. Clients can still commit delta files or full files, and the server storage may become suboptimal over time. We suggest adding the hv optsrv as a cron job.

    Backup and restore

    Currently, there is no dedicated procedure to back up the vault contents. It can be done by temporarily stopping the vault server and making a copy of the sqlite3 database as well as the files. The server must be stopped only during the backup of the sqlite3 database and then can be immediately restarted. It is ok to let the server run when making copies of the vault files. In the worst case some additional files will get copied in the backup, which normally will not cause problems. Since we never modify vault files but always create new revisions, there is no danger of copying inconsistent data.

    Alternatively, it is possible to use sqlite3 backup functionality to make a backup of the database. Vault files can be copied using any Linux command (e.g. rsync or tar).

    Upgrading the server

    Switching to the newest versions of the Hex-Rays Vault server is recommended in order for the team to benefit from its improvements and new features.

    The upgrade procedure consists of the following steps:

    1. stopping the server. E.g., sudo systemctl stop hexvault if you are using systemd to manage the server.
    2. performing a backup of the database
    3. putting the new server instead of the old one
    4. making sure the new server runs, upgrading the database schema to the new version if needed
    5. restarting the server. E.g., sudo systemctl start hexvault

    Verifying the database schema

    Right after putting the new Hex-Rays Vault server binary into place, it is recommended to make sure it runs fine. To do that, we’ll run the server manually just like we did the first time we installed it:

    >sudo -u hexvault ./vault_server --config-file hexvault.conf \
                                     --certchain-file hexvault.crt \
                                     --privkey-file hexvault.key \
                                     --license-file teams_server_<LID>.hexlic \
                                     --vault-dir ./files \
    >2022-10-07 11:13:55 Vault Server v1.0 Hex-Rays (c) 2022-2024
    >2022-10-07 11:13:55 Using a license with 30 seats
    >Error: obsolete database schema (5); use --upgrade-schema to upgrade it
    

    In this case, the server complains that the database schema is outdated. This may happen as we will keep improving the Hex-Rays Vault server, and new versions might require an upgrade of the database schema in order to be able to work correctly.

    Note that the Hex-Rays Vault server will not perform that upgrade automatically. That is on-purpose, to give you a chance to backup the database before proceeding.

    Let’s tell the server to upgrade to the latest schema:

    >sudo -u hexvault ./vault_server --config-file hexvault.conf \
                                     --certchain-file hexvault.crt \
                                     --privkey-file hexvault.key \
                                     --license-file teams_server_<LID>.hexlic \
                                     --vault-dir ./files \
                                     --upgrade-schema
    >2022-10-07 11:15:59 Vault Server v1.0 Hex-Rays (c) 2022-2024
    >2022-10-07 11:15:59 Upgrading the database schema from 5 to 8...
    >2022-10-07 11:15:59 Database schema is up to date; exiting.
    

    Please ensure you performed a backup of the database before issuing this command.

    Once this is done, you should be able to restart the server in a normal way, and resume work.

    Managing vault files

    We plan to introduce additional functionalities like:

    • obliteration of files
    • periodic vault self-verification
    • periodic backups
    • usage stats

    Hex-Rays Vault server command-line options

    Short formLong formDescription
    -p …​–port-number …​Port number (default 65433)
    -i …​–ip-address …​IP address to bind to (default to any)
    -c …​–certchain-file …​TLS certificate chain file
    -k …​–privkey-file …​TLS private key file
    -v–verboseVerbose mode
    –upgrade-schemaUpgrade database schema; then quit
    -C …​ –connection-string …​Connection string
    -l …​–log-file …​Log file
    -L …​–license-file …​License file
    -f …​–config-file …​Config file
    -D …–badreq-dir …Directory holding dumps of requests causing internal errors
    –recreate-schemaDrop & re-create schema; then quit THIS WILL ERASE ALL DATA
    –set-admin …​Set admin password; requires username:password
    -d …–vault-dir …​Directory for vault files
    -e …​–log-level …​Log level
    –full-file-freq …After how many deltas create a full file?
    –max-delta-size …Size of consecutive deltas compared to the full file size (%)
    –keep-full-filesKeep superfluous full files during storage optimization
    –delete-deltasDelete superfluous delta files during storage optimization

    Troubleshooting

    This chapter explains how to solve typical problems with the vault server.

    Connection issues

    By default, the vault server listens on the TCP port 65433 on all interfaces. Please ensure that this port is enabled in your firewalls.

    The vault server uses secure TLS connections with the clients. The TLS layer requires the certificate (.crt) and private key (.key) files. Usually, they are attached to the email message with the activation information.

    Lost admin password

    A lost admin password can be reset by following these steps:

    • Stop the running server
    • Launch the server with the --set-admin command line switch
    • Start the server

    In practice it may look like this:

    >systemctl stop hexvault.service
    >vault_server --config-file hexvault.conf --set-admin USERNAME:PASSWORD
    >systemctl start hexvault.service
    

    The uppercase USERNAME and PASSWORD placeholders should be replaced by the desired values. The user name and the password are separated by a colon.

    The specified user must exist. If sh/e was not an admin before, s/he will be promoted to an admin by this command.

    NOTE: If you do not know any valid users of the vault, use the sqlite3 command line utility to list the users. They are stored in the users table.

    Site verification

    The following command:

    >hv md5 PATH REVISION
    

    can be used to retrieve MD5 checksums of the specified files.

    PATH
    path pattern to retrieve checksums from

    REVISION
    optional file revision. If not specified, the checksum of the last revision is reported

    The server complains about a “world-accessible” file, and exits

    The following files shouldn’t be readable by everyone on the system, but only by root and hexvault:

    • hexvault.conf: this file file holds the connection string to the database the server will use, and might contain credentials.
    • hexvault.crt: the certificate chain
    • hexvault.key: the private key file
    • teams_server_<LID>.hexlic: the license file

    As a precaution, the Hex-Rays Vault server will refuse to start if these files are readable by unauthorized users.

    Please make sure they:

    • have hexvault:hexvault ownership: chown hexvault:hexvault hexvault.crt hexvault.key teams_server_*.hexlic hexvault.conf
    • are not world-accessible: chmod 640 hexvault.crt hexvault.key teams_server_*.hexlic hexvault.conf

    Licensing

    The hexvault.lic file is tied to the MAC address of the first network interface. If they do not match, the server will not start. To change the MAC address, please contact [email protected]

    Restoring from backups

    There are no special precautions to take: restoring the sqlite3 database and vault files from a backup should be enough.

    IDA Teams Lumina server

    In addition to the Hex-Rays Vault server, the Teams users can make use of a private, on-the-premises Lumina server (unlike the Hex-Rays Vault server, the Lumina server isn’t a strictly necessary component of the Teams deployment.)

    In the Teams setup, the Lumina server must have access to a running Hex-Rays Vault server in order to work: indeed, all user management is done through the Hex-Rays Vault server.

    Please make sure the Hex-Rays Vault server is properly installed & running.

    Prerequisites

    After your purchase of Lumina server, go to the customer portal, where you will find an installer for the Lumina server. Please go ahead and download it.

    Quick alternative {% hint style=“success” %}

    HCLI Commands | See HCLI Docs

    • hcli license get
    • hcli download {% endhint %}

    You will also need root access on the host where you will be installing the Lumina server (to install the server, not to run it).

    MySQL server

    The Lumina server stores its data in a MySQL DBMS server. It is therefore necessary to have valid credentials to such a server, as well as a fresh, empty database.

    NOTE: The Lumina server requires a MySQL server version 5.8 or newer.

    For illustration purposes, let’s assume the MySQL database the server will use, is called: "lumina_db".

    Installation

    At installation-time, the Lumina server installer will need information about the MySQL instance the Lumina server will be using (host, port, username, password). Eventually, that information will end up in the lumina.conf file, sitting next to the lumina_server binary:

    CONNSTR="mysql;Server=127.0.0.1;Port=3306;Database=lumina_db;Uid=lumina;Pwd=<snipped>"
    

    Installation in a Teams setup

    When Lumina is installed in a Teams setup, in addition to information about the MySQL database in which the Lumina server will store the metadata, the installer asks for the host+port pair where to find a running Hex-Rays Vault server to which user authentication will be delegated.

    That information will also end up in the lumina.conf file:

    VAULT_HOST="vault.acme.com:65433"
    

    Supported platforms

    The Lumina server can be installed on Linux servers. We have tested it on Debian and Ubuntu, but other major flavors of Linux should be fine too.

    To install the server, run the Lumina installer as root and follow the instructions (the server will not require root permissions; only the installer does.)

    NOTE: If your Linux system is based on systemd (e.g., Debian/Ubuntu, Red-Hat, CentOS, …​), it is recommended to let the installer create systemd units so that the server will start automatically at the next reboot.

    Activating the server license

    In order for the Lumina server license to be activated, it must be bound to a Host ID (an Ethernet MAC address.)

    From a command prompt, run /sbin/ifconfig, and lookup the “ether” address for the network interface through which the server will be accessible.

    >/sbin/ifconfig
    enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            [...snipped...]
            ether bf:e2:91:10:58:d2  txqueuelen 1000  (Ethernet)
            [...snipped...]
    

    In this case, our mac address is: bf:e2:91:10:58:d2

    Go to Hex-Rays customer portal and activate your license for Lumina server. During that process, you will need to provide the MAC address of the device where the Lumina server will be running. Once the activation is complete, you’ll be able to download the following files:

    • lumina server certificate
    • lumina_server_<LID>.hexlic (license key, where LID is your license ID)

    Installing the server license

    Those need to be copied in the Lumina installation directory. As root:

    >cd /opt/lumina
    >cp .../path/to/lumina_server.crt .
    >cp .../path/to/lumina_server.key .
    >cp .../path/to/lumina_server_<LID>.hexlic .
    >chown lumina:lumina lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic
    >chmod 640 lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic
    

    Creating the initial database schema

    At this point, the server should be ready to run.

    NOTE: If your system is already in production and hosts files, skip this section. Using the --recreate-schema option as in the example below, will re-create an empty database and lose all data.

    For the Lumina server to work, it needs to have a proper database schema to work with (at this point, the MySQL database (i.e., "lumina_db") must already exist but is still empty.)

    That is why, on the first install, you will need to initialize the database the server will use as well as specify which user authentication will be used (either lumina or vault, we will use lumina in the example below):

    >sudo -u lumina ./lumina_server --config-file lumina.conf \
                                    --certchain-file lumina_server.crt \
                                    --privkey-file lumina_server.key \
                                    --recreate-schema lumina
    Hex-Rays Lumina Server v8.0 Hex-Rays (c) 2022-2024
    2022-09-02 10:28:30 Database has been initialized; exiting.
    

    If you see “Error: Cannot connect to lumina db” please refer to troubleshooting section.

    Testing the server

    Now that the server is installed and has a database to work with, we can test that it works:

    >sudo -u lumina ./lumina_server --config-file lumina.conf \
                          --certchain-file lumina_server.crt \
                          --privkey-file lumina_server.key
    Hex-Rays Lumina Server v8.0 Hex-Rays (c) 2022-2024
    2022-09-22 12:14:37 Listening on 0.0.0.0:443...
    

    Good, the server appears to run! (If you are observing more worrying messages than this one, please refer to the troubleshooting section.)

    At this point, you may want to either let the server run, or stop it (Ctrl+C will do) and restart it using systemd:

    >systemctl restart lumina.service
    

    …​and make sure it runs:

    >ps aux | grep lumina_server
    lumina  78812  0.0  0.0 ...
    

    or:

    >systemctl status lumina.service
    

    If you don’t see a running lumina_server process or systemctl reports a startup failure, please refer to the systemd diagnostic tools (e.g., journalctl) for more info.

    Hex-Rays Vault authentication

    The Lumina server delegates authentication to the Hex-Rays Vault server. That is where the primary source of users information is located.

    Consequently, it is the exact same set of users, with the exact same credentials as those that are able to use the Hex-Rays Vault server, that will be able to make use of the Lumina server.

    Assuming Alice was registered in the Hex-Rays Vault server (and has admin rights), she should be able to use the lc utility to perform operations on the Lumina server.

    NOTE: lc is the Lumina command-line administration client, which comes with the Lumina server installer. We will assume the server has been installed in /opt/lumina/, and thus lc is present in /opt/lumina/lc.

    >cd /opt/lumina
    >./lc -hlumina.acme.com -ualice -psecr3t info
    	Hex-Rays Lumina Server v8.0
    	Lumina time: 2022-09-01 14:28:02, up since 2022-09-01 14:27:58
    	MAC address: <snipped macaddr>
    	Client name: alice *ADMIN*
    	Client host: 127.0.0.1
    
    >./lc -hlumina.acme.com -ualice -psecr3t users
    	LastActive          Adm Login License         User name Email
    	------------------- --- ----- --------------- --------- --------------
    	2022-09-01 14:28:04 *   alice AA-A11C-AC8E-01 Alice     [email protected]
    	# Shown 1 results
    

    “shadow” copy of users in the Lumina server

    Although the authority for user management & authentication is the Hex-Rays Vault server, the Lumina server will need to “shadow” that information for its own database to be in a coherent state.

    Every time a user opens a new connection to the Lumina server it will in turn perform a call to the Hex-Rays Vault server to authenticate the user against the provided credentials.

    Depending on the success of that latter call, a “shadow” of the user will be recorded, updated, or deleted from the Lumina server’s database.

    NOTE: Not everything is copied to the Lumina server’s shadow users table; in particular, the password hash isn’t.

    Useful environment variables

    To facilitate using lc, you may consider defining the following environment variables:

    export LUMINA_HOST=lumina.acme.com
    export LUMINA_USER=alice
    export LUMINA_PASS=secr3t
    

    After that, you can connect to the server effortlessly. For example, this command will print information about the server and the client:

    >./lc info
        Hex-Rays Lumina Server v8.0
        Lumina time: 2022-09-01 14:28:02, up since 2022-09-01 14:27:58
        MAC address: <snipped macaddr>
        Client name: alice *ADMIN*
        Client host: 127.0.0.1
    ...
    

    The lumina server looks up an additional LUMINA_RECV_HELO_TIMEOUT environment variable, which can be used to set the timeout for client login phase (the time between the TLS handshake and the arrival of the first packet). The value is in milliseconds, and setting it to -1 disables the timeout.

    Note that when a client attempts to connect, the lumina server creates a new thread and keeps it running for the entire duration of this timeout. Hence, for publicly exposed lumina servers, it is advised to keep it as short as possible (e.g. 1000 ms).

    Lumina server command-line options

    -p …​ (–port-number …​)Port number (default 443)
    -i …​ (–ip-address …​)IP address to bind to (default to any)
    -c …​ (–certchain-file …​)TLS certificate chain file
    -k …​ (–privkey-file …​)TLS private key file
    -v (–verbose)Verbose mode
    (–recreate-schema [lumina|vault]​)Drop & re-create schema using either lumina or vault user authentication. Note that THIS WILL ERASE ALL DATA
    (–upgrade-schema)Upgrade database schema; then quit. Only necessary when upgrading to a newer version of the Lumina server.
    -C …​ (–connection-string …​)Connection string
    -l …​ (–log-file …​)Log file
    -f …​ (–config-file …​)Config file
    -D …​ (–badreq-dir …​)Directory holding dumps of requests causing internal errors

    Troubleshooting

    The server complains about a “world-accessible” file, and exits

    The following files shouldn’t be readable by everyone on the system, but only by root and lumina:

    • lumina.conf: this file file holds the connection string to the database the server will use, and might contain credentials.
    • lumina_server.crt: the certificate chain
    • lumina_server.key: the private key file
    • lumina_server_<LID>.hexlic: the license file where represents your lumina server license ID.

    As a precaution, the Lumina server will refuse to start if these files are readable by unauthorized users.

    Please make sure they:

    • have lumina:lumina ownership: chown lumina:lumina lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic lumina.conf
    • are not world-accessible: chmod 640 lumina_server.crt lumina_server.key lumina_server_<LID>.hexlic lumina.conf

    MySQL

    Before the first --recreate-schema command can succeed, it is necessary to create the MySQL database, as well as the user that it will be accessed as.

    “Authentication plugin ‘caching_sha2_password’ cannot be loaded”

    Some recent Linux distributions ship versions of MySQL that use the "caching_sha2_password" password-checking plugin (as opposed to the traditional “native password” one.)

    In order for the Lumina server to able to use this strategy, it would have to ship with a libmysqlclient.so file that is linked against libssl.so.3.

    Unfortunately, this library is not yet available on all of the various [versions of] distributions that we currently support, and introducing this dependency would significantly reduce the diversity of platforms on which the Lumina server can run.

    Consequently (for now) we have opted for another approach: the “lumina” MySQL user should use MySQL’s “native password” strategy. This can be accomplished by issuing the following command in a MySQL prompt:

    ALTER USER lumina@localhost IDENTIFIED WITH mysql_native_password BY '<luminauserpassword>';
    

    Once libssl.so.3 is more generally available, Lumina will not require this particular fine-tuning anymore.

    MySQL TLS connections

    For the same reasons as the caching_sha2_passwordissue, the Lumina server does not use TLS connections and thus will negotiate a plain TCP connection to the MySQL server.

    Creating the user and database

    What follows is an example creating a user + database, on a Debian system:

    >sudo mysql -uroot -p
    [sudo] password for aundro:
    Enter password:
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 14306
    Server version: 10.1.48-MySQL-0+deb9u2 Debian 9.13
    
    Copyright (c) 2000, 2018, Oracle, MySQL Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    MySQL [(none)]> create user lumina@localhost;
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> set password for lumina@localhost = PASSWORD('<snipped>');
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> grant all on *.* to lumina@localhost;
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> ALTER USER lumina@localhost IDENTIFIED WITH mysql_native_password BY '<snipped>';
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [(none)]> create database lumina_db;
    Query OK, 1 row affected (0.00 sec)
    
    MySQL [(none)]> [Ctrl+C] Bye
    
    “Index column size too large. The maximum column size is 767 bytes.”

    The Lumina server cannot create its schema due to a particularly stringent limit on “index prefix sizes” in older versions of MySQL.

    This limit was increased in MySQL version 5.8, and thus this is the minimum version the Lumina server can work with.

    “Error: Cannot connect to lumina db”

    In this case, edit the configuration file, by default /opt/lumina/lumina.conf and replace Server=localhost by Server=127.0.0.1 in CONNSTR.

    What is the Lumina server

    The Lumina server is a “functions metadata” repository.

    It is a place where IDA users can push, and pull such metadata, to ease their reverse-engineering work: metadata can be extracted from existing projects, and re-applied effortlessly to new projects, thereby reducing (sometimes dramatically) the amount of time needed to analyze binaries.

    Functions metadata

    The Lumina server associates “function metadata” to functions, by means of a (md5) hash of those functions: whenever it wants to push information to, or pull information from the server, IDA will first have to compute hashes of the functions it wants to retrieve metadata for, and send those hashes to the Lumina server.

    Similarly, when IDA pushes information to the Lumina server, it will first compute hashes for the corresponding functions, extract the metadata corresponding to those from the .idb file, and send those hash+metadata pairs to the server.

    Metadata contents

    Metadata about functions can include:

    • function name
    • function address
    • function size
    • function prototype
    • function [repeatable] comments
    • instruction-specific [repeatable] comments
    • anterior/posterior (i.e., “extra”) comments
    • user-defined “stack points” in the function’s frame
    • the function frame description and stack variables
    • instructions operands representations
    Pushing & overriding metadata

    When a user pushes metadata about a function whose md5 hash isn’t present in the database, the Lumina server will simply create a new record for it.

    However, when a user pushes metadata about a function whose md5 hash (and associated metadata) is already present in the database, the Lumina server will attempt to “score” the quality of the old metadata and the quality of the new metadata. If the score of the new metadata is higher, the new function metadata will override the previous one.

    {% hint style=“info” %} When a user asks IDA to push all functions to the Lumina server, IDA will automatically skip some functions: those that still have a “dummy” name (e.g., sub_XXXX), or that are below a certain size threshold (i.e., 32 bytes) will be ignored. {% endhint %}

    Metadata history

    The Lumina server retains a history of the metadata associated to functions. Using the lc utility, it is possible to dig into that history, and view changes (detailed diffs, too.)

    File contents

    It’s worth pointing out that when pushing metadata to the Lumina server, IDA will not push the binary file itself. Only the following metadata about the file itself will be sent:

    • the name of the input file
    • the name of the IDB file
    • a md5 hash of the input file

    The Lumina server cannot therefore be used as a backup/repository for binary files & IDBs (that is the role of the vault_server)

    Lumina server vs Hex-Rays Vault server: what is the difference?

    While the workflow with the Hex-Rays Vault server and associated tools (hv, hvui and IDA’s diff/merge modes) are extremely powerful for working on multiple revisions of the same binaries, the Lumina server in turn eases the replication of past efforts to new projects.

    In effect, the Lumina server offers another “dimension” to collaborative reverse-engineering efforts.

    Concepts

    What is a “site”?

    A site represents a mapping of the server files to the local filesystem. Normally each computer has a site associated with it. A site has the following attributes:

    • A site name
    • A host name
    • The path to a folder on the filesystem (a.k.a., “root directory”)
    • Path filters (optional)

    site details

    Root directory

    The root directory is the essential attribute of a site. It denotes where all files from the vault server will be mapped to the local disk. Everything inside the root directory can potentially be uploaded to the vault server and shared with other team members.

    The vault server cannot manage files located outside the root directory. However, this limitation is straightforward to overcome: create a symbolic link (or, on Windows, a junction point) from the root directory to the directory of your choice. This will make the target of the symbolic link visible as part of the root directory.

    The vault server keeps track of each site’s state: what files have been downloaded to the local disk, what files have been checked out for editing, etc. This simplifies the housekeeping tasks, especially for big repositories with millions of files. Even for them, downloading the latest files or reconciling the local disk with the server, are almost instantaneous.

    The host name is a security feature that prevents from using a site on a wrong computer. Since the server keeps track of the files downloaded to each site, using a wrong site may lead to an inconsistent mapping between the server and local disk. However, if the user does not want this protection, it is possible to erase the host name in the site definition.

    Sites can be edited from the “Sites” view.

    Path filters

    By default all server files are visible, but for servers that manage gigabytes of data this can be problematic: it may be undesirable for users to download all files to their local computer.

    Site filters provide a mechanism that lets users restrict the set of files their IDA Teams client works with. Users who want to work on some specific projects can set a filter that restricts the visibility only to selected subdirectories.

    Each site has its own filters, that con be modified at any time. Filters do not directly affect any files on the local disk, or on the server: they are strictly about visibility.

    WARNING: Site filters are meant simplify a user’s life by letting them focus on specific projects. Since they can be modified by users, they should not be considered a security measure: that would be the role of the permissions system, which can only be managed by vault_server administrators.

    NOTE: The purpose of site filters is to create a subset of the full set of files provided by the server. Site filters don’t directly affect what locally-available files (i.e., present in the site’s rootdir, but not tracked by the server) are visible by IDA Teams clients.

    There is another mechanism to specify what files should not be added to the vault. See .hvignore for more info.

    Examples

    An empty filter

    $ cat empty_filter.txt
    $
    

    Hide all files, except those in malware/

    $ cat only_malware.txt
    malware/
    $
    

    Show all files, except those from the pentesting team

    $ cat hide_pentest.txt
    !pentesting/
    $
    

    Show all files but those from the pentesting team, except their produced documents

    $ cat hide_pentest_but_docs.txt
    !pentesting/
    pentesting/research_docs/
    $
    

    The registry

    On Microsoft Windows, IDA Teams will store certain bits of information in the registry (host name, user name, site name.)

    On macOS and Linux, it will use a pseudo-registry file, located at $HOME/.idapro/hvui.reg.

    Passwords storage in the OS’s keychain

    While hosts, user names & site names are persisted to the registry, passwords are stored securely in the operating system’s keychain.

    • On Windows, the Windows Credential Store is used (therefore requiring Windows 7 or newer)
    • On macOS, the macOS Keychain is used
    • On Linux, the “Secret service” is used (through libsecret-1)

    Hex-Rays License Server Administrator Guide

    Introduction

    {% hint style=“info” %} To ensure proper functionality, we recommend that the License Server version match the IDA Pro version and that both are updated to the latest version. The 9.1 License Server has backward compatibility with the 9.0 IDA Pro version (client). However, the reverse is not supported. Ensure that the License Server version is equal to or higher than the client version to maintain compatibility.

    For the latest installers, visit the Download Center in My Hex-Rays portal. {% endhint %}

    This manual describes the installation, management, and interaction with a Hex-Rays License Server deployment. It is primarily intended for administrators, and will focus on the setup and management of the Hex-Rays License Server.

    While we will (at least superficially) make use of the command-line client used to access/manage the server, this manual will not offer a detailed explanation of its usage, although there is a dedicated section for essential lsadm commands

    Let’s get started

    The first step is to install the Hex-Rays License Server, which is the central component of the deployment.

    Installing the Hex-Rays License Server

    Prerequisites

    After your purchase of a Hex-Rays product with floating licenses, go to the customer portal, where you will find:

    • an installer for the Hex-Rays License Server
    • the installer for the product you have purchased
    • a license_server_<LID>.hexlic (where <LID> is your license ID) and the certificate bundle will be available after License Server activation, under Licenses tab

    All those will be necessary, so please go ahead and download them.

    Quick alternative {% hint style=“success” %}

    HCLI Commands | See HCLI Docs

    • hcli license get
    • hcli download {% endhint %}

    You will also need root access on the host where you will be installing the server.

    Installation

    This chapter explains how to install the Hex-Rays License Server.

    Installing clients

    The command-line client lsadm is bundled with the Hex-Rays License Server installer. To install both Hex-Rays License Server and lsadm, simply run the installer and follow the instructions.

    Every Hex-Rays product using floating licenses, such as IDA, is also a client of Hex-Rays License Server. For installation instructions for these products, please refer to their documentation.

    Installing the server

    The Hex-Rays License Server can be installed on x64 Linux servers. We have tested it on Debian and Ubuntu, but other major flavors of Linux should be fine too.

    The installer is provided as an executable file. If needed, use chmod to ensure it has execute permissions.

    To install the server, run the Hex-Rays License Server installer as root and follow the instructions (the server will not require root permissions; only the installer does.)

    {% hint style=“info” %} If your Linux system is based on systemd (e.g., Debian/Ubuntu, Red-Hat, CentOS, …​), it is recommended to let the installer create systemd units so that the server will start automatically at the next reboot. {% endhint %}

    {% hint style=“info” %} During server installation, you’ll be prompted to create the hexlicsrv.conf configuration file. We recommend accepting the default option to create it automatically, as this file is required to run the server. {% endhint %}

    Activating the server license

    In order for the Hex-Rays License Server license to be activated, it must be bound to a Host ID (an Ethernet MAC address.) From a command prompt, run /sbin/ifconfig, and lookup the "ether" address for the network interface through which the server will be accessible.

        >/sbin/ifconfig
        enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
                [...snipped...]
                ether bf:e2:91:10:58:d2  txqueuelen 1000  (Ethernet)
                [...snipped...]
    

    In this case, our MAC address is: bf:e2:91:10:58:d2

    Go to Hex-Rays customer portal and activate your license for license server. During that process, you will need to provide the MAC address of the device where the license server will be running. Once the activation is complete, you’ll be able to download the following files:

    • license server certificate bundle
    • license_server_<LID>.hexlic (license key)

    Those need to be copied in the Hex-Rays License Server installation directory. As root:

        >cd /opt/hexlicsrv
        >cp .../path/to/hexlicsrv.crt .
        >cp .../path/to/hexlicsrv.key .
        >cp .../path/to/license_server*.hexlic .
        >chown hexlicsrv:hexlicsrv hexlicsrv.crt hexlicsrv.key license_server*.hexlic
        >chmod 640 hexlicsrv.crt hexlicsrv.key license_server*.hexlic
    

    Creating the initial database

    At this point, the server should be ready to run.

    {% hint style=“caution” %} If your system is already in production, skip this section. Using the --recreate-schema option as in the example below, will re-create an empty database. {% endhint %}

    On the first install, you will need to initialize the database the server will use:

        >sudo -u hexlicsrv ./license_server --config-file hexlicsrv.conf \
                                            --certchain-file hexlicsrv.crt \
                                            --privkey-file hexlicsrv.key \
                                            --recreate-schema
        >2024-04-14 14:30:28 License Server v1.0 Hex-Rays (c) 2024
        >2024-04-14 14:30:28 Database initialized; exiting.
    

    Testing the server

    Now that the server is installed and has a database to work with, we can test that it works:

        >sudo -u hexlicsrv ./license_server --config-file hexlicsrv.conf \
                                            --certchain-file hexlicsrv.crt \
                                            --privkey-file hexlicsrv.key \
                                            --license-file license_server_<LID>.hexlic
        >2024-04-14 14:35:47 License Server v1.0 Hex-Rays (c) 2024
        >2024-04-14 14:35:47 Using a license with 1 seats
        >2024-04-14 14:35:47 Listening on 0.0.0.0:65434...
    

    Good, the server appears to run! If you are observing more worrying messages than this one, please refer to the troubleshooting section.

    At this point, you may want to either let the server run, or stop it (Ctrl+C will do) and restart it using systemd:

        >systemctl restart hexlicsrv.service
    

    …​and make sure it runs:

        >ps aux | grep license_server
        hexlicsrv  58246  0.0  0.0 ...
    

    If you don’t see a running license_server process, please refer to the systemd diagnostic tools (e.g., journalctl) for more info.

    Management

    This chapter explains in detail how to perform regular administrator tasks.

    Backup and restore

    Currently, there is no dedicated procedure to back up the Hex-Rays License Server database. It can be done by temporarily stopping the Hex-Rays License Server and making a copy of the sqlite3 database. The server must be stopped only during the backup of the sqlite3 database and then can be immediately restarted.

    Alternatively, it is possible to use sqlite3 backup functionality to make a backup of the database.

    Upgrading the server

    Switching to the newest versions of the Hex-Rays License Server is recommended in order for the team to benefit from its improvements and new features.

    The upgrade procedure consists of the following steps:

    1. Stop the server. For example, if you are using systemd to manage the server: sudo systemctl stop hexlicsrv

    2. Perform a backup of the database

    3. Launch the installer

    4. Follow the on-screen instructions

    5. Upgrade the database with ./license_server --config-file hexlicsrv.conf --upgrade-schema

    6. Restart the server. E.g., sudo systemctl start hexlicsrv

    License Borrowing Limits

    The server supports limiting the maximum duration for which licenses can be borrowed using the MAX_BORROW_HOURS environment variable.

    ExampleBehavior
    MAX_BORROW_HOURS=0 or unsetNo limit (default)
    MAX_BORROW_HOURS=-1Borrowing is completely disabled
    MAX_BORROW_HOURS=<hours>Limits borrowing to the specified number of hours

    Note: Changes to this environment variable require a server restart to take effect.

    Hex-Rays License Server command-line options

      -p ...​ (\--port-number ...​)         Port number (default 65434)
      -i ...​ (\--ip-address ...​)          IP address to bind to (default to any)
      -c ...​ (\--certchain-file ...​)      TLS certificate chain file
      -k ...​ (\--privkey-file ...​)        TLS private key file
      -v (\--verbose)                     Verbose mode
      (\--upgrade-schema)                 Upgrade database schema; then quit
      -C ...​ (\--connection-string ...​)   Connection string
      -l ...​ (\--log-file ...​)            Log file
      -L ...​ (\--license-file ...​)        License file
      -f ...​ (\--config-file ...​)         Config file
      (\--recreate-schema)                Drop & re-create schema; then quit **THIS WILL ERASE ALL DATA**
    

    Troubleshooting

    This chapter explains how to solve typical problems with the Hex-Rays License Server.

    Connection issues

    By default, the Hex-Rays License Server listens on the TCP port 65434 on all interfaces. Please ensure that this port is enabled in your firewalls.

    The Hex-Rays License Server uses secure TLS connections with the clients. The TLS layer requires the certificate (.crt) and private key (.key) files. Usually, they are attached to the email message with the activation information.

    The server complains about a "world-accessible" file, and exits

    The following files shouldn’t be readable by everyone on the system, but only by root and hexlicsrv:

    • hexlicsrv.conf: this file file holds the connection string to the database the server will use, and might contain credentials.
    • hexlicsrv.crt: the certificate chain
    • hexlicsrv.key: the private key file
    • license_server_<LID>.hexlic: the license file

    As a precaution, the Hex-Rays License Server will refuse to start if these files are readable by unauthorized users.

    Please make sure they:

    • have hexlicsrv:hexlicsrv ownership: chown hexlicsrv:hexlicsrv hexlicsrv.crt hexlicsrv.key licensesrv.hexlic hexlicsrv.conf
    • are not world-accessible: chmod 640 hexlicsrv.crt hexlicsrv.key license_server_<LID>.hexlic hexlicsrv.conf

    Licensing

    The licensesrv.hexlic file is tied to the MAC address of the first network interface. If they do not match, the server will not start. To change the MAC address, please contact support

    "Error: Failed to list licenses"

    This error means that the currently installed license server license file (hexlic) content is incorrect. More precisly, the “licenses” list does not contain an entry with the following items:

    ...
            "product_id": "IDAPRO",
            "edition_id": "ida-pro",
    ...
    

    or that the activation end date in the same section has expired.

    Make sure to activate all the floating license plans owned by the license server before downloading the license server hexlic file.

    “Error: stat() failed on “hexlicsrv.conf”: No such file or directory“

    This error occurs when the hexlicsrv.conf configuration file is missing.

    During the server installation, the user is asked whether to automatically create this configuration file for pre-configuring the server. Replying “no” will require creating the configuration file manually (which may be a bit tedious).

    Solution:
    The simplest approach is to reinstall the server:

    1. Uninstall the server by executing the uninstall program in the installation directory.
    2. Re-run the installer and accept the prompt to automatically create the configuration file.

    "Error: Failed to initialize the license manager: No valid license file could be found"

    This error can occur if a recent hexlic file is loaded in the version 9.0 of the license server.

    Solution Make sure to download and install the latest version of the license server.

    "Missing private key path" when upgrading the schema

    This is a known regression in the version 9.2 of the license server.

    Solution Use the following command line:

    >sudo -u hexlicsrv ./license_server --config-file hexlicsrv.conf \
                                            --certchain-file hexlicsrv.crt \
                                            --privkey-file hexlicsrv.key \
                                            --upgrade-schema
    

    Restoring from backups

    There are no special precautions to take: restoring the sqlite3 database from a backup should be enough.

    lsadm Tool Quick Guide

    This quick manual presents the basic common commands for lsadm tool.

    Note: Replace <IP_ADDRESS>:<PORT> with your actual server address and port.

    List All Licenses

    ./lsadm -h <IP_ADDRESS>:<PORT> list
    

    This command shows:

    • Licensed products and their IDs (IDA, License server, Teams Server or Lumina Server)
    • Add-ons/decompilers associated with each license
    • License start and expiration dates
    • Available and total seats
    • License owner information

    Example Output Structure

    Licenses (assigned to [email protected], <[email protected]>):
      License:
        License ID: 96-C43F-B0F4-96
        Product: IDAPRO
        Add-ons:
          HEXX86:
            License ID: 97-DCD8-46B5-86
            Owner ID: 96-C43F-B0F4-96
            Start: 2024-10-07
            Expiration: 2025-10-07
          <snipped>
        Features:
        Start: 2024-10-07
        Expiration: 2025-10-07
        Available seats: 32
        Total seats: 35
      License:
        License ID: 96-E735-E78D-9B
        Product: LICENSE_SERVER
        Add-ons:
        Features:
        Start: 2024-10-08
        Expiration: 2025-10-08
        Available seats: 1
        Total seats: 1
    

    Check Active and Borrowed Licenses

    ./lsadm -h <IP_ADDRESS>:<PORT> active
    

    This command shows:

    • currently used licenses
    • users using those licenses (both online and borrowed)
    • end dates for borrowed licenses

    Example Output Structure

    Active licenses:
      96-C43F-B0F4-96 IDAPRO (HEXX86, HEXX64, HEXARM, HEXMIPS, HEXARM64, HEXMIPS64, HEXPPC, HEXPPC64, HEXARC, HEXRV, TEAMS, LUMINA, HEXRV64): used 3 out of 35 seat(s)
      Expires: 2025-10-07
      Online users: root@secrethost (192.168.0.131): 1 instance(s)
      Borrowed by:  bob@chronos until 2025-03-14 17:10:32
                    alice@badger until 2025-10-01 00:00:00
    

    Display Server Information

    ./lsadm -h <IP_ADDRESS>:<PORT> info
    

    This command shows:

    • Server version
    • MAC address
    • Connected client details and session timestamp

    Example Output Structure

    Server info:
      Version: v1.0
      MAC address: AA:BB:CC:DD:EE:FF
      Client:
        Name: 192.168.0.104
        Session ID: 187
        Established: 2025-02-10 17:37:35
    

    Hex-Rays License Server Migration Guide

    Introduction

    Up to now our floating license management has been based around the following components:

    • the license server manager, lmadmin, provided by Flexera
    • the vendor daemon, hexrays, provided by Hex-Rays

    As of the IDA Pro new release (9.0) and its new licensing model these have been replaced by:

    • The Hex-Rays License Server, and
    • lsadm command line tool

    Both components are provided by Hex-Rays.

    Differences between the servers

    FlexeraHex-Rays
    Server setupTwo binaries and processes: lmadmin or lmdrd server + hexrays vendor daemonSingle binary (license_server)
    Ports requiredTwo ports required, plaintext communicationSingle TCP port, communication protected by TLS
    OS supportedServer available for Windows, Linux, or macOS x64. Manual service configuration on Linux.Server available for Linux x64 only. Automatic configuration of systemd service at install time.

    Migration steps

    Moving from the 8.4 to the 9.0 license server management infrastructure is really easy:

    • First make sure that you have the license server admin guide at hand.
    • Follow the installation steps (section 2 of the admin guide).
    • Install an IDA 9.0 instance and test your installation by trying to connect to the license server, to select a license, borrow and finally return it.

    You are now ready to switch.

    Attention points for the switch

    Since an 8.4 client will not be able to connect to the new license server (and a 9.0 client won’t be able to connect to the 8.4 license server), you should make sure that all users are using the new clients which are configured with the correct server and port. If your workflow requires using 8.4, you can keep the old server running until all users have switched to the new IDA version. Then you can stop and decommission the old server.

    Hex-Rays License Server on Windows with WSL: Configuration Guide

    Introduction

    This tutorial will guide you through the steps to configure Windows Subsystem for Linux (WSL) to install and use the new Hex-Rays license server in a WSL Ubuntu instance.

    You will learn how to:

    1. Properly configure the WSL and optionally make it run in the background.
    2. Install the Hex-Rays license server and verify it’s up and running.
    3. Troubleshoot common issues.

    Prerequisites

    To follow this tutorial:

    • Ensure you have an up-to-date Windows Subsystem for Linux with an installed Ubuntu distribution. If not, refer to this guide for installation instructions.
    • You should use Windows 11 version 22H2 or later, as we will enable the WSL mirrored mode networking.

    WSL configuration

    Mirrored mode

    Enabling mirrored mode configures WSL to an entirely new networking architecture that replicates (mirrors) your Windows network interfaces within the Linux environment.

    Create WSL configuration file

    1. To enable this mode, create a new file named %UserProfile%\\.wslconfig.
    2. Add the following lines to the file:
    [wsl2]
    networkingMode = mirrored
    
    1. Save the file.

    Verify mirrored network configuration

    1. First, make sure that all the WSL instances are stopped and restart a fresh Ubuntu instance:
    wsl --shutdown
    wsl
    
    1. In the WSL instance, type:
    ip a
    

    Examples comparison

    On our current machine, we have the following output:

    ...
    10: eth7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
        link/ether f4:7b:09:3f:7c:44 brd ff:ff:ff:ff:ff:ff
        inet 192.168.1.131/24 brd 192.168.1.255 scope global noprefixroute eth7
           valid_lft forever preferred_lft forever
        inet6 fe80::b944:ac9b:bd85:2a6c/64 scope link nodad noprefixroute
           valid_lft forever preferred_lft forever
    ...
    

    On Windows, ipconfig /all output gives matching details:

    ...
    Wireless LAN adapter Wi-Fi:
    
       Connection-specific DNS Suffix  . :
       Description . . . . . . . . . . . : Intel(R) Wi-Fi 6E AX210 160MHz
       Physical Address. . . . . . . . . : F4-7B-09-3F-7C-44
       DHCP Enabled. . . . . . . . . . . : Yes
       Autoconfiguration Enabled . . . . : Yes
       Link-local IPv6 Address . . . . . : fe80::b944:ac9b:bd85:2a6c%12(Preferred)
       IPv4 Address. . . . . . . . . . . : 192.168.1.131(Preferred)
       Subnet Mask . . . . . . . . . . . : 255.255.255.0
       Lease Obtained. . . . . . . . . . : Wednesday, February 19, 2025 7:35:07 PM
       Lease Expires . . . . . . . . . . : Sunday, February 23, 2025 7:09:58 AM
       Default Gateway . . . . . . . . . : 192.168.1.1
       DHCP Server . . . . . . . . . . . : 192.168.1.1
       DHCPv6 IAID . . . . . . . . . . . : 150240009
       DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-29-0A-D1-50-84-A9-38-6F-0B-65
       DNS Servers . . . . . . . . . . . : 192.168.1.1
       NetBIOS over Tcpip. . . . . . . . : Enabled
    ...
    

    When properly configured, the wireless interface is “mirrored” in the WSL Ubuntu instance, i.e., the Windows machine and the WSL Ubuntu instance share the Wifi interface IP and MAC address. In fact, all the Windows interfaces are mirrored, but we focus on wireless network interface.

    Systemd

    The Hex-Rays license server installation supports configuring the server as a systemd service. To use this feature, you should enable systemd in your WSL instance.

    1. Start a WSL Ubuntu instance as root:
    wsl -u root
    
    1. Use your preferred editor to create or add the following lines to the /etc/wsl.conf file:
    [boot]
    systemd = true
    
    1. Execute the following lines:
    wsl --shutdown
    wsl
    

    Networking

    To communicate with the WSL-hosted Hex-Rays license server from the network, you have to know the IP address of your WSL Ubuntu instance as seen by your Windows host.

    Use wsl hostname -i command to retrieve the IP address:

    wsl hostname -i
    127.0.1.1
    

    Setting up port forwarding

    To allow external connections to reach the license server, you must forward incoming connections from the Windows host to the Ubuntu instance. This is achieved using the port proxy interface.

    In this setup, we forward all connections coming to our Windows host on port 65435 to our license server listening on the default port 65434 in WSL.

    1. In an elevated command prompt, type the following command:
    netsh interface portproxy add v4tov4 listenport=65435 listenaddress=192.168.1.131 connectport=65434 connectaddress=127.0.1.1
    
    1. Verify the result:
    netsh interface portproxy show all
    
    Listen on ipv4:             Connect to ipv4:
    
    Address         Port        Address         Port
    --------------- ----------  --------------- ----------
    192.168.1.131   65435       127.0.1.1       65434
    

    Firewall configuration

    Finally, ensure that the Hyper-V firewall allows inbound connections on your port (in this example, 65434).

    1. Execute the following PowerShell command in an elevated command prompt:
    New-NetFirewallHyperVRule -Name "H-RLicenseServer" -DisplayName "Hex-Rays License Servr" -Direction Inbound -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -Protocol TCP -LocalPorts 65434
    
    1. If your setup requires it, you might have to open the TCP forwarding port (65435 in our case) in the Windows firewall.

    With this final step, the WSL networking configuration is complete.

    Running WSL in the background - optional configuration

    In a typical scenario, a WSL instance starts at system startup or within a command prompt, however when the command prompt is closed, WSL will silently stop after about a minute. To keep WSL running until it is explicitly stopped with wsl --shutdown, a simple script can be used.

    1. Create a script that executes the following command:
    wsl --exec dbus-launch true
    
    1. To verify if your instance is still running, use the following command:
    wsl --list --running
    Windows Subsystem for Linux Distributions:
    Ubuntu (Default)
    

    Installing the Hex-Rays license server

    After your WSL is properly configured, you can go ahead and install the Hex-Rays license server.

    The procedure to install the Hex-Rays license server can be found here.

    Verify the Hex-Rays license server is up and running

    To verify that the Hex-Rays license server is accessible, make the following checks:

    1. Check the network configuration

    In our exemplary case, we retrieved the IPv4 address of the Windows machine to ensure the correct network settings.

    1. Connect with Hex-Rays license server in IDA License Manager

    In the License Manager, we set a server address at 192.168.1.131 and port 65435.

    Troubleshooting

    License server connection fails after reboot

    We have noticed that for some reason, the Windows IP Helper service has to be restarted after rebooting your computer, otherwise an RST (Reset) response is received when trying to connect to the License server.

    The solution: Restart the IP Helper automatically

    Add this command to a startup script so that Windows runs it automatically after every reboot:

    Restart-Service -Name iphlpsvc