Skip to content

Commit a30cb60

Browse files
committed
feat: Implement Structor plugin for automated structure synthesis
This commit introduces the initial codebase for Structor, an IDA Pro/Hex-Rays plugin designed to reconstruct C structures from raw pointer arithmetic found in decompiled code. The plugin analyzes access patterns (e.g., `*(ptr + 8)`) to infer field offsets, sizes, and types, automatically generating and applying structure definitions to the IDB. include/structor/access_collector.hpp: - Implements AccessPatternVisitor, a ctree_visitor_t subclass that traverses Hex-Rays ASTs. - Collects memory access patterns (dereferences, member pointers, array indices) relative to a specific variable. - Records offset, size, and semantic context (read/write/call) for every access. include/structor/layout_synthesizer.hpp: - Implements the logic to transform raw access patterns into a coherent structure layout. - Handles conflict resolution for overlapping accesses (detecting unions). - Automatically inserts padding bytes to maintain alignment. - Infers field types based on usage context (e.g., float vs int, pointer vs value). include/structor/vtable_detector.hpp: - Adds logic to recognize C++ virtual table patterns (double dereferences followed by calls). - Synthesizes vtable structures with function pointer slots based on call indices. - Attempts to recover function signatures for vtable slots from call sites. include/structor/type_propagator.hpp: - Implements recursive type propagation to spread synthesized structures to callers and callees. - Supports configurable depth and direction (forward/backward) to maximize coverage. include/structor/pseudocode_rewriter.hpp: - Provides mechanisms to refresh the decompiler view and apply user comments. - Includes logic to highlight transformed expressions for visual feedback. include/structor/ui_integration.hpp: - Registers the "Synthesize Structure" action and binds it to Shift+S. - Installs Hex-Rays callback hooks to enable context menu integration. include/structor/api.hpp, src/python_bindings.cpp: - Exposes core functionality via IDC and IDAPython (structor_synthesize). - Allows headless/batch operation for automated analysis pipelines. CMakeLists.txt, Makefile: - Sets up the build system for the plugin, targeting the IDA SDK. - Configures GoogleTest integration for unit testing. integration_tests/: - Adds a comprehensive suite of C test binaries (vtable, linked list, nested structs) and IDAPython scripts to validate synthesis accuracy. Impact: - Users can now position the cursor on a void* variable in the decompiler and press Shift+S to automatically generate a typed structure. - Reduces manual effort required to reverse engineer complex data structures. - Introduces a new binary dependency (structor64.dylib/so/dll) to the plugin directory.
0 parents  commit a30cb60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+12421
-0
lines changed

