Skip to content

Commit

Permalink
Initial commit of the Linux FontSub.dll loader
Browse files Browse the repository at this point in the history
  • Loading branch information
j00ru committed Aug 28, 2019
1 parent 8ee4b37 commit cf49a52
Show file tree
Hide file tree
Showing 5 changed files with 771 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ BrokenType is a set of tools designed to test the robustness and security of fon
- **[TTF/OTF loader for Windows GDI](ttf-otf-windows-loader)** - a utility for loading and testing custom fonts with Windows GDI / Uniscribe.
- **[TTF/OTF loader for DirectWrite](ttf-otf-dwrite-loader)** - a utility for loading and testing custom fonts with the Microsoft DirectWrite API.
- **[TTF loader for Windows FontSub.dll](ttf-fontsub-loader)** - a utility for loading and testing custom fonts with the Font Subsetting library.
- **[Linux PE loader for FontSub.dll](fontsub-dll-on-linux)** - a minimal PE loader for Linux, tailored for fuzzing the Windows subsetter.
- **[PDF font embedders](font2pdf)** - Python scripts for generating PDF documents which embed the specified fonts and display all of their glyphs.

The description and usage instructions of the utilities can be found in their corresponding READMEs.
Expand Down
18 changes: 18 additions & 0 deletions fontsub-dll-on-linux/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CXX=g++
LD=g++
CXXFLAGS=-m32 -DDEBUG
LDFLAGS=-lpe-parser-library -ldl -m32
DEPS=fontsub.h
SRCS=loader.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: loader

%.o: %.cc $(DEPS)
$(CXX) -c -o $@ $< $(CXXFLAGS)

loader: $(OBJS)
$(LD) -o $@ $< $(LDFLAGS)

clean:
$(RM) loader $(OBJS)
117 changes: 117 additions & 0 deletions fontsub-dll-on-linux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Linux DLL loader for the Windows Font Subsetting Library (FontSub.dll)

