Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ the module:
imports = [ seclab-pkgs.flakeModules.default ];

# All optional. `nixpkgs` defaults to ours, `shellName` to "re", and
# every toolset to true.
# every toolset to true except `cross` and `cross-extra`.
seclab.re = {
nixpkgs = inputs.nixpkgs;
toolsets.hardware = false;
Expand All @@ -169,10 +169,22 @@ devShells.default = pkgs.mkShell {
};
```

The groups are `binary-analysis`, `crypto`, `debugging`, `dev-tools`,
`firmware`, `forensics`, `hardware`, `python` and `reversing`;
`lib.mkToolsets { inherit pkgs; }` returns all of them as
`{ packagesByGroup, allPackages }`.
The groups are `binary-analysis`, `crypto`, `cross`, `cross-extra`,
`debugging`, `dev-tools`, `firmware`, `forensics`, `hardware`, `python`,
`reversing` and `static-analysis`; `lib.mkToolsets { inherit pkgs; }` returns
all of them as `{ packagesByGroup, allPackages }`, with `cross` and
`cross-extra` left out of `allPackages` unless `enabled` turns them on.

`cross` gives a gcc and binutils per foreign target (`aarch64`, `arm`, `i386`,
`mips64el`, `mipsel`, `ppc64` (ELFv1), `ppc64le`, `riscv64`), plus a
`qemu-<arch>-sysroot` command that runs a dynamically linked foreign binary
against that target's glibc, libgcc_s and libstdc++. `cross-extra` adds `mips`,
`mips64` and `ppc`, whose toolchains are not in cache.nixos.org and build
locally. Neither helps with uClibc or musl firmware: point `qemu-<arch> -L` at
the extracted rootfs for those.

On x86_64, `afl-qemu-arch <arch> afl-fuzz -Q ...` runs AFL++'s QEMU mode
against a foreign binary; plain `afl-fuzz -Q` handles x86_64 only.

> A toolset needs `pkgs` built with **both** `overlays.default` and
> `config.allowUnfree = true` — it contains this repo's own packages, and
Expand Down
8 changes: 4 additions & 4 deletions modules/re-environment/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ in
description = "Extra packages for the shell, on top of the toolsets.";
};

toolsets = lib.genAttrs groups (
group:
toolsets = lib.mapAttrs (
group: enabledByDefault:
lib.mkOption {
type = lib.types.bool;
default = true;
default = enabledByDefault;
description = "Include the ${group} toolset.";
}
);
) groups;
};

config.perSystem =
Expand Down
4 changes: 3 additions & 1 deletion nix/exclusions.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"bindiff"
# Half-hour from-source build behind a submodule fetch.
"dynamorio"
# Wraps uniflash, a requireFile CI cannot satisfy.
"f28335-tools"
# Unfree CUDA 13 closure, and the derivation is only the FHS sandbox.
"freetoken"
# A Gradle build against the whole Ghidra distribution.
Expand All @@ -28,7 +30,7 @@
"pwndbg-lldb"
# requireFile behind an ST login.
"stm32cubeprogrammer"
# Large vendor installer from TI.
# requireFile; the installer is staged by hand.
"uniflash"
# keep-sorted end
];
Expand Down
3 changes: 3 additions & 0 deletions nix/lib.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ _: {
# keep-sorted start
binary-analysis = import ../toolsets/binary-analysis.nix;
crypto = import ../toolsets/crypto.nix;
cross = import ../toolsets/cross.nix;
cross-extra = import ../toolsets/cross-extra.nix;
debugging = import ../toolsets/debugging.nix;
dev-tools = import ../toolsets/dev-tools.nix;
firmware = import ../toolsets/firmware.nix;
forensics = import ../toolsets/forensics.nix;
hardware = import ../toolsets/hardware.nix;
python = import ../toolsets/python.nix;
reversing = import ../toolsets/reversing.nix;
static-analysis = import ../toolsets/static-analysis.nix;
# keep-sorted end
};

Expand Down
6 changes: 5 additions & 1 deletion overlays/angr-suite.nix
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ let
inherit (wheel) hash;
};
nativeBuildInputs = final.lib.optional final.stdenv.hostPlatform.isLinux final.autoPatchelfHook;
buildInputs = final.lib.optional final.stdenv.hostPlatform.isLinux final.stdenv.cc.cc.lib;
# zlib: the aarch64 wheel's bundled blink links libz.so.1.
buildInputs = final.lib.optionals final.stdenv.hostPlatform.isLinux [
final.stdenv.cc.cc.lib
final.zlib
];
pythonImportsCheck = [ "pyxdia" ];
meta.description = "Extract program information from PDB files (prebuilt wheel)";
};
Expand Down
8 changes: 5 additions & 3 deletions packages/misc/stm32cubeprogrammer/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
makeDesktopItem,
writeShellScript,
symlinkJoin,
version ? "2.23.0",
hash ? "sha256-ap5gpaBIxF6zJB+btmvcLmy9ARn7LkJWjcBZ/GFnRCo=",
}:

let
version = "2.22.0";

desktopItem = makeDesktopItem {
name = "STM32CubeProgrammer";
# Must match the FHS wrapper binary name (pname of the GUI env below) —
Expand All @@ -38,7 +38,7 @@ let
src = requireFile {
name = "SetupSTM32CubeProgrammer_linux_64.zip";
url = "https://www.st.com/en/development-tools/stm32cubeprog.html";
hash = "sha256-//oBertNoUWC4Smqmh5Ph+bQcZo8uVDAGE9MtIq2Cqc=";
inherit hash;
};

nativeBuildInputs = [
Expand Down Expand Up @@ -181,10 +181,12 @@ let
at-spi2-atk
dbus

brotli
openssl
krb5

zlib
zstd
cups
nspr
nss
Expand Down
16 changes: 9 additions & 7 deletions packages/misc/uniflash/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@
{
stdenvNoCC,
lib,
fetchurl,
requireFile,
buildFHSEnv,
writeShellScript,
symlinkJoin,
glibc,
version ? "9.6.0",
buildId ? "5764",
hash ? "sha256-ZueL+gg0kpmcUkpuqXwWtLkL5U1lvq53ASEPtkBLDZw=",
}:

let
version = "9.5.0";
buildId = "5651";

package = stdenvNoCC.mkDerivation {
pname = "uniflash-unwrapped";
inherit version;

src = fetchurl {
url = "https://dr-download.ti.com/software-development/software-programming-tool/MD-QeJBJLj8gq/${version}/uniflash_sl.${version}.${buildId}.run";
hash = "sha256-/2gUq90WcEIGmnmpjaNGXxaSEXQn12B7AaHTgUNjn3M=";
# Register with: nix-store --add-fixed sha256 <run>
src = requireFile {
name = "uniflash_sl.${version}.${buildId}.run";
url = "https://www.ti.com/tool/UNIFLASH";
inherit hash;
};

dontUnpack = true;
Expand Down
1 change: 1 addition & 0 deletions requiredFiles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ no-op.
| --------------------------------------- | ----------------------------------------- | --------------------------- |
| `binaryninja_linux_dev_ultimate.zip` | Binary Ninja (`nixosModules.binaryninja`) | base32, set by the consumer |
| `SetupSTM32CubeProgrammer_linux_64.zip` | `stm32cubeprogrammer` | SRI, pinned in-package |
| `uniflash_sl.9.6.0.5764.run` | `uniflash` | SRI, pinned in-package |

The two formats are not interchangeable, which is why the helper prints both.

Expand Down
58 changes: 58 additions & 0 deletions toolsets/binary-analysis.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,89 @@
# SPDX-License-Identifier: Apache-2.0
{ pkgs }:
let
inherit (pkgs) lib;
seclab = import ./lib.nix { inherit pkgs; };

# capa looks for rules/ and sigs/ beside its package, which nixpkgs does not
# install; without them it exits 10 on every sample. The source carries both.
capa = pkgs.python3Packages.toPythonApplication (
pkgs.python3Packages.capa.overridePythonAttrs (old: {
postInstall = (old.postInstall or "") + ''
ln -s ${old.src}/rules ${old.src}/sigs $out/${pkgs.python3.sitePackages}/
'';
})
);

# nixpkgs builds afl-qemu-trace for the host arch only. ppc64 and ppc64le
# are absent: qemuafl's target/ppc does not compile with current gcc.
aflQemuTargets = [
"aarch64"
"arm"
"i386"
"mips"
"mips64"
"mips64el"
"mipsel"
"ppc"
"riscv64"
"x86_64"
];
aflQemu = pkgs.aflplusplus.qemu.overrideAttrs (old: {
configureFlags = [
"--target-list=${lib.concatMapStringsSep "," (t: "${t}-linux-user") aflQemuTargets}"
]
++ lib.filter (f: !lib.hasPrefix "--target-list=" f) old.configureFlags;
});
# afl-fuzz, afl-showmap and afl-tmin all find afl-qemu-trace through AFL_PATH.
afl-qemu-arch = pkgs.runCommand "afl-qemu-arch" { } ''
${lib.concatMapStrings (t: ''
mkdir -p $out/share/afl-qemu/${t}
ln -s ${aflQemu}/bin/qemu-${t} $out/share/afl-qemu/${t}/afl-qemu-trace
'') aflQemuTargets}
mkdir -p $out/bin
cat > $out/bin/afl-qemu-arch <<EOF
#!${pkgs.runtimeShell}
arch=\''${1:?usage: afl-qemu-arch <arch> <afl command...>}
[ -d $out/share/afl-qemu/\$arch ] || { echo "no afl-qemu-trace for \$arch; have: ${toString aflQemuTargets}" >&2; exit 1; }
shift
AFL_PATH=$out/share/afl-qemu/\$arch exec "\$@"
EOF
chmod +x $out/bin/afl-qemu-arch
'';
in
seclab.requireSeclabPkgs (
with pkgs;
[
# keep-sorted start
bloaty
capa
capstone
checksec
# Minimal, not full: the full build drags ghc, ocaml, mono and four JDKs.
diffoscopeMinimal
dwarfdump
elfutils
flare-floss
honggfuzz
keystone
# libtriton, not triton: the module it installs is named triton, which
# would collide with python3Packages.triton.
libtriton
lief
one_gadget
osslsigncode
pahole
pax-utils
pev
radamsa
ropgadget
unicorn
upx
yara-x
# keep-sorted end
]
++ lib.optionals stdenv.hostPlatform.isx86_64 [
afl-qemu-arch
aflplusplus
bindiff
# meta.platforms is x86_64-linux; upstream treats aarch64 as a cross target.
Expand Down
18 changes: 18 additions & 0 deletions toolsets/cross-extra.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2025-2026 Technology Innovation Institute (TII)
# SPDX-License-Identifier: Apache-2.0
#
# Not in cache.nixos.org: enabling this builds a cross gcc and glibc per target.
{ pkgs }:
let
seclab = import ./lib.nix { inherit pkgs; };
in
seclab.mkCross "cross-extra" (
with pkgs.pkgsCross;
{
# keep-sorted start
mips = mips-linux-gnu;
mips64 = mips64-linux-gnuabi64;
ppc = ppc32;
# keep-sorted end
}
)
26 changes: 26 additions & 0 deletions toolsets/cross.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2025-2026 Technology Innovation Institute (TII)
# SPDX-License-Identifier: Apache-2.0
#
# Only targets whose gcc and glibc cache.nixos.org serves for x86_64-linux;
# cross-extra.nix holds the ones that build locally.
{ pkgs }:
let
seclab = import ./lib.nix { inherit pkgs; };
in
seclab.mkCross "cross" (
with pkgs.pkgsCross;
{
# keep-sorted start
aarch64 = aarch64-multiplatform;
arm = armv7l-hf-multiplatform;
i386 = gnu32;
mips64el = mips64el-linux-gnuabi64;
mipsel = mipsel-linux-gnu;
# ELFv1, not nixpkgs' default ppc64: big-endian binaries in the wild are
# ELFv1 and ask for ld64.so.1, which an ELFv2 glibc does not provide.
ppc64 = ppc64-elfv1;
ppc64le = powernv;
inherit riscv64;
# keep-sorted end
}
)
15 changes: 10 additions & 5 deletions toolsets/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,40 @@
let
inherit (pkgs) lib;

groups = import ./groups.nix;

# Every group, whatever `enabled` says: a consumer who turned a group off in
# the shell can still reach it by name.
packagesByGroup = {
# keep-sorted start
binary-analysis = import ./binary-analysis.nix { inherit pkgs; };
crypto = import ./crypto.nix { inherit pkgs; };
cross = import ./cross.nix { inherit pkgs; };
cross-extra = import ./cross-extra.nix { inherit pkgs; };
debugging = import ./debugging.nix { inherit pkgs; };
dev-tools = import ./dev-tools.nix { inherit pkgs; };
firmware = import ./firmware.nix { inherit pkgs; };
forensics = import ./forensics.nix { inherit pkgs; };
hardware = import ./hardware.nix { inherit pkgs; };
python = import ./python.nix { inherit pkgs; };
reversing = import ./reversing.nix { inherit pkgs; };
static-analysis = import ./static-analysis.nix { inherit pkgs; };
# keep-sorted end
};
in
# groups.nix repeats these names for the re-environment module, which declares
# one option per group and has no pkgs to ask.
assert lib.assertMsg (lib.attrNames packagesByGroup == import ./groups.nix) ''
# groups.nix repeats these names, with their defaults, for the re-environment
# module, which declares one option per group and has no pkgs to ask.
assert lib.assertMsg (lib.attrNames packagesByGroup == lib.attrNames groups) ''
toolsets/groups.nix and toolsets/default.nix disagree:
groups.nix: ${lib.concatStringsSep " " (import ./groups.nix)}
groups.nix: ${lib.concatStringsSep " " (lib.attrNames groups)}
default.nix: ${lib.concatStringsSep " " (lib.attrNames packagesByGroup)}
'';
{
inherit packagesByGroup;

allPackages = lib.concatLists (
lib.mapAttrsToList (
group: packages: lib.optionals (enabled.${group} or true) packages
group: packages: lib.optionals (enabled.${group} or groups.${group}) packages
) packagesByGroup
);
}
4 changes: 4 additions & 0 deletions toolsets/dev-tools.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ with pkgs;
hexyl
imhex
jq
kaitai-struct-compiler
nasm
ninja
parallel
patchelf
pkg-config
rehex
ripgrep
wireshark-cli
# keep-sorted end
]
Loading
Loading