Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into Discovered-more-i38…
Browse files Browse the repository at this point in the history
…6-xrefs
  • Loading branch information
Arker123 committed Jun 26, 2024
2 parents 47c79f1 + e4595b2 commit 606d01a
Show file tree
Hide file tree
Showing 25 changed files with 413 additions and 150 deletions.
18 changes: 10 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,21 @@ jobs:
# Pin action version by commit hash to maximize trust, ref: https://securitylab.github.com/research/github-actions-building-blocks/
steps:
- name: Checkout floss
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: false
# using Python 3.8 to support running across multiple operating systems including Windows 7
- name: Set up Python 3.8
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: '3.8'
- name: Install floss [build]
run: pip install -e .[build]
run: |
pip install -r requirements.txt
pip install -e .[build]
- name: Build standalone executable
run: pyinstaller .github/pyinstaller/floss.spec
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: ${{ matrix.asset_name }}
path: dist/${{ matrix.artifact_name }}
Expand Down Expand Up @@ -67,11 +69,11 @@ jobs:
asset_name: macos
steps:
- name: Download ${{ matrix.asset_name }}
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
with:
name: ${{ matrix.asset_name }}
- name: Checkout testfiles
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
repository: mandiant/flare-floss-testfiles
path: tests/data
Expand Down Expand Up @@ -100,7 +102,7 @@ jobs:
artifact_name: floss
steps:
- name: Download ${{ matrix.asset_name }}
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
with:
name: ${{ matrix.asset_name }}
- name: Set executable flag
Expand All @@ -110,7 +112,7 @@ jobs:
- name: Zip ${{ matrix.artifact_name }} into ${{ env.zip_name }}
run: zip ${{ env.zip_name }} ${{ matrix.artifact_name }}
- name: Upload ${{ env.zip_name }} to GH Release
uses: svenstaro/upload-release-action@v2
uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # v2.9.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ env.zip_name }}
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,25 @@ jobs:
permissions:
id-token: write
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up Python
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e .[build]
- name: build package
run: |
python -m build
- name: upload package artifacts
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
path: dist/*
- name: publish package
uses: pypa/gh-action-pypi-publish@f5622bde02b04381239da3573277701ceca8f6a0 # release/v1
uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450 # v1.8.14
with:
skip-existing: true
verbose: true
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ jobs:
# Pin action version by commit hash to maximize trust, ref: https://securitylab.github.com/research/github-actions-building-blocks/
steps:
- name: Checkout FLOSS
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up Python 3.8
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: '3.8'
- name: Install dependencies
run: pip install -e .[dev]
run: |
pip install -r requirements.txt
pip install -e .[dev]
- name: Lint with isort
run: pre-commit run isort
- name: Lint with black
Expand All @@ -48,17 +50,19 @@ jobs:
python-version: '3.10'
steps:
- name: Checkout FLOSS with submodule
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: ${{ matrix.python-version }}
- name: Install pyyaml
if: matrix.os == 'ubuntu-20.04'
run: sudo apt-get install -y libyaml-dev
- name: Install FLOSS
run: pip install -e .[dev]
run: |
pip install -r requirements.txt
pip install -e .[dev]
- name: Run tests
run: pytest tests/
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ flare_floss.egg-info

# vscode
.vscode
.direnv/
.env/
.envrc
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Not all compilers use string formats that the classic `strings.exe` algorithm su
1. Go
2. Rust

The strings FLOSS extracts specific to a compiler are must easier to inspect by humans.
The strings FLOSS extracts specific to a compiler are much easier to inspect by humans.

Please consult the documentation to learn more about the [language-specific string extraction](doc/language_specific_strings.md).

Expand Down
9 changes: 9 additions & 0 deletions doc/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ This means that Python will load the FLOSS module from this local
This is good, because it is easy for us to modify files and see the
effects reflected immediately.
But be careful not to remove this directory unless uninstalling FLOSS!
If you encounter the error `ERROR: Project has a 'pyproject.toml' and its build backend is missing the 'build_editable' hook.`,
please ensure that you have upgraded to the latest versions of pip and setuptools.


- Install FLOSS:

Expand All @@ -87,6 +90,12 @@ You'll find that the `floss.exe` (Windows) or `floss` (Linux, macOS) executables

### Step 3: Install development and testing dependencies

When developing FLOSS, please use the pinned dependencies found in `requirements.txt`.
This ensures that everyone has the exact same, reproducible environment.
Please install these dependencies before install FLOSS (from source or from PyPI):

`$ pip install -r requirements.txt`

To install all testing and development dependencies, run:

`$ pip install -e /local/path/to/src[dev]`
Expand Down
10 changes: 10 additions & 0 deletions doc/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@ Specify functions by using their hex-encoded virtual address.
floss.exe --functions 0x401000 0x402000 malware.exe


### Install/Uninstall right click menu option for Windows (`--install-right-click-menu/--uninstall-right-click-menu`)

You can use the `--install-right-click-menu` and `--uninstall-right-click-menu`
options to install/remove the `Open with FLOSS` option from the right-click menu
of the Windows file explorer.

After this option is installed, you can right-click on any file and select `Open with FLOSS`
to quickly open the target file with FLOSS for analysis.


## <a name="shellcode"></a>Shellcode analysis options

Malicious shellcode often times contains obfuscated strings or stackstrings.
Expand Down
6 changes: 5 additions & 1 deletion floss/identify.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ def find_decoding_function_features(vw, functions, disable_progress=False) -> Tu

f = viv_utils.Function(vw, function_address)

function_data = {"meta": get_function_meta(f), "features": list()}
function_data = {
"meta": get_function_meta(f),
"features": [],
"xrefs_to": len(list(vw.getXrefsTo(function_address))),
}

# meta data features
function_data["features"].append(BlockCount(function_data["meta"].get("block_count")))
Expand Down
7 changes: 7 additions & 0 deletions floss/language/rust/rust_version_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@


rust_commit_hash = {
"a28077b28a02b92985b3a3faecf92813155f1ea1": "1.74.1",
"79e9716c980570bfd1f666e3b16ac583f0168962": "1.74.0",
"cc66ad468955717ab92600c770da8c1601a4ff33": "1.73.0",
"d5c2e9c342b358556da91d61ed4133f6f50fc0c3": "1.72.1",
"5680fa18feaa87f3ff04063800aec256c3d4b4be": "1.72.0",
"eb26296b556cef10fb713a38f3d16b9886080f26": "1.71.1",
"8ede3aae28fe6e4d52b38157d7bfe0d3bceef225": "1.71.0",
"90c541806f23a127002de5b4038be731ba1458ca": "1.70.0",
"84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc": "1.69.0",
"9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0": "1.68.2",
Expand Down
65 changes: 49 additions & 16 deletions floss/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ def make_parser(argv):
)
parser.register("action", "extend", floss.utils.ExtendAction)
parser.add_argument("-H", action="help", help="show advanced options and exit")

parser.add_argument(
"-n",
"--minimum-length",
Expand Down Expand Up @@ -200,9 +199,11 @@ def make_parser(argv):
type=str,
choices=[l.value for l in Language if l != Language.UNKNOWN],
default=Language.UNKNOWN.value,
help="use language-specific string extraction, auto-detect language by default, disable using 'none'"
if show_all_options
else argparse.SUPPRESS,
help=(
"use language-specific string extraction, auto-detect language by default, disable using 'none'"
if show_all_options
else argparse.SUPPRESS
),
)
advanced_group.add_argument(
"-l",
Expand All @@ -215,9 +216,11 @@ def make_parser(argv):
type=lambda x: int(x, 0x10),
default=None,
nargs="+",
help="only analyze the specified functions, hex-encoded like 0x401000, space-separate multiple functions"
if show_all_options
else argparse.SUPPRESS,
help=(
"only analyze the specified functions, hex-encoded like 0x401000, space-separate multiple functions"
if show_all_options
else argparse.SUPPRESS
),
)
advanced_group.add_argument(
"--disable-progress",
Expand All @@ -228,24 +231,48 @@ def make_parser(argv):
"--signatures",
type=str,
default=SIGNATURES_PATH_DEFAULT_STRING,
help="path to .sig/.pat file or directory used to identify library functions, use embedded signatures by default"
if show_all_options
else argparse.SUPPRESS,
help=(
"path to .sig/.pat file or directory used to identify library functions, use embedded signatures by default"
if show_all_options
else argparse.SUPPRESS
),
)
advanced_group.add_argument(
"-L",
"--large-file",
action="store_true",
help="allow processing files larger than {} MB".format(int(MAX_FILE_SIZE / MEGABYTE))
if show_all_options
else argparse.SUPPRESS,
help=(
"allow processing files larger than {} MB".format(int(MAX_FILE_SIZE / MEGABYTE))
if show_all_options
else argparse.SUPPRESS
),
)
advanced_group.add_argument(
"--version",
action="version",
version="%(prog)s {:s}".format(__version__),
help="show program's version number and exit" if show_all_options else argparse.SUPPRESS,
)
if sys.platform == "win32":
advanced_group.add_argument(
"--install-right-click-menu",
action=floss.utils.InstallContextMenu,
help=(
"install FLOSS to the right-click context menu for Windows Explorer and exit"
if show_all_options
else argparse.SUPPRESS
),
)

advanced_group.add_argument(
"--uninstall-right-click-menu",
action=floss.utils.UninstallContextMenu,
help=(
"uninstall FLOSS from the right-click context menu for Windows Explorer and exit"
if show_all_options
else argparse.SUPPRESS
),
)

output_group = parser.add_argument_group("rendering arguments")
output_group.add_argument("-j", "--json", action="store_true", help="emit JSON instead of text")
Expand Down Expand Up @@ -598,7 +625,11 @@ def main(argv=None) -> int:

if results.metadata.language not in ("", "unknown"):
if args.enabled_types == [] and args.disabled_types == []:
prompt = input("Do you want to enable string deobfuscation? (this could take a long time) [y/N] ")
# when stdout is redirected, such as in 'floss foo.exe | less' use default prompt values
if sys.stdout.isatty():
prompt = input("Do you want to enable string deobfuscation? (this could take a long time) [y/N] ")
else:
prompt = "n"

if prompt.lower() == "y":
logger.info("enabled string deobfuscation")
Expand Down Expand Up @@ -752,8 +783,10 @@ def main(argv=None) -> int:
else:
logger.debug("identified %d candidate decoding functions", len(fvas_to_emulate))
for fva in fvas_to_emulate:
results.analysis.functions.decoding_function_scores[fva] = decoding_function_features[fva]["score"]
logger.debug(" - 0x%x: %.3f", fva, decoding_function_features[fva]["score"])
score = decoding_function_features[fva]["score"]
xrefs_to = decoding_function_features[fva]["xrefs_to"]
results.analysis.functions.decoding_function_scores[fva] = {"score": score, "xrefs_to": xrefs_to}
logger.debug(" - 0x%x: score: %.3f, xrefs to: %d", fva, score, xrefs_to)

# TODO filter out strings decoded in library function or function only called by library function(s)
results.strings.decoded_strings = decode_strings(
Expand Down
20 changes: 12 additions & 8 deletions floss/render/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,19 @@ def render_string_type_rows(results: ResultDocument) -> List[Tuple[str, str]]:
return [
(
" static strings",
f"{len_ss:>{len(str(len_ss))}} ({len_chars_ss:>{len(str(len_chars_ss))}d} characters)"
if results.analysis.enable_static_strings
else DISABLED,
(
f"{len_ss:>{len(str(len_ss))}} ({len_chars_ss:>{len(str(len_chars_ss))}d} characters)"
if results.analysis.enable_static_strings
else DISABLED
),
),
(
" language strings",
f"{len_ls:>{len(str(len_ss))}} ({len_chars_ls:>{len(str(len_chars_ss))}d} characters)"
if results.metadata.language
else DISABLED,
(
f"{len_ls:>{len(str(len_ss))}} ({len_chars_ls:>{len(str(len_chars_ss))}d} characters)"
if results.metadata.language
else DISABLED
),
),
(
" stack strings",
Expand Down Expand Up @@ -134,11 +138,11 @@ def render_function_analysis_rows(results) -> List[Tuple[str, str]]:
if results.analysis.functions.decoding_function_scores:
rows.append(
(
" identified decoding functions\n (offset and score)",
" identified decoding functions\n (offset, score, and number of xrefs to)",
textwrap.fill(
", ".join(
[
f"0x{fva:x} ({d:.3f})"
f"0x{fva:x} ({d['score']:.3f}, xrefs_to: {d['xrefs_to']})"
for fva, d in results.analysis.functions.decoding_function_scores.items()
]
),
Expand Down
Loading

0 comments on commit 606d01a

Please sign in to comment.