This project is an equivalent of the [Windows FontSub Harness](https://github.com/googleprojectzero/BrokenType/tree/master/ttf-fontsub-loader), but aimed to run on Linux, by introducing a thin PE loading component. It is capable of mapping the PE sections in the Linux address space, setting the requested memory access rights, redirecting `msvcrt.dll` imports to the corresponding libc functions, providing custom stubs for other imports, and handling basic relocations. As it turns out, the `FontSub.dll` library is simple and self-contained enough that this is sufficient to have it run on Linux.

The benefit to this approach is that with the harness, all typical Linux fuzzing tools become available:
- You can use [AFL](http://lcamtuf.coredump.cx/afl/), [honggfuzz](https://github.com/google/honggfuzz), or your favourite Linux-based fuzzer.
- You can use custom allocators, either by compiling them in, or injecting them through `LD_PRELOAD` (e.g. AFL's [libdislocator](https://github.com/google/afl/tree/master/libdislocator)).
- You can use performance improvements such as a "Fork Server", which are easier to implement on Linux.
- You can use additional DBI such as [Intel Pin](https://software.intel.com/en-us/articles/pin-a-dynamic-binary-instrumentation-tool) or [DynamoRIO](https://www.dynamorio.org/), which in our experience work most reliably on Linux.

The program is meant to serve as a proof-of-concept and reference for quickly developing simple Linux DLL loaders for specialized tasks. Another more complex and mature project of this kind is Tavis Ormandy's [loadlibrary](https://github.com/taviso/loadlibrary).

We used a similar tool for fuzzing a JPEG2000 decoder in VMware Workstation in 2016, see slides 195-208 of the [Windows Metafiles - An Analysis of the EMF Attack Surface & Recent Vulnerabilities](https://j00ru.vexillium.org/slides/2016/metafiles_full.pdf) presentation.

## Requirements

The tool uses the [pe-parse](https://github.com/trailofbits/pe-parse) library for a majority of the PE-related work. You also obviously need the Windows `FontSub.dll` system file to execute.

## Building

With `pe-parse` installed in the system, simply type `make` in the project directory:

```
$ make
g++ -c -o loader.o loader.cc -m32 -DDEBUG
g++ -o loader loader.o -lpe-parser-library -ldl -m32
$
```

## Usage

Before using the loader, please note that some recent versions of the FontSub library contain telemetry functions such as `LogCreateFontPackage` and `LogMergeFontPackage`, called at the end of the exported routines, e.g.:

```
.text:0000000180001345 loc_180001345: ; CODE XREF: CreateFontPackage+C1
.text:0000000180001345 ; CreateFontPackage+161
.text:0000000180001345 movzx ebx, r10w
.text:0000000180001349 mov ecx, ebx ; unsigned int
.text:000000018000134B call LogCreateFontPackage
.text:0000000180001350 mov eax, ebx
```

These functions will call unimplemented Win32 API imports and crash the loader. Since their execution is not essential to the correct functioning of the subsetter, you might consider disabling them in your copy of the DLL.

Then, just pass the path of the library, path of the input TrueType, and optionally the desired image base:

```
$ ./loader fontsub.dll times.ttf 0x20000000
[+] Provided fontsub.dll file successfully parsed.
[*] Attempting to map section .text base 20001000, size 88576
[+] SUCCESS!
[*] Attempting to map section .data base 20017000, size 1536
[+] SUCCESS!
[*] Attempting to map section .idata base 20018000, size 2048
[+] SUCCESS!
[*] Attempting to map section .rsrc base 20019000, size 1024
[+] SUCCESS!
[*] Attempting to map section .reloc base 2001a000, size 2560
[+] SUCCESS!
[...]
[*] Resolving the MSVCRT.DLL!memmove import.
[+] Function memmove found in libc at address 0xf7b53690.
[*] Resolving the MSVCRT.DLL!memcmp import.
[+] Function memcmp found in libc at address 0xf7b688e0.
[*] Resolving the MSVCRT.DLL!memcpy import.
[+] Function memcpy found in libc at address 0xf7b53050.
[*] Resolving the MSVCRT.DLL!memset import.
[+] Function memset found in libc at address 0xf7b51e20.
[...]
[*] Setting desired access rights for section .text
[+] SUCCESS!
[*] Setting desired access rights for section .data
[+] SUCCESS!
[*] Setting desired access rights for section .idata
[+] SUCCESS!
[*] Setting desired access rights for section .rsrc
[+] SUCCESS!
[*] Setting desired access rights for section .reloc
[+] SUCCESS!
[+] Located CreateFontPackage at 0x20002500, MergeFontPackage at 0x20002630.
[A] malloc(0x168) ---> 0x573eebb0
[A] malloc(0x121b) ---> 0x573f3780
[A] malloc(0x14) ---> 0x573ed7d0
[A] malloc(0x490) ---> 0x573eed20
[A] malloc(0xfae) ---> 0x573f49a0
[A] free(0x573eed20)
[A] free(0x573f49a0)
[...]
[A] free(0xf79a1010)
[+] CreateFontPackage([ 1162804 bytes ], TTFCFP_SUBSET) ---> 0 (344996 bytes)
[A] realloc((nil), 0x543a4) ---> 0x573f7a20
[A] free(0x573f7a20)
[+] MergeFontPackage(NULL, [ 344996 bytes ], TTFMFP_SUBSET) ---> 0 (344996 bytes)
$
```

There are a lot of debug messages in the above output. If you build the tool without `-DDEBUG`, the output is much cleaner:

```
$ ./loader fontsub.dll times.ttf 0x20000000
[+] CreateFontPackage([ 1162804 bytes ], TTFCFP_SUBSET) ---> 0 (344996 bytes)
[+] MergeFontPackage(NULL, [ 344996 bytes ], TTFMFP_SUBSET) ---> 0 (344996 bytes)
$
```

## Limitations

The harness currently only supports x86 `FontSub.dll` modules, but adding support for x64 images should be relatively straightforward.

However, in a more general scenario, there are a number of differences between the Windows and Linux runtime environments, and the MSVC/gcc/clang compilers. They may result in compatbility problems with varying degrees of difficulty to solve. For instance:
- `sizeof(long)` is 4 on 64-bit Windows, but 8 on 64-bit Linux.
- Both systems have [different](https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions) calling conventions on the x64 architecture. This can be somewhat mitigated by using the `ms_abi` attribute for external function prototypes.
- Accessing the TEB/PEB Windows structures through segment registers like `fs` or `gs` will most likely crash the loader, if some kind of emulation is not developed. They may be directly referenced in code to make use of the [SEH](https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling) mechanism (in built-in functions such as `_SEH_prolog4` and `_SEH_epilog4`), dynamic stack allocations (`alloca()`, to get the stack base address) etc.
- The exception handling architecture is vastly different in Windows/Linux, and so a target which makes extensive use of them may be problematic. Furthermore, standard C++ exceptions are implemented with the `RaiseException` API on Windows, which is not provided by the harness at the moment.

Last but not least, all external Windows API functions used by the library in question must be emulated or at least stubbed out, which may range from a simple to an almost impossible task.

57 changes: 57 additions & 0 deletions fontsub-dll-on-linux/fontsub.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/////////////////////////////////////////////////////////////////////////
//
// Author: Mateusz Jurczyk ([email protected])
//
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef FONTSUB_H_
#define FONTSUB_H_

// Standard FontSub constants from the Windows SDK (fontsub.h).

/* for usSubsetFormat */
#define TTFCFP_SUBSET 0 /* Straight Subset Font - Backward compatibility */
#define TTFCFP_SUBSET1 1 /* Subset font with full TTO and Kern tables. For later merge */
#define TTFCFP_DELTA 2 /* Delta font, for merge with a subset1 font */

/* for usSubsetPlatform */
#define TTFCFP_UNICODE_PLATFORMID 0
#define TTFCFP_APPLE_PLATFORMID 1
#define TTFCFP_ISO_PLATFORMID 2
#define TTFCFP_MS_PLATFORMID 3

/* for usSubsetEncoding */
#define TTFCFP_STD_MAC_CHAR_SET 0 /* goes with TTFSUB_APPLE_PLATFORMID */
#define TTFCFP_SYMBOL_CHAR_SET 0 /* goes with TTFSUB_MS_PLATFORMID */
#define TTFCFP_UNICODE_CHAR_SET 1 /* goes with TTFSUB_MS_PLATFORMID */
#define TTFCFP_DONT_CARE 0xFFFF

/* for usSubsetLanguage */
#define TTFCFP_LANG_KEEP_ALL 0

/* for usFlags */
#define TTFCFP_FLAGS_SUBSET 0x0001 /* if bit off, don't subset */
#define TTFCFP_FLAGS_COMPRESS 0x0002 /* if bit off, don't compress */
#define TTFCFP_FLAGS_TTC 0x0004 /* if bit off, its a TTF */
#define TTFCFP_FLAGS_GLYPHLIST 0x0008 /* if bit off, list is characters */

/* for usModes */
#define TTFMFP_SUBSET 0 /* copy a Straight Subset Font package to Dest buffer */
#define TTFMFP_SUBSET1 1 /* Expand a format 1 font into a format 3 font */
#define TTFMFP_DELTA 2 /* Merge a format 2 with a format 3 font */

#endif // FONTSUB_H_

Loading

0 comments on commit cf49a52

Please sign in to comment.