Skip to main content

When to Create Definitions

You should create custom API definitions when:
  • Analyzing applications that use undocumented Windows APIs
  • Reverse engineering custom DLLs or internal libraries
  • Working with third-party libraries not in the default definitions
  • Adding missing functions from Windows APIs
  • Defining internal functions within the target application

Prerequisites

Before creating definitions, ensure you have:
  1. x64dbg with xAnalyzer installed - The plugin must be functional
  2. Access to the APIs definition folder - Located at <x64dbg>/apis_def/
  3. Function documentation - MSDN docs, header files, or reverse engineering notes
  4. Text editor - Any editor that can save plain text files

Step-by-Step: Creating a Definition File

Step 1: Identify the Target Module

Determine which DLL or module contains the functions you want to define. Example: You’re analyzing a custom DLL called CustomLib.dll

Step 2: Create the .api File

In the apis_def directory, create a new file:
CustomLib.api
The filename must match the module name (without the .dll extension) exactly, including capitalization.

Step 3: Define Your First Function

Let’s say CustomLib.dll has a function InitializeLibrary with this prototype:
BOOL InitializeLibrary(
    LPCSTR configPath,
    DWORD flags,
    LPVOID reserved
);
Add this to CustomLib.api:
[InitializeLibrary]
1=LPCSTR configPath
2=DWORD flags
3=LPVOID reserved
ParamCount=3
@=InitializeLibrary

Step 4: Add More Functions

Continue adding functions to the same file:
[GetLibraryVersion]
ParamCount=0
@=GetLibraryVersion

[ProcessData]
1=LPBYTE pData
2=SIZE_T dataSize
3=DWORD options
ParamCount=3
@=ProcessData

[CleanupLibrary]
ParamCount=0
@=CleanupLibrary

Step 5: Test Your Definitions

  1. Restart x64dbg - Or reload the plugin to refresh definitions
  2. Load your target - Open the executable that uses your custom DLL
  3. Run analysis - Use xAnalyzer’s “Analyze Module” or “Analyze Function”
  4. Verify results - Check that function calls are now annotated correctly

Adding Custom Types

For parameters with specific flag or enum values, create a header file.

Step 1: Create a Header File

In apis_def/headers/, create:
CustomLib.h.api

Step 2: Define Flags

Let’s define the flags parameter from our example:
[InitFlags]
TypeDisplay=DWORD
Base=DWORD
Type=Flag
Const1=INIT_FLAG_VERBOSE
Value1=0x00000001
Const2=INIT_FLAG_DEBUG
Value2=0x00000002
Const3=INIT_FLAG_NO_CACHE
Value3=0x00000004
Const4=INIT_FLAG_FORCE_RELOAD
Value4=0x00000008

Step 3: Reference the Type

Update the function definition in CustomLib.api:
[InitializeLibrary]
1=LPCSTR configPath
2=[InitFlags] flags
3=LPVOID reserved
ParamCount=3
Header=CustomLib.h.api;
@=InitializeLibrary
Now xAnalyzer will resolve values like 0x00000003 to INIT_FLAG_VERBOSE | INIT_FLAG_DEBUG.

Real-World Example: Adding Missing Windows API

Suppose NtQueryInformationProcess is missing from ntdll.api:

Research the Function

From documentation:
NTSTATUS NtQueryInformationProcess(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
);

Add to ntdll.api

[NtQueryInformationProcess]
1=[ProcessHandle] ProcessHandle
2=[PROCESSINFOCLASS] ProcessInformationClass
3=PVOID ProcessInformation
4=ULONG ProcessInformationLength
5=PULONG ReturnLength
ParamCount=5
Header=ntdll.h.api;
@=NtQueryInformationProcess

Define the Enum in ntdll.h.api

[PROCESSINFOCLASS]
TypeDisplay=DWORD
Base=DWORD
Type=Enum
Const1=ProcessBasicInformation
Value1=0
Const2=ProcessQuotaLimits
Value2=1
Const3=ProcessIoCounters
Value3=2
Const4=ProcessVmCounters
Value4=3
Const5=ProcessTimes
Value5=4

Tips for Success

Prefer DWORD, LPVOID, HANDLE over custom types unless the parameter has special meaning.
Add comments in your definitions (as INI comments with ;) to note sources or special cases.
Submit useful definitions back to the xAnalyzer repository so others can benefit.
Verify your definitions work on multiple call sites to ensure correctness.

Common Pitfalls

Mismatched ParamCount - Ensure ParamCount matches the number of parameter lines exactly.
Missing Header Reference - If you use custom types like [FlagName], you must include Header=filename.h.api;
Case Sensitivity - Function names and filenames are case-sensitive. Match the actual export names.
Semicolon in Header Field - Always end the Header line with a semicolon, even with one file.

Template for New Definitions

Basic Function

[FunctionName]
1=TYPE param1
2=TYPE param2
ParamCount=2
@=FunctionName

Function with Custom Types

[FunctionName]
1=[CustomType] param1
2=TYPE param2
ParamCount=2
Header=module.h.api;
@=FunctionName

Function with No Parameters

[FunctionName]
ParamCount=0
@=FunctionName

Workflow Summary

1

Research

Find function signatures from documentation, headers, or reverse engineering.
2

Create .api File

Name it after the module (e.g., module.api) in the apis_def/ directory.
3

Define Functions

Add INI sections for each function with parameters and ParamCount.
4

Create Header (Optional)

If using custom types, create module.h.api in apis_def/headers/.
5

Test

Restart x64dbg and run xAnalyzer on code using your functions.
6

Refine

Adjust definitions based on analysis results and add missing details.

Contributing Definitions

If you create useful definitions, consider contributing them:
  1. Fork the repository - xAnalyzer is on GitHub
  2. Add your files - Place .api and .h.api files in appropriate directories
  3. Test thoroughly - Ensure definitions work on various binaries
  4. Submit a pull request - Include notes about what you added
  5. Follow conventions - Match the existing style and naming patterns

Next Steps

Header Files

Deep dive into enum and flag definitions

File Format Reference

Complete syntax reference for .api files

GitHub Repository

Browse existing definitions and contribute

Configuration

Configure how xAnalyzer processes definitions

Build docs developers (and LLMs) love