.github/workflows/build.yml

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
name: Build Structor Plugin
2+
3+
on:
4+
push:
5+
branches: [ master, main ]
6+
tags: [ 'v*' ]
7+
pull_request:
8+
branches: [ master, main ]
9+
workflow_dispatch:
10+
11+
env:
12+
IDA_SDK_REPO: HexRaysSA/ida-sdk
13+
14+
jobs:
15+
build:
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
include:
20+
- os: macos-latest
21+
name: macos-x86_64
22+
cmake_arch: x86_64
23+
- os: macos-latest
24+
name: macos-arm64
25+
cmake_arch: arm64
26+
- os: ubuntu-latest
27+
name: linux-x86_64
28+
- os: windows-latest
29+
name: windows-x86_64
30+
cmake_arch: x64
31+
32+
runs-on: ${{ matrix.os }}
33+
name: Build ${{ matrix.name }}
34+
35+
steps:
36+
- name: Checkout repository
37+
uses: actions/checkout@v4
38+
with:
39+
submodules: recursive
40+
41+
- name: Checkout IDA SDK
42+
uses: actions/checkout@v4
43+
with:
44+
repository: ${{ env.IDA_SDK_REPO }}
45+
path: ida-sdk
46+
47+
- name: Setup MSVC (Windows)
48+
if: runner.os == 'Windows'
49+
uses: ilammy/msvc-dev-cmd@v1
50+
with:
51+
arch: ${{ matrix.cmake_arch }}
52+
53+
- name: Install dependencies (Linux)
54+
if: runner.os == 'Linux'
55+
run: |
56+
sudo apt-get update
57+
sudo apt-get install -y build-essential cmake
58+
59+
- name: Configure CMake (macOS)
60+
if: runner.os == 'macOS'
61+
run: |
62+
mkdir -p build
63+
cd build
64+
cmake .. \
65+
-DCMAKE_BUILD_TYPE=Release \
66+
-DCMAKE_OSX_ARCHITECTURES=${{ matrix.cmake_arch }} \
67+
-DIDA_SDK_DIR=${{ github.workspace }}/ida-sdk/src
68+
69+
- name: Configure CMake (Linux)
70+
if: runner.os == 'Linux'
71+
run: |
72+
mkdir -p build
73+
cd build
74+
cmake .. \
75+
-DCMAKE_BUILD_TYPE=Release \
76+
-DIDA_SDK_DIR=${{ github.workspace }}/ida-sdk/src
77+
78+
- name: Configure CMake (Windows)
79+
if: runner.os == 'Windows'
80+
run: |
81+
mkdir build -Force
82+
cd build
83+
cmake .. -G "Visual Studio 17 2022" -A ${{ matrix.cmake_arch }} -DIDA_SDK_DIR=${{ github.workspace }}/ida-sdk/src
84+
85+
- name: Build (Unix)
86+
if: runner.os != 'Windows'
87+
run: |
88+
cd build
89+
cmake --build . --config Release -j$(nproc 2>/dev/null || sysctl -n hw.ncpu)
90+
91+
- name: Build (Windows)
92+
if: runner.os == 'Windows'
93+
run: |
94+
cd build
95+
cmake --build . --config Release
96+
97+
- name: Find built plugin (Unix)
98+
if: runner.os != 'Windows'
99+
id: find_plugin_unix
100+
run: |
101+
if [ "${{ runner.os }}" = "macOS" ]; then
102+
PLUGIN_FILE=$(find build -name "structor64.dylib" -type f | head -1)
103+
EXT="dylib"
104+
else
105+
PLUGIN_FILE=$(find build -name "structor64.so" -type f | head -1)
106+
EXT="so"
107+
fi
108+
109+
if [ -z "$PLUGIN_FILE" ]; then
110+
echo "ERROR: Could not find built plugin"
111+
find build -type f -name "structor*"
112+
exit 1
113+
fi
114+
115+
echo "plugin_file=$PLUGIN_FILE" >> $GITHUB_OUTPUT
116+
echo "extension=$EXT" >> $GITHUB_OUTPUT
117+
echo "Found plugin: $PLUGIN_FILE"
118+
119+
- name: Find built plugin (Windows)
120+
if: runner.os == 'Windows'
121+
id: find_plugin_windows
122+
shell: pwsh
123+
run: |
124+
$plugin = Get-ChildItem -Path build -Recurse -Filter "structor64.dll" | Select-Object -First 1
125+
if ($null -eq $plugin) {
126+
Write-Error "Could not find built plugin"
127+
Get-ChildItem -Path build -Recurse -Filter "structor*"
128+
exit 1
129+
}
130+
echo "plugin_file=$($plugin.FullName)" >> $env:GITHUB_OUTPUT
131+
echo "extension=dll" >> $env:GITHUB_OUTPUT
132+
Write-Host "Found plugin: $($plugin.FullName)"
133+
134+
- name: Prepare artifact (Unix)
135+
if: runner.os != 'Windows'
136+
run: |
137+
mkdir -p artifacts
138+
cp "${{ steps.find_plugin_unix.outputs.plugin_file }}" "artifacts/structor64_${{ matrix.name }}.${{ steps.find_plugin_unix.outputs.extension }}"
139+
140+
- name: Prepare artifact (Windows)
141+
if: runner.os == 'Windows'
142+
shell: pwsh
143+
run: |
144+
New-Item -ItemType Directory -Force -Path artifacts
145+
Copy-Item "${{ steps.find_plugin_windows.outputs.plugin_file }}" "artifacts/structor64_${{ matrix.name }}.${{ steps.find_plugin_windows.outputs.extension }}"
146+
147+
- name: Upload artifact
148+
uses: actions/upload-artifact@v4
149+
with:
150+
name: structor-${{ matrix.name }}
151+
path: artifacts/
152+
retention-days: 30
153+
154+
release:
155+
if: startsWith(github.ref, 'refs/tags/v')
156+
needs: build
157+
runs-on: ubuntu-latest
158+
permissions:
159+
contents: write
160+
161+
steps:
162+
- name: Download all artifacts
163+
uses: actions/download-artifact@v4
164+
with:
165+
path: artifacts
166+
167+
- name: Prepare release files
168+
run: |
169+
mkdir -p release
170+
find artifacts -type f \( -name "*.dylib" -o -name "*.so" -o -name "*.dll" \) -exec cp {} release/ \;
171+
ls -la release/
172+
173+
- name: Create Release
174+
uses: softprops/action-gh-release@v1
175+
with:
176+
files: release/*
177+
generate_release_notes: true
178+
draft: false
179+
prerelease: ${{ contains(github.ref, '-') }}
180+
env:
181+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Build directories
2+
build/
3+
cmake-build-*/
4+
out/
5+
6+
# CMake generated files
7+
CMakeCache.txt
8+
CMakeFiles/
9+
cmake_install.cmake
10+
install_manifest.txt
11+
CTestTestfile.cmake
12+
*.ninja
13+
.ninja_deps
14+
.ninja_log
15+
16+
# Compiled Object files
17+
*.o
18+
*.obj
19+
*.lo
20+
*.slo
21+
22+
# Precompiled Headers
23+
*.gch
24+
*.pch
25+
26+
# Compiled Dynamic libraries
27+
*.so
28+
*.dylib
29+
*.dll
30+
31+
# Compiled Static libraries
32+
*.a
33+
*.lib
34+
*.la
35+
36+
# Executables
37+
*.exe
38+
*.out
39+
*.app
40+
41+
# IDA Pro files
42+
*.i64
43+
*.idb
44+
*.id0
45+
*.id1
46+
*.id2
47+
*.nam
48+
*.til
49+
*.bnm
50+
51+
# macOS
52+
.DS_Store
53+
.AppleDouble
54+
.LSOverride
55+
._*
56+
57+
# Linux
58+
*~
59+
.directory
60+
61+
# Windows
62+
Thumbs.db
63+
Desktop.ini
64+
65+
# IDEs and editors
66+
.vscode/
67+
.idea/
68+
*.swp
69+
*.swo
70+
*~
71+
.project
72+
.cproject
73+
.settings/
74+
*.code-workspace
75+
76+
# Logs and databases
77+
*.log
78+
*.sql
79+
*.sqlite
80+
81+
# Temporary files
82+
*.tmp
83+
*.temp
84+
*.bak
85+
*.orig
86+
87+
# Temporary test files
88+
foo
89+
foo.c
90+
91+
# Test binaries
92+
tests/string_obfuscation/test_strings
93+
*.dSYM/
94+
95+
.cache
96+
.claude

0 commit comments

Comments
 (0)