Skip to content

Commit

Permalink
pe: Add tests for TLS parser and characteristics constants (#426)
Browse files Browse the repository at this point in the history
* pe: add tests for TLS parser and characteristics constants
* Fix panic on malformed callbacks may cause subtract with overflow
* Add reproducible cxx project
  • Loading branch information
kkent030315 authored Dec 17, 2024
1 parent 48da3d8 commit 19d88ec
Show file tree
Hide file tree
Showing 12 changed files with 825 additions and 1 deletion.
413 changes: 413 additions & 0 deletions etc/projects/bingen/.gitignore

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions etc/projects/bingen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.12)
project(bingen LANGUAGES CXX)
option(ENABLE_TLS "Whether to generate TLS in resulting binary" ON)

if(ENABLE_TLS)
add_definitions(-DENABLE_TLS)
endif()

set(CMAKE_SYSTEM_NAME Windows)

add_executable(bin WIN32 "main.cc")
set_target_properties(bin PROPERTIES LANGUAGE CXX)
target_compile_options(bin PRIVATE
/GS- # Disable generation of stack check handlers
/GL # Enable whole program optimization
)
target_link_options(bin PRIVATE
/ENTRY:main # Explicit entry symbol since there are no CRT/libs to be linked
/MANIFEST:NO # Disable manifest
/NODEFAULTLIB # No libs; we want a pure binary
/FIXED # No relocs
/DYNAMICBASE:NO # No ASLR
/SAFESEH # No unwinds
/MERGE:.data=.text /MERGE:.CRT=.text /MERGE:.tls=.text # Combine sections to avoid paddings
)
63 changes: 63 additions & 0 deletions etc/projects/bingen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Test binary generator for Portable Executable

## Preprocessor definitions

- `ENABLE_TLS`: if defined, compile the binary with Thread Local Storage (TLS) enabled.

## How to build

This project is designed to be compiled by Clang (`clang-cl`) _not_ MSVC toolchain, primarily because 1) MSVC linker supports more features and may unexpectedly generate larger binaries than LLD linker under Clang, 2) compiler and linker flags are designed for specifically Clang for best efforts in reducing size of the resulting binary, 3) sometimes LLD links much smarter e.g., metadatas such as unnecessary rich headers (can be disabled by `/EMITTOOLVERSIONINFO:NO`).

While MSVC toolchains are theoretically possible; but not recommended.

### CMake

**Prerequisites**
- 64-bit Windows host
- CMake 3.12 or later
- [Ninja build system](https://ninja-build.org) (any version)
- Clang (ideally 17 or later)

Firstly run the following commands on terminal:

```bash
mkdir build
```

```bash
cd build
```

```bash
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang-cl
```

Then build the binary:

```bash
cmake --build . --config release
```

### Visual Studio

**Prerequisites**
- 64-bit Windows host
- Visual Studio 2022 (editions do not matter)
- C++ Clang Compiler for Windows [or this method if you have manual installation](#optional-referencing-manually-installed-clang-toolchain)
- MSBuild support for LLVM (clang-cl) toolset

Open `bingen.sln` under [`etc/projects/bingen`](etc/projects/bingen/) and compile as Release (Debug configuration is redacted).

#### Optional: Referencing manually-installed Clang toolchain

If you do not have or not willing to install Clang under Visual Studio individual components, [customize the build by folder for MSBuild](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022) by deploying following `Directory.build.props` right next to the `.sln`:

```xml
<!-- Directory.build.props -->
<Project>
<PropertyGroup>
<LLVMInstallDir>C:/path/to/llvm/bin</LLVMInstallDir>
<LLVMToolsVersion>xx.xxxx.x</LLVMToolsVersion>
</PropertyGroup>
</Project>
```
22 changes: 22 additions & 0 deletions etc/projects/bingen/bingen.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35527.113
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bingen", "bingen.vcxproj", "{45EE6877-125F-49B9-9837-D91D38F6C2A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x64.ActiveCfg = Release|x64
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x64.Build.0 = Release|x64
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x86.ActiveCfg = Release|Win32
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
91 changes: 91 additions & 0 deletions etc/projects/bingen/bingen.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{45EE6877-125F-49B9-9837-D91D38F6C2A3}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="main.cc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>ClangCL</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ENABLE_TLS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>main</EntryPointSymbol>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<FixedBaseAddress>true</FixedBaseAddress>
<MergeSections>/MERGE:.data=.text /MERGE:.CRT=.text /MERGE:.tls=.text</MergeSections>
<ImageHasSafeExceptionHandlers>true</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
46 changes: 46 additions & 0 deletions etc/projects/bingen/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <Windows.h>

#if !(_WIN64)
#error "Only x64 is supported"
#endif

#ifdef ENABLE_TLS
EXTERN_C unsigned int _tls_index{};
static void NTAPI tls_callback(PVOID, DWORD, PVOID) {}

// Force include unreferenced symbols
// Marker symbol to tell the linker that TLS is being used
#pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:_tls_callback")

#pragma data_seg(".tls")
int _tls_start = 0;
#pragma const_seg()

#pragma data_seg(".tls$ZZZ")
int _tls_end = 0;
#pragma const_seg()

#pragma data_seg(".CRT$XLA")
int __xl_a = 0;
#pragma const_seg()

#pragma data_seg(".CRT$XLZ")
int __xl_z = 0;
#pragma const_seg()

#pragma const_seg(".CRT$XLB")
EXTERN_C const PIMAGE_TLS_CALLBACK _tls_callback[] = { &tls_callback, 0 };
#pragma const_seg()

EXTERN_C IMAGE_TLS_DIRECTORY _tls_used = {
/*StartAddressOfRawData*/(ULONG64)&_tls_start,
/*EndAddressOfRawData*/(ULONG64)&_tls_end,
/*AddressOfIndex*/(ULONG64)&_tls_index,
/*AddressOfCallbacks*/(ULONG64)&_tls_callback,
/*SizeOfZeroFill*/0,
/*Characteristics*/{0},
};
#endif // #ifdef ENABLE_TLS

int main() { return 0; }
Loading

0 comments on commit 19d88ec

Please sign in to comment.