Binary Analysis Craft!

Overview

logo

BinCraft - Binary Analysis Craft

BinCraft is a future binary analysis toolkit.

Features:

  • Layered Architecture: composed by multiple libraries that can be used seperatedly.
  • Written in Rust: high performance, safe interface, no VM.
  • Python API: easy scripting. In the future, C API will also be provided, allows to bind to more programming languages.
  • Extensible: with sleigh DSL, new architecture is easy to add.
  • (Currently In Development) SQL based binary analysis

BinCraft is seperated into multiple parts, while currently only the first one, sleighcraft is working.

NOTE:

this project is still in early stage. Large scale API modifications, bugs are expected. Documentations are yet to be complete. Star us, we will try our best to make it complete and better. 🥺 Please, do it.

SleighCraft

SleighCraft is a decoder (or, linear disassembler) based on ghidra's decompiler implementation. Sleighcraft can be used in Rust or Python, with both high-level and low-level API.

In general, sleighcraft is just like capstone but with IR and more archs.

Features:

  • Rust based API and Python scripting API.
  • Decoding with IR as the semantic meaning.
  • Archs: 110 architectures.

️️ ✔️ : provided

❌ : not provided

🚧 : in construction

🤔 : not sure, maybe not

Comparison with capstone:

Feature SleighCraft Capstone Engine
disassemble ✔️ ✔️
IR ✔️ ️ ❌
C API 🚧 ✔️
custom architecture ️ ✔️ ❌

Architectures comparision with capstone (according to capstone arch list):

Arch Names SleighCraft Capstone Engine
6502 ✔️ 🤔
6805 ✔️ 🤔
8051 ✔️ 🤔
8048 ✔️ 🤔
8085 ✔️ 🤔
68000 ✔️ 🤔
aarch64(armv8) ✔️ ️️ ✔️
arm ✔️ ️️ ✔️
cp1600 ✔️ 🤔
cr16 ✔️ 🤔
avr8 ✔️ ️️ 🤔
dalvik ✔️ 🤔
jvm ✔️ 🤔
mips ✔️ ️️ ✔️
powerpc ✔️ ️️ ✔️
sparc ✔️ ️️ ✔️
tricore ✔️ 🤔
riscv ✔️ 🤔
z80 ✔️ 🤔
System Z ❌ ✔️
xCore ❌ ✔️

How to install

Rust

Use cargo:

sleighcraft = { git = "https://github.com/ret2lab/bincraft" }

The repo is a bit large to submit on crates-io (because of predefined sla files), but save you the complex of compiling sleigh files yourself.

Python

# quick install it with pip
$ pip3 install bincraft

# or download binaries than choose the corresponding architecture
$ pip3 install bincraft-0.1.0-cp39-cp39-Arch.whl

# or manual, to do this, you need to have rust compiler installed and maturin
# better with rustup.
$ pip3 install maturin
$ maturin build
$ pip3 install bincraft-0.1.0-cp39-cp39-Arch.whl

How to Use

One could refer to doc.rs to see how Rust binding can be used.

Python binding:

from bincraft import Sleigh

code = [0x90, 0x31, 0x32] # code to disassemble

# init the sleigh engine Sleigh(arch, code)
sleigh = Sleigh("x86", code)

# now we are prepared to disassemble!
# disasm(start_addr)
for asm in sleigh.disasm(0):
    addr = asm.addr()
    mnem = asm.mnemonic()
    body = asm.body()

    # quite like capstone, right?
    print(f'Addr: {addr}\t  mnemonic: {mnem}\t body: {body}')

    # but! we also have the IR!
    pcodes = asm.pcodes()
    for pcode in pcodes:
        opcode = pcode.opcode()
        vars = pcode.vars()
        print(f'opcode: {opcode}\t vars: {vars}\t')
    print()

Rust (kinda low level):

// Overall procedure:
// 1. get the spec, this is where we know how to decode anything
// 2. get a loader, this is where we fill the input bytes to the engine.
// A predefined loader is provided: `PlainLoadImage`, which sets
// the things to decode by using a single buf.
// 3. set the AssemblyEmit and PcodeEmit instance, these are two
// traits that defines the callback at the decode time.
// 4. do the decode
use sleighcraft::*;
let mut sleigh_builder = SleighBuilder::default();
let spec = arch("x86").unwrap();
let buf = [0x90, 0x32, 0x31];
let mut loader = PlainLoadImage::from_buf(&buf, 0);
sleigh_builder.loader(&mut loader);
sleigh_builder.spec(spec);
let mut asm_emit = CollectingAssemblyEmit::default();
let mut pcode_emit = CollectingPcodeEmit::default();
sleigh_builder.asm_emit(&mut asm_emit);
sleigh_builder.pcode_emit(&mut pcode_emit);
let mut sleigh = sleigh_builder.try_build().unwrap();

sleigh.decode(0).unwrap();

println!("{:?}", asm_emit.asms);
println!("{:?}", pcode_emit.pcode_asms);

A more detailed documentation of Rust API is still under development.

QueryCraft (In-Development)

QueryCraft is a SQL based binary analysis, its goal is to allow analyzer write SQL to fetch information (both raw and analyzed) from binary.

This is a currently in development future.

Demo only support for disassembly bytes into table is available. One can do this using the demo:

sqlite> .load ./libquerycraft.so
sqlite> select qc_disasm("bytes", X'319090', "x86", "qc_out_asm", "qc_out_pcode");
1
sqlite> select * from qc_out_asm;
ram|0|XOR|word ptr [BX + SI + 0x90],DX
sqlite> select * from qc_out_pcode;
ram|0|INT_ADD|register|12|2|register|24|2||||unique|4736|2|
ram|0|INT_ADD|unique|4736|2|const|144|2||||unique|4992|2|
ram|0|CALLOTHER|const|0|4|register|262|2|unique|4992|2|unique|14336|4|
ram|0|COPY|const|0|1|||||||register|512|1|
ram|0|COPY|const|0|1|||||||register|523|1|
ram|0|LOAD|const|94230195853072|8|unique|14336|4||||unique|30848|2|
ram|0|INT_XOR|unique|30848|2|register|8|2||||unique|30848|2|
ram|0|STORE|const|94230195853072|8|unique|14336|4|unique|30848|2||||
ram|0|LOAD|const|94230195853072|8|unique|14336|4||||unique|30848|2|
ram|0|INT_SLESS|unique|30848|2|const|0|2||||register|519|1|
ram|0|LOAD|const|94230195853072|8|unique|14336|4||||unique|30848|2|
ram|0|INT_EQUAL|unique|30848|2|const|0|2||||register|518|1|
ram|0|LOAD|const|94230195853072|8|unique|14336|4||||unique|30848|2|
ram|0|INT_AND|unique|30848|2|const|255|2||||unique|55552|2|
ram|0|POPCOUNT|unique|55552|2|||||||unique|55680|1|
ram|0|INT_AND|unique|55680|1|const|1|1||||unique|55808|1|
ram|0|INT_EQUAL|unique|55808|1|const|0|1||||register|514|1|

In the Future

Currently we are in the early stage of the project. But we have already planned several goals in the future:

  • decoder (linear disassembler) with IR (based on ghidra)
  • encoder (single instruction assemble) (based on ghidra)
  • universal binary analysis algorithms (CFG generation, data flow information)
  • C API/More language bindings
  • PCode emulator
  • Analysis Framework
  • symbolic execution
  • customizable (with DSL, like sleigh to decoder) loader

About Us

This is a project started by StarCrossTech PortalLab.

Any contribution through pull request is welcome. ✌️

Issues
  • Rust decompiler improvement

    Rust decompiler improvement

    Current ghidra has a hard problem decompiling Rust programs.

    Fixes:

    • [x] display proper string representation when strings are concatenated into one (in Rust) case. This is resolved in this PR already.
    • [x] wrong stack analysis. Resolved by this PR.
    • [x] wrong parameter analysis. Resolved by this PR
    difficulty: hard 
    opened by Escapingbug 3
  • Pcode patching

    Pcode patching

    This is required for more flexible IR arrangements.

    The background is that, currently the only way to modify semantic of the program is through instruction patching. However, the instruction patching has some drawbacks:

    1. instruction patching cannot insert any instruction
    2. instruction patching cannot modify patch a longer instruction and keep the next instruction untouched

    And, to be honest, those drawbacks are preventing strong analysis such as deobfuscating control flow flattening.

    Obfuscations like control flow flattening would rearrange the basic blocks. But because of the drawbacks mentioned, no possible rearrangements can be done in Ghidra (or IDA). At least, not easily possible.

    The solution of this problem is to allow pcode patching. That is, we allow user to display the raw-pcode and patch them.

    What we need:

    • [ ] an action that pops only when clicked on raw-pcode (this is possible by checking which "row" the user clicked on the instruction.)
    • [ ] parsing the user input Pcode as the reverse version of the PcodeFormatter.
    • [ ] record the pcode
    • [ ] use the recorded pcode and bypass the decompiler calling sleigh engine

    The reason of the last two is that the pcode is not stored in the database and is lifted each time by the sleigh engine as mentioned in this issue.

    So maybe we could find out some way to bypass the translation and remember the last time lifted and use it for the pcode patching feature. Note that not all the functions need the pcode stored, only the ones patched. Or else we might have a database exploded in disk space.

    difficulty: hard 
    opened by Escapingbug 2
  • x86-64 throws BadDataError on basic disassembly

    x86-64 throws BadDataError on basic disassembly

    While attempting to use sleighcraft for x86-64 disassembly I've run into a problem with BadDataErrors being thrown on valid code.

    Code to reproduce when using the python package:

    from bincraft import Sleigh
    # Opcodes for xor rax, rax in x86-64
    # Also for dec eax; xor eax, eax in x86
    code = [72, 49, 192]
    
    # x86 test case
    sleigh = Sleigh("x86", code)
    print(sleigh.disasm(0)) # works
    
    sleigh = Sleigh("x86-64", code)
    print(sleigh.disasm(0)) # fails with OSError: cpp exception: BadDataError
    

    I'm unsure as to what could be causing this issue, or if I missed a configuration step somewhere in the process. Any feedback is appreciated.

    opened by Jumboperson 1
  • UI color configuration refactor

    UI color configuration refactor

    Current UI color is scattered in the code that describes the UI components. Many components use hard-coded color which does not care about the overall look and feel in anyway and may not be configuration. One such example is, if you search for "Color.BLUE" you will likely get a tons of such hard coded color.

    One possible solution for this is to refactor all the place that needs the color and use a seperate config file (xml or json, whatever) to describe those colors.

    As a side note of how this can be implemented, ghidra instance always need an ApplicationLayout to start,

    For example, the GhidraLauncher uses GhidraApplicationLayout class:

    image

    The application layout stores many whole-ghidra level directory structure:

    image

    So, when instantiating the GhidraApplicationLayout, we can use the dir info to find the color configuration file resided in the ghidra installation dir.

    Then, we can instantiate a singleton called something like ColorConfig and parse the file (xml or json?) to get a configuration. To ease the choice of color, we can just name the colors like "primary", "secondary", "foreground_default".

    Whenever some class wants the color, it should query the singleton and get a color of a particular name. In this way, if the LaF of java swing switched (just like in dark theme), we should also provide a new configuration of colors so that the colors switches accordingly.

    difficulty: easy 
    opened by Escapingbug 1
  • Equate Symbol Storage

    Equate Symbol Storage

    When you set a new equate to a number appear in Listing area but not be identified to a variable in deompile area, and then if you want to rename a variable in decompile area, you will get a error message.

    And I have found the reason, ghidra will storage all equate symbols in symbol table and produce their hash storage in LocalSymbolMap, so when you rename a variable, ghidra will search for the LocalSymbolMap and make you operate failed.

    difficulty: medium 
    opened by shizhongpwn 1
  • IDA-like default variable names in decompiler

    IDA-like default variable names in decompiler

    Current ghidra default variable names are verbose, especially those contain stringified address in it. Most of the time, those addresses are not useful. We should strip them out to provide a cleaner decompiler output.

    Example (ghidra): image

    Same function in IDA: image

    Ignore the array analysis and the alloca thing. v2 is definitely visually better than those uStack77832 thing. Nobody cares about 77832 kinda thing.

    This functionality could be also provided to upstream. But in our case, we could set it to enabled by default but official upstream should have it disabled.

    My previous commit can be an illustration of how this can be done properly. But that's not a complete commit, as it does not cover all of the variable name generation algorithm.

    One can implement this by following my commit and complete the whole variable generation. Also, better simpler variable name genration algorithm is also welcome.

    difficulty: medium 
    opened by Escapingbug 1
  • Tool requirement: binary generation from API

    Tool requirement: binary generation from API

    The Sleigh engine is the core of ghidra decompiler. It can deal with the binary stream, disassemble it into instructions and lift it into IRs.

    However, its restriction is that it can only deal with the binary stream instead of text streams. Sometimes we are given the text streams, and we know the underlining semantic of each text instruction. To deal with such situation, the usage of sleigh engine is hard.

    A possible solution of this is to write a tool (possibly in Python?) that could generate the binary according to the text instructions and a sleigh specification that could further translate the binary back to the text format.

    This allows the sleigh engine to be bypassed and let the ghidra do the rest of the job as it is.

    What we need:

    • [ ] API design
    • [ ] instruction choice algorithm (choose the binary format of each instruction when instructions are fed into the API)
    • [ ] sleigh generation algorithm
    • [ ] complete tool
    difficulty: hard 
    opened by Escapingbug 1
  • More fluent convert to char/hex/dec display experience

    More fluent convert to char/hex/dec display experience

    Currently convert functionality (by EquatePlugin) has a strange behavior: after convert, sometimes the decompiler also follows the converting, but sometimes it does not. No explicit message is showed to user. And the expected behavior is not ensured to succeed each time.

    The reason behind is that current decompiler only support show constant in five possible format:

    • decimal
    • oct
    • hex
    • char
    • binary

    This can be proved in decompiler source code database.hh: image

    Formats such as floating is not yet supported (or string? not sure).

    There are two possible solutions to this problem:

    1. show a error message when decompiler cannot follow the rule
    2. fix decompiler, adding the missing parts.

    One more task is to add the convert part to the decompiler, but we identify it not included in 0.1 release.

    difficulty: medium 
    opened by Escapingbug 1
  • UI modernize: dark theme

    UI modernize: dark theme

    Complete UI modernize tracking issue.

    Tasks:

    • [x] dark theme introduce (with FlatLaf)
    • [x] ~~forground coloring fixing: Ghidra uses hard coded colors all across the project. After introducing dark theme, some of the letters can be hard to recognize because of the default color.~~ (Basic level is done already but the next things should rely on #17, so we consider this done for now)
    • [ ] other elements flattening
    • [ ] better icons

    Current showcase: image image

    difficulty: easy 
    opened by Escapingbug 1
  • Add incremental sla compilation

    Add incremental sla compilation

    After this PR, the sla compilation should be incremental. i.e, if you haven't changed sleigh source code, the sla file should be generated only once instead of being generated each time you compile.

    opened by Escapingbug 0
  • build time compile sla

    build time compile sla

    After this PR, we should be able to allow uploading to crates.io.

    Current issue blocking the uploading is the code size, previously with sla files, the code can be quite large. But actually the sleigh files (slaspec) is not that large, we can require user of our crate to compile the sllaspec to sla before using. Hopefully, this PR does the trick.

    opened by Escapingbug 0
  • Rewrite decode_with for rust api

    Rewrite decode_with for rust api

    Delete the function decode_with for original and Expose more Rust low-level APIs.

    • [x] fixed cxx exception content display
    • [x] fixed pcode instructions display error
    • [x] disassembly and pcode instruction api exposed
    • [x] rewrite decode_with for rust api

    #21

    opened by ioo0s 0
  • v0.2.0 api adjustment

    v0.2.0 api adjustment

    I got to admit, current API, especially Rust API is totally a mess.

    Hopefully this PR should beautify our Rust API. But note that Python and Nodejs binding has not been changed, so this is still a work in progress.

    Current todo:

    • [x] better Rust API
    • [ ] doc the Rust API
    • [ ] fix Python binding leveraging the new Rust API
    • [ ] fix Nodejs binding
    opened by Escapingbug 0
  • X86-64 architecture program decompile error

    X86-64 architecture program decompile error

    When using code code = [15, 31, 128, 0, 0, 0, 0] in sleighcraft and set MODE_64, We will get an error BadDataError.

    crash demo

      let mut sleigh_builder = SleighBuilder::default();
        let spec = arch("x86-64").unwrap();
        let buf = [15, 31, 128, 0, 0, 0, 0];
        let mut loader = PlainLoadImage::from_buf(&buf, 0);
        sleigh_builder.loader(&mut loader);
        sleigh_builder.spec(spec);
        sleigh_builder.mode(MODE64);
        let mut asm_emit = CollectingAssemblyEmit::default();
        let mut pcode_emit = CollectingPcodeEmit::default();
        sleigh_builder.asm_emit(&mut asm_emit);
        sleigh_builder.pcode_emit(&mut pcode_emit);
        let mut sleigh = sleigh_builder.try_build().unwrap();
    
        sleigh.decode(0).unwrap();
    
        println!("{:?}", asm_emit.asms);
        println!("{:?}", pcode_emit.pcode_asms);
    

    But using capstone is normal image

    opened by ioo0s 0
  • Better Rust API?

    Better Rust API?

    As noted in the README, the Rust API is kind of low level. Users need to construct internal structures like CollectingAssemblyEmit and call internal methods sleigh.decode(0).unwrap() (what does this do?) to get the results. I guess the developer may expect Rust users to be skilled enough, so they can even develop fancier features based on those low level APIs? How about also providing a higher level one, like shown in the Python/Nodejs bindings?

    By the way, the implementation code contains many wrappers of XXXEmit, such as AssemblyEmit, RustAssemblyEmit, CollectingAssemblyEmit, and the Pcode-series emitters. They are basically doing similar things. I guess the authors may want to provide a callback mechanism and also a default callback that collects the emitted code into a vector. But I think it is kind of over-designed. Maybe a cleaner way is simply returning an interator, so users can iterate through the generated code and collect them in whatever way they want.

    opened by liangjs 0
Owner
PortalLab
StarCross Technology PortaLab 星阑科技PortalLab实验室 (Previous Ret2Lab)
PortalLab
This is like Inverting Binary Tree, but instead of a Binary Tree it's a File Tree.

Invert File Tree in C++ This is like Inverting Binary Tree, but instead of the Binary Tree it's a File Tree. This is intended as a simple exercise to

Tsoding 11 Jun 18, 2021
A Binary Genetic Traits Lexer

BinLex a Genetic Binary Trait Lexer Library and Utility The purpose of BinLex is to extract basic blocks and functions as traits from binaries. Most p

c3rb3ru5 276 Jun 25, 2022
WIP runtime binary patcher for Aroma

Example plugin This is just a simple example plugin which can be used as a template. Building For building you need: wups wut libutils for common func

Ash 4 Sep 19, 2021
Binary Search tree

eng Binary tree Task: Create a binary search tree, the information part of which will be a symbol, make direct and symmetric traversals, search for th

Andrey 0 Nov 25, 2021
C++ DataFrame for statistical, Financial, and ML analysis -- in modern C++ using native types, continuous memory storage, and no pointers are involved

C++ DataFrame for statistical, Financial, and ML analysis -- in modern C++ using native types, continuous memory storage, and no pointers are involved

Hossein Moein 1.5k Jun 21, 2022
A Pipeline for LC-MS/MS Metabolomics Data Process and Analysis

NP³ MS Workflow A Pipeline for LC-MS/MS Metabolomics Data Process and Analysis Overview The NP³ MS workflow is a software system with a collection of

null 3 Feb 15, 2022
Binary Analysis Craft!

BinCraft - Binary Analysis Craft BinCraft is a future binary analysis toolkit. Features: Layered Architecture: composed by multiple libraries that can

PortalLab 61 May 25, 2022
Probabilistic Risk Analysis Tool (fault tree analysis, event tree analysis, etc.)

SCRAM SCRAM is a Command-line Risk Analysis Multi-tool. This project aims to build a command line tool for probabilistic risk analysis. SCRAM is capab

Olzhas Rakhimov 112 Jun 16, 2022
CRAFT: A Benchmark for Causal Reasoning About Forces and inTeractions

CRAFT This repository contains the codes used to generate the CRAFT dataset as described in the paper: CRAFT: A Benchmark for Causal Reasoning About F

null 10 Apr 12, 2022
This is like Inverting Binary Tree, but instead of a Binary Tree it's a File Tree.

Invert File Tree in C++ This is like Inverting Binary Tree, but instead of the Binary Tree it's a File Tree. This is intended as a simple exercise to

Tsoding 11 Jun 18, 2021
Pharos Static Binary Analysis Framework

Automated static analysis tools for binary programs

Software Engineering Institute 1.2k Jul 3, 2022
Binary data analysis and visualization tool

Veles - A new age tool for binary analysis It is a very difficult task for a human to notice subtle patterns in large amounts of binary data, however,

CodiLime Sp. z o.o. 848 Jun 29, 2022
Maat is an open-source Dynamic Symbolic Execution and Binary Analysis framework

About Maat is an open-source Dynamic Symbolic Execution and Binary Analysis framework. It provides various functionalities such as symbolic execution,

Trail of Bits 444 Jun 22, 2022
Terrain Analysis Using Digital Elevation Models (TauDEM) software for hydrologic terrain analysis and channel network extraction.

TauDEM (Terrain Analysis Using Digital Elevation Models) is a suite of Digital Elevation Model (DEM) tools for the extraction and analysis of hydrolog

David Tarboton 184 Jun 23, 2022
Your binary serialization library

Bitsery Header only C++ binary serialization library. It is designed around the networking requirements for real-time data delivery, especially for ga

Mindaugas Vinkelis 713 Jun 24, 2022
Fast Binary Encoding is ultra fast and universal serialization solution for C++, C#, Go, Java, JavaScript, Kotlin, Python, Ruby, Swift

Fast Binary Encoding (FBE) Fast Binary Encoding allows to describe any domain models, business objects, complex data structures, client/server request

Ivan Shynkarenka 570 Jun 24, 2022
Simple Binary Encoding (SBE) - High Performance Message Codec

Simple Binary Encoding (SBE) SBE is an OSI layer 6 presentation for encoding and decoding binary application messages for low-latency financial applic

Real Logic 2.7k Jun 22, 2022
A simple C library for compressing lists of integers using binary packing

The SIMDComp library A simple C library for compressing lists of integers using binary packing and SIMD instructions. The assumption is either that yo

Daniel Lemire 370 Jun 23, 2022
Binary Serialization

Binn Binn is a binary data serialization format designed to be compact, fast and easy to use. Performance The elements are stored with their sizes to

null 358 Jun 20, 2022
Binary visualization tool primarily aimed at videogame reverse engineering & research.

binviz Binary visualization tool. Allows you to load a binary and pan/zoom around its content. Each byte (or 4 bytes in 4-byte mode) is represented by

Nick Renieris 28 Apr 25, 2022
Utility to convert any binary file into C source that can be compiled and linked to the executable.

bin2c Utility to convert any binary file into C source that can be compiled and linked to the executable. bin2o Utility to convert any binary file int

Vadim A. Anisimov 16 Jul 14, 2021
Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications

Zmeya Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications. Zmeya is not even a serializ

Sergey Makeev 95 Jun 22, 2022
Orbit, the Open Runtime Binary Instrumentation Tool, is a standalone C/C++ profiler for Windows and Linux

Orbit, the Open Runtime Binary Instrumentation Tool, is a standalone C/C++ profiler for Windows and Linux. Its main purpose is to help developers visualize the execution flow of a complex application.

Google 2.6k Jun 30, 2022
A lightweight and simpling iOS binary decryptor

FlexDecrypt's source code is pretty FAT, bundling the whole swift runtime to just achieve a simple mremap_encrypted.

null 152 Jun 30, 2022
A Binary Genetic Traits Lexer

BinLex a Genetic Binary Trait Lexer Library and Utility The purpose of BinLex is to extract basic blocks and functions as traits from binaries. Most p

c3rb3ru5 276 Jun 25, 2022
A simple processor emulator written in c++ that can parse and execute x32 code. x32 is binary code made by me for this processor.

A SIMPLE PROCESSOR EMULATOR AND CODE EXECUTOR The Repository This is a fairly new project and is still heavy in development. If you find and bugs feel

Luka Golob 4 Jan 20, 2022
VMPImportFixer is a tool aimed to resolve import calls in a VMProtect'd (3.x) binary.

VMPImportFixer VMPImportFixer is a tool aimed to resolve import calls in a VMProtect'd (3.x) binary. Information VMPImportFixer attempts to resolve al

null 240 Jun 24, 2022
C++ Simplistic Binary Stream

C++ Simplistic Binary Stream Bare minimal header-only binary stream based on C++ file streams where the stream operator can be overloaded for your cus

null 22 Apr 27, 2022