Skip to content

Implement C-style printf specifiers and BeaconFormat API suite#6

Open
chvancooten wants to merge 1 commit intopraetorian-inc:mainfrom
chvancooten:feat/beacon-format
Open

Implement C-style printf specifiers and BeaconFormat API suite#6
chvancooten wants to merge 1 commit intopraetorian-inc:mainfrom
chvancooten:feat/beacon-format

Conversation

@chvancooten
Copy link
Contributor

This PR significantly improves the compatibility and output quality of the Beacon API implementation. It addresses artifacting issues in BeaconPrintf output and implements the missing BeaconFormat* API suite, which is required by some modern BOFs (e.g., ChromeKatz).

Problem

The previous BeaconPrintf implementation used a primitive manual parser that only explicitly handled %s and %p, falling back to Go's default fmt.Sprintf for other specifiers. Since arguments are passed as uintptr values, specifiers like %S (wide strings) or %i (integers) would print the raw memory address (e.g., %!S(uintptr=...)) instead of the intended value.

Furthermore, the BeaconFormat* functions were stubs that fell through to default handlers, causing BOFs that rely on dynamic output buffering to fail or crash.

Changes

1. Robust Printf Parsing (formatPrintf)
Implemented a comprehensive C-style printf parser that supports:

  • Comprehensive Specifiers: Support for %s, %S, %c, %C, %p, %d, %i, %u, %x, %X, %o, %f, etc.
  • Wide String Support: Properly handles %S (and %ls/%ws) by utilizing a fixed ReadWStringFromPtr to decode UTF-16 code units.
  • Flags, Width, and Precision: Supports standard C flags (+, -, #, 0, space) and dynamic * width/precision.
  • Heuristic String Detection: Added a heuristic to better distinguish between ANSI and UTF-16 strings when specifiers are ambiguous.

2. BeaconFormat API Suite
Fully implemented the dynamic buffer management suite:

  • BeaconFormatAlloc: Allocates a managed buffer for output assembly.
  • BeaconFormatReset & BeaconFormatFree: Proper lifecycle management for temporary buffers.
  • BeaconFormatAppend & BeaconFormatPrintf: Methods to populate the buffer, with the latter utilizing the new robust printf logic.
  • BeaconFormatToString: Retrieves the final assembled string pointer.
  • BeaconFormatInt: Appends a 4-byte integer in the expected big-endian format.

3. Memory Access Improvements

  • Modified ReadWStringFromPtr to correctly decode UTF-16 code units instead of raw byte concatenation, ensuring proper representation of multi-byte characters.

4. COFF Symbol Resolution

  • Updated the COFF loader to resolve individual BeaconFormat* symbols to their new Go implementations.

Validation

Case 1: locale.x64.o (Formatting Fix)
This BOF uses %S extensively for locale information.

Output Before:

Locale: %!S(uintptr=948722202866) (%!S(uintptr=948722202696))
LCID: dc00000409
Date: %!S(uintptr=948722203036)
Country: %!S(uintptr=948722203206)

Output After:

Locale: English (en-US)
LCID: 5400000409
Date: Tuesday, January 20, 2026
Country: United States

Case 2: ChromeKatz (Compatibility Fix)
ChromeKatz utilizes BeaconFormatPrintf and BeaconFormatToString for its credential output.

  • Before: Failed to run due to missing BeaconFormat* implementations.
  • After: Functions correctly and returns the full set of captured credentials.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant