[Maintenance] Remove unmaintained commands, tests, and documentation, and moved to Ruff (#1222)

## Description

This PR  
 - removes unmaintained `shellcode` commands, tests, and documentation
- (finally) switches to Ruff instead of Pylint (still handled by
`pre-commit`)
 - fixes a few ruff/ty-found issues
This commit is contained in:
crazy hugsy
2026-05-02 12:15:26 -07:00
committed by GitHub
parent fd8ec6ff12
commit 90cced847b
69 changed files with 3073 additions and 30047 deletions
+17 -15
View File
@@ -2,24 +2,26 @@ default_stages: [pre-commit, pre-push]
fail_fast: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pycqa/pylint
rev: v3.0.0a6
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.2
hooks:
- id: pylint
- id: ruff-check
args: [ --fix ]
- id: ruff-format
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.35.0
rev: v0.48.0
hooks:
- id: markdownlint-docker
args:
- --config=docs/.markdownlint.yaml
- --ignore=docs/api/gef.md
- --ignore=docs/obsolete/docs/index.md
- --ignore=docs/index.md
- --ignore=README.md
- "docs/**/*.md"
- id: markdownlint-docker
args:
- --config=docs/.markdownlint.yaml
- --ignore=docs/api/gef.md
- --ignore=docs/obsolete/docs/index.md
- --ignore=docs/index.md
- --ignore=README.md
- "docs/**/*.md"
-904
View File
@@ -1,904 +0,0 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-allow-list=
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
# for backward compatibility.)
extension-pkg-whitelist=
# Return non-zero exit code if any of these messages/categories are detected,
# even if score is above --fail-under value. Syntax same as enable. Messages
# specified are enabled, while categories only check already-enabled messages.
fail-on=
# Specify a score threshold to be exceeded before program exits with error.
fail-under=10.0
# Files or directories to be skipped. They should be base names, not paths.
ignore=CVS
# Add files or directories matching the regex patterns to the ignore-list. The
# regex matches against paths and can be in Posix or Windows format.
ignore-paths=
# Files or directories matching the regex patterns are skipped. The regex
# matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
jobs=0
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Minimum Python version to use for version dependent checks. Will default to
# the version used to run pylint.
py-version=3.10
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
; disable=invalid-name,
; disallowed-name,
; empty-docstring,
; missing-module-docstring,
; missing-class-docstring,
; missing-function-docstring,
; unidiomatic-typecheck,
; non-ascii-name,
; consider-using-enumerate,
; consider-iterating-dictionary,
; bad-classmethod-argument,
; bad-mcs-method-argument,
; bad-mcs-classmethod-argument,
; single-string-used-for-slots,
; consider-using-dict-items,
; use-maxsplit-arg,
; use-sequence-for-iteration,
; too-many-lines,
; missing-final-newline,
; trailing-newlines,
; superfluous-parens,
; mixed-line-endings,
; unexpected-line-ending-format,
; wrong-spelling-in-comment,
; wrong-spelling-in-docstring,
; invalid-characters-in-docstring,
; multiple-imports,
; wrong-import-order,
; ungrouped-imports,
; wrong-import-position,
; useless-import-alias,
; import-outside-toplevel,
; use-implicit-booleaness-not-len,
; use-implicit-booleaness-not-comparison,
; raw-checker-failed,
; bad-inline-option,
; locally-disabled,
; file-ignored,
; suppressed-message,
; useless-suppression,
; deprecated-pragma,
; use-symbolic-message-instead,
; c-extension-no-member,
; literal-comparison,
; comparison-with-itself,
; no-self-use,
; no-classmethod-decorator,
; no-staticmethod-decorator,
; useless-object-inheritance,
; property-with-parameters,
; cyclic-import,
; consider-using-from-import,
; duplicate-code,
; too-many-ancestors,
; too-many-instance-attributes,
; too-few-public-methods,
; too-many-public-methods,
; too-many-return-statements,
; too-many-branches,
; too-many-arguments,
; too-many-locals,
; too-many-statements,
; too-many-boolean-expressions,
; consider-merging-isinstance,
; too-many-nested-blocks,
; simplifiable-if-statement,
; redefined-argument-from-local,
; no-else-return,
; consider-using-ternary,
; trailing-comma-tuple,
; stop-iteration-return,
; simplify-boolean-expression,
; inconsistent-return-statements,
; useless-return,
; consider-swap-variables,
; consider-using-join,
; consider-using-in,
; consider-using-get,
; chained-comparison,
; consider-using-dict-comprehension,
; consider-using-set-comprehension,
; simplifiable-if-expression,
; no-else-raise,
; unnecessary-comprehension,
; consider-using-sys-exit,
; no-else-break,
; no-else-continue,
; super-with-arguments,
; simplifiable-condition,
; condition-evals-to-constant,
; consider-using-generator,
; use-a-generator,
; consider-using-min-builtin,
; consider-using-max-builtin,
; consider-using-with,
; unnecessary-dict-index-lookup,
; use-list-literal,
; use-dict-literal,
; pointless-statement,
; pointless-string-statement,
; expression-not-assigned,
; unnecessary-pass,
; unnecessary-lambda,
; assign-to-new-keyword,
; useless-else-on-loop,
; exec-used,
; eval-used,
; confusing-with-statement,
; using-constant-test,
; missing-parentheses-for-call-in-test,
; self-assigning-variable,
; redeclared-assigned-name,
; assert-on-string-literal,
; comparison-with-callable,
; lost-exception,
; nan-comparison,
; assert-on-tuple,
; attribute-defined-outside-init,
; bad-staticmethod-argument,
; protected-access,
; arguments-differ,
; signature-differs,
; abstract-method,
; super-init-not-called,
; no-init,
; non-parent-init-called,
; useless-super-delegation,
; invalid-overridden-method,
; arguments-renamed,
; unused-private-member,
; overridden-final-method,
; subclassed-final-class,
; bad-indentation,
; wildcard-import,
; deprecated-module,
; reimported,
; import-self,
; preferred-module,
; misplaced-future,
; fixme,
; global-variable-undefined,
; global-statement,
; global-at-module-level,
; unused-argument,
; unused-wildcard-import,
; redefined-outer-name,
; redefined-builtin,
; undefined-loop-variable,
; unbalanced-tuple-unpacking,
; cell-var-from-loop,
; possibly-unused-variable,
; self-cls-assignment,
; bare-except,
; broad-except,
; duplicate-except,
; try-except-raise,
; raise-missing-from,
; raising-format-tuple,
; wrong-exception-operation,
; keyword-arg-before-vararg,
; arguments-out-of-order,
; non-str-assignment-to-dunder-name,
; isinstance-second-argument-not-valid-type,
; logging-not-lazy,
; logging-format-interpolation,
; logging-fstring-interpolation,
; bad-format-string-key,
; unused-format-string-key,
; missing-format-argument-key,
; unused-format-string-argument,
; format-combined-specification,
; missing-format-attribute,
; invalid-format-index,
; duplicate-string-formatting-argument,
; f-string-without-interpolation,
; useless-with-lock
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
; enable=unneeded-not,
; format-string-without-interpolation,
; anomalous-unicode-escape-in-string,
; implicit-str-concat,
; inconsistent-quotes,
; redundant-u-string-prefix,
; boolean-datetime,
; redundant-unittest-assert,
; deprecated-method,
; bad-thread-instantiation,
; shallow-copy-environ,
; invalid-envvar-default,
; subprocess-popen-preexec-fn,
; subprocess-run-check,
; deprecated-argument,
; deprecated-class,
; deprecated-decorator,
; unspecified-encoding,
; forgotten-debug-statement,
; using-f-string-in-unsupported-version,
; using-final-decorator-in-unsupported-version,
; singleton-comparison,
; consider-using-f-string,
; line-too-long,
; trailing-whitespace,
; multiple-statements,
; syntax-error,
; unrecognized-inline-option,
; bad-option-value,
; bad-plugin-value,
; bad-configuration-section,
; init-is-generator,
; return-in-init,
; function-redefined,
; not-in-loop,
; return-outside-function,
; yield-outside-function,
; return-arg-in-generator,
; nonexistent-operator,
; duplicate-argument-name,
; abstract-class-instantiated,
; bad-reversed-sequence,
; too-many-star-expressions,
; invalid-star-assignment-target,
; star-needs-assignment-target,
; nonlocal-and-global,
; continue-in-finally,
; nonlocal-without-binding,
; used-prior-global-declaration,
; misplaced-format-function,
; method-hidden,
; access-member-before-definition,
; no-method-argument,
; no-self-argument,
; invalid-slots-object,
; assigning-non-slot,
; invalid-slots,
; inherit-non-class,
; inconsistent-mro,
; duplicate-bases,
; class-variable-slots-conflict,
; invalid-class-object,
; non-iterator-returned,
; unexpected-special-method-signature,
; invalid-length-returned,
; invalid-bool-returned,
; invalid-index-returned,
; invalid-repr-returned,
; invalid-str-returned,
; invalid-bytes-returned,
; invalid-hash-returned,
; invalid-length-hint-returned,
; invalid-format-returned,
; invalid-getnewargs-returned,
; invalid-getnewargs-ex-returned,
; import-error,
; relative-beyond-top-level,
; used-before-assignment,
; undefined-variable,
; undefined-all-variable,
; invalid-all-object,
; invalid-all-format,
; no-name-in-module,
; unpacking-non-sequence,
; bad-except-order,
; raising-bad-type,
; bad-exception-context,
; misplaced-bare-raise,
; raising-non-exception,
; notimplemented-raised,
; catching-non-exception,
; bad-super-call,
; no-member,
; not-callable,
; assignment-from-no-return,
; no-value-for-parameter,
; too-many-function-args,
; unexpected-keyword-arg,
; redundant-keyword-arg,
; missing-kwoa,
; invalid-sequence-index,
; invalid-slice-index,
; assignment-from-none,
; not-context-manager,
; invalid-unary-operand-type,
; unsupported-binary-operation,
; repeated-keyword,
; not-an-iterable,
; not-a-mapping,
; unsupported-membership-test,
; unsubscriptable-object,
; unsupported-assignment-operation,
; unsupported-delete-operation,
; invalid-metaclass,
; unhashable-dict-key,
; dict-iter-missing-items,
; await-outside-async,
; logging-unsupported-format,
; logging-format-truncated,
; logging-too-many-args,
; logging-too-few-args,
; bad-format-character,
; truncated-format-string,
; mixed-format-string,
; format-needs-mapping,
; missing-format-string-key,
; too-many-format-args,
; too-few-format-args,
; bad-string-format-type,
; bad-str-strip-call,
; invalid-envvar-value,
; yield-inside-async-function,
; not-async-context-manager,
; fatal,
; astroid-error,
; parse-error,
; config-parse-error,
; method-check-failed,
; unreachable,
; dangerous-default-value,
; duplicate-key,
; unnecessary-semicolon,
; global-variable-not-assigned,
; unused-import,
; unused-variable,
; binary-op-exception,
; bad-format-string,
; anomalous-backslash-in-string,
; bad-open-mode
enable =
F,
E,
anomalous-backslash-in-string,
bad-format-string,
bad-open-mode,
consider-using-f-string,
dangerous-default-value,
duplicate-key,
global-variable-not-assigned
line-too-long,
singleton-comparison,
trailing-whitespace,
unnecessary-semicolon,
unneeded-not,
unreachable,
unused-import,
unused-variable,
binary-op-exception
disable = all
[REPORTS]
# Python expression which should return a score less than or equal to 10. You
# have access to the variables 'error', 'warning', 'refactor', and 'convention'
# which contain the number of messages in each category, as well as 'statement'
# which is the total number of statements analyzed. This score is used by the
# global evaluation report (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages.
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit,argparse.parse_error
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=200
# Maximum number of lines in a module.
max-module-lines=15000
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it work,
# install the 'python-enchant' package.
spelling-dict=
# List of comma separated words that should be considered directives if they
# appear and the beginning of a comment and should not be checked.
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains the private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to the private dictionary (see the
# --spelling-private-dict-file option) instead of raising a message.
spelling-store-unknown-words=no
[LOGGING]
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style=old
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of names allowed to shadow builtins
allowed-redefined-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
[SIMILARITIES]
# Comments are removed from the similarity computation
ignore-comments=yes
# Docstrings are removed from the similarity computation
ignore-docstrings=yes
# Imports are removed from the similarity computation
ignore-imports=no
# Signatures are removed from the similarity computation
ignore-signatures=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
# Regular expression of note tags to take in consideration.
#notes-rgx=
[BASIC]
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style.
#argument-rgx=
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Bad variable names regexes, separated by a comma. If names match any regex,
# they will always be refused
bad-names-rgxs=
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
#class-attribute-rgx=
# Naming style matching correct class constant names.
class-const-naming-style=UPPER_CASE
# Regular expression matching correct class constant names. Overrides class-
# const-naming-style.
#class-const-rgx=
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style.
#class-rgx=
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style.
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names.
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style.
#function-rgx=
# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_
# Good variable names regexes, separated by a comma. If names match any regex,
# they will always be accepted
good-names-rgxs=
# Include a hint for the correct naming format with invalid-name.
include-naming-hint=no
# Naming style matching correct inline iteration names.
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
#inlinevar-rgx=
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style.
#method-rgx=
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style.
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style.
#variable-rgx=
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=no
# This flag controls whether the implicit-str-concat should generate a warning
# on implicit string concatenation in sequences defined over several lines.
check-str-concat-over-line-jumps=no
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# class is considered mixin if its name matches the mixin-class-rgx option.
ignore-mixin-members=yes
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
# Regex pattern to define which classes are considered mixins ignore-mixin-
# members is set to 'yes'
mixin-class-rgx=.*[Mm]ixin
# List of decorators that change the signature of a decorated function.
signature-mutators=
[IMPORTS]
# List of modules that can be imported at any level, not just the top level
# one.
allow-any-import-level=
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=
# Output a graph (.gv or any supported image format) of external dependencies
# to the given file (report RP0402 must not be disabled).
ext-import-graph=
# Output a graph (.gv or any supported image format) of all (i.e. internal and
# external) dependencies to the given file (report RP0402 must not be
# disabled).
import-graph=
# Output a graph (.gv or any supported image format) of internal dependencies
# to the given file (report RP0402 must not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
# Couples of modules and preferred modules, separated by a comma.
preferred-modules=
[DESIGN]
# List of regular expressions of class ancestor names to ignore when counting
# public methods (see R0903)
exclude-too-few-public-methods=
# List of qualified class names to ignore when counting class parents (see
# R0901)
ignored-parents=
# Maximum number of arguments for function / method.
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in an if statement (see R0916).
max-bool-expr=5
# Maximum number of branch for function / method body.
max-branches=12
# Maximum number of locals for function / method body.
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body.
max-returns=6
# Maximum number of statements in function / method body.
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[CLASSES]
# Warn about protected attribute access inside special methods
check-protected-access-in-special-methods=no
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp,
__post_init__
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "BaseException, Exception".
overgeneral-exceptions=BaseException,
Exception
+9 -5
View File
@@ -3,7 +3,9 @@
As long as the 'memory' section is enabled in your context layout (which it is by default), you can
register addresses, lengths, and grouping size.
![memory watch](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/memory watch.png)
<!-- markdownlint-disable MD013,MD034 -->
![memory watch](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/memory-watch.png)
<!-- markdownlint-enable MD013,MD034 -->
_Note_: this command **should NOT** be mistaken with the [GDB `watch`
command](https://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html) meant to set
@@ -23,9 +25,10 @@ If the format specified is `pointers`, then the output will be similar to execut
`dereference $address`. For all other format, the output will be an hexdump of the designated
location.
Note that the address format is a GDB therefore a symbol can be passed to it. It also supports [GEF
functions
format](https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html)
Note that the address format is a GDB therefore a symbol can be passed to it. It also supports
<!-- markdownlint-disable MD013 -->
[GEF functions format](https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html)
<!-- markdownlint-enable MD013 -->
allowing to easily track commonly used addresses:
For example, to watch the first 5 entries of the [GOT](https://hugsy.github.io/gef/functions/got/)
@@ -37,8 +40,9 @@ gef ➤ memory watch $_got()+0x18 5
```
Which, when the `context` is displayed, will show something like:
<!-- markdownlint-disable MD013 -->
![gef-context-memory](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/gef-context-memory.png)
<!-- markdownlint-enable MD013 -->
### Removing a watch
+4 -2
View File
@@ -120,8 +120,10 @@ For a full demo, watch the following tutorial:
Additionally, if you have successfully configured your IDA settings, you can also directly import
the structure(s) that was(were) reverse-engineered in IDA directly in your GDB session:
![ida-structure-examples](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/ida-structure-examples.png) - (see `gef-extras/ida-rpyc`,
which is the new improved version of `ida-interact`)
<!-- markdownlint-disable MD013 -->
![ida-structure-examples](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/ida-structure-examples.png)
<!-- markdownlint-enable MD013 -->
(see `gef-extras/ida-rpyc`, which is the new improved version of `ida-interact`)
#### Dynamic `ctypes.Structure`-like classes
-31
View File
@@ -1,31 +0,0 @@
## Command `shellcode`
`shellcode` is a command line client for @JonathanSalwan shellcodes database. It can be used to
search and download directly via `GEF` the shellcode you're looking for. Two primitive subcommands
are available, `search` and `get`
```text
gef➤ shellcode search arm
[+] Showing matching shellcodes
901 Linux/ARM Add map in /etc/hosts file - 79 bytes
853 Linux/ARM chmod("/etc/passwd", 0777) - 39 bytes
854 Linux/ARM creat("/root/pwned", 0777) - 39 bytes
855 Linux/ARM execve("/bin/sh", [], [0 vars]) - 35 bytes
729 Linux/ARM Bind Connect UDP Port 68
730 Linux/ARM Bindshell port 0x1337
[...]
gef➤ shellcode get 698
[+] Downloading shellcode id=698
[+] Shellcode written as '/tmp/sc-EfcWtM.txt'
gef➤ system cat /tmp/sc-EfcWtM.txt
/*
Title: Linux/ARM - execve("/bin/sh", [0], [0 vars]) - 27 bytes
Date: 2010-09-05
Tested on: ARM926EJ-S rev 5 (v5l)
Author: Jonathan Salwan - twitter: @jonathansalwan
shell-storm.org
Shellcode ARM without 0x20, 0x0a and 0x00
[...]
```
+6 -2
View File
@@ -23,8 +23,12 @@ Patching `fork()` calls:
* Without stub:
![fork execution](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/fork execution.png)
<!-- markdownlint-disable MD013,MD034 -->
![fork execution](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/fork-execution.png)
<!-- markdownlint-enable MD013,MD034 -->
* With stub:
![stubbed fork](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/stubbed fork.png)
<!-- markdownlint-disable MD013,MD034 -->
![stubbed fork](https://raw.githubusercontent.com/hugsy/gef/refs/heads/main/docs/assets/images/stubbed-fork.png)
<!-- markdownlint-enable MD013,MD034 -->
+1
View File
@@ -16,6 +16,7 @@ page aims to track those changes.
| `windbg` | Moved | [a933a5a](https://github.com/hugsy/gef-extras/commit/a933a5ac43933742d91f4e299eadf05e3e0670be) | [New location](https://github.com/hugsy/gef-extras/blob/main/scripts/windbg.py) | |
| `is-syscall` | Moved | [3f79fb38](https://github.com/hugsy/gef-extras/commit/3f79fb382aa9052d073698d40237f98982c5d2de) | [New location](https://github.com/hugsy/gef-extras/blob/main/scripts/syscall_args) | |
| `syscall-args` | Moved | [3f79fb38](https://github.com/hugsy/gef-extras/commit/3f79fb382aa9052d073698d40237f98982c5d2de) | [New location](https://github.com/hugsy/gef-extras/blob/main/scripts/syscall_args) | |
| `shellcode` | Removed | 2026.06 | N/A | Reason: `http://shell-storm.org` not active |
## Removed support for pyenv
+1 -1
View File
@@ -138,7 +138,7 @@ cases, the following command is enough:
```bash
cd /root/of/gef
python3 -m pylint --rcfile .pylintrc
ruff check ./gef.py [other/python/file/added/modified]
```
Note that to ensure compatibility, tests must be executed with the same Python version GDB was
+2746 -1315
View File
File diff suppressed because it is too large Load Diff
-27506
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -61,7 +61,6 @@ nav:
- reset-cache: commands/reset-cache.md
- scan: commands/scan.md
- search-pattern: commands/search-pattern.md
- shellcode: commands/shellcode.md
- stub: commands/stub.md
- stepover: commands/stepover.md
- skipi: commands/skipi.md
+99 -49
View File
@@ -12,24 +12,25 @@ from https://github.com/settings/tokens/new).
import argparse
import datetime
import requests
import subprocess
import os
import pathlib
import subprocess
import tempfile
__author__ = "@_hugsy_"
__version__ = 0.1
__licence__ = "MIT"
__file__ = "new-release.py"
__desc__ = "Generate a new release for a Github project."
__usage__ = f"""{__file__} v{__version__}\nby {__author__} under {__licence__}\nsyntax: {__file__} [options] args"""
import requests
__author__ = "@_hugsy_"
__version__ = 0.1
__licence__ = "MIT"
__file__ = "new-release.py"
__desc__ = "Generate a new release for a Github project."
__usage__ = f"""{__file__} v{__version__}\nby {__author__} under {__licence__}\nsyntax: {__file__} [options] args"""
REPOSITORY = "hugsy/gef"
GITHUB_TOKEN = os.getenv("GITHUB_REPO_TOKEN")
DEBUG = False
OUTPUT_FILE = pathlib.Path( tempfile.gettempdir() ) / "CHANGELOG.md"
REPOSITORY = "hugsy/gef"
GITHUB_TOKEN = os.getenv("GITHUB_REPO_TOKEN")
DEBUG = False
OUTPUT_FILE = pathlib.Path(tempfile.gettempdir()) / "CHANGELOG.md"
GITHUB_NEW_TOKEN_URL = "https://github.com/settings/personal-access-tokens/new"
@@ -49,36 +50,42 @@ def generate_changelog(args: argparse.Namespace) -> bool:
latest_tag = shell("git describe --tags --abbrev=0")
print(f"Creating changelog for {args.version} in {args.output_file.name}")
args.output_file.write(f"# Changelog: {args.version} - {args.codename}{os.linesep}{os.linesep}")
content = f"# Changelog: {args.version} - {args.codename}{os.linesep}{os.linesep}"
dbg("Adding commit summary...")
args.output_file.write(f"## Highlights of `{args.codename}`{os.linesep}{os.linesep}")
args.output_file.write(f"{os.linesep}{os.linesep}")
content += f"## Highlights of `{args.codename}`{os.linesep}{os.linesep}"
content += f"{os.linesep}{os.linesep}"
dbg("Adding contributor summary...")
args.output_file.write(f"## Contributors{os.linesep}{os.linesep}")
contributor_names = shell(f"git log {latest_tag}..HEAD --pretty=format:'%aN' | sort -u").splitlines()
content += f"## Contributors{os.linesep}{os.linesep}"
contributor_names = shell(
f"git log {latest_tag}..HEAD --pretty=format:'%aN' | sort -u"
).splitlines()
commits = {}
for author in contributor_names:
author_commits = shell(f'git log {latest_tag}..HEAD --pretty=format:"%h" --author="{author}"').splitlines()
commits[ author ] = len(author_commits)
author_commits = shell(
f'git log {latest_tag}..HEAD --pretty=format:"%h" --author="{author}"'
).splitlines()
commits[author] = len(author_commits)
total_commits = sum(commits.values())
args.output_file.write(f"| Author | Number of commits | {os.linesep}")
args.output_file.write(f"|:--|--:| {os.linesep}")
content += f"| Author | Number of commits | {os.linesep}"
content += f"|:--|--:| {os.linesep}"
commits_sorted = dict(sorted(commits.items(), key=lambda item: -item[1]))
for author in commits_sorted:
args.output_file.write(f"| {author} | {commits[author]}|{os.linesep}")
args.output_file.write(f"{os.linesep}{os.linesep}")
content += f"| {author} | {commits[author]}|{os.linesep}"
content += f"{os.linesep}{os.linesep}"
dbg("Adding Github info...")
url = f"https://api.github.com/repos/{args.repository}/issues?state=closed&milestone.title=Release%3a%20{args.version}"
js = requests.get(url, headers={"Authorization": f"token {args.token}"}).json()
prs = { x['number']: x['html_url'] for x in js if "pull" in x['html_url'] }
issues = { x['number']: x['html_url'] for x in js if "issues" in x['html_url'] }
prs = {x["number"]: x["html_url"] for x in js if "pull" in x["html_url"]}
issues = {x["number"]: x["html_url"] for x in js if "issues" in x["html_url"]}
closed_prs_item = " &bull; ".join([f" [{nb}]({url}) " for nb, url in prs.items()])
closed_issues_item = " &bull; ".join([f" [{nb}]({url}) " for nb, url in issues.items()])
args.output_file.write(f"""
closed_issues_item = " &bull; ".join(
[f" [{nb}]({url}) " for nb, url in issues.items()]
)
content += f"""
## Closed Issues
* {len(issues)} issues closed ({closed_issues_item})
@@ -88,12 +95,14 @@ def generate_changelog(args: argparse.Namespace) -> bool:
* {len(prs)} PRs closed ({closed_prs_item})
""")
"""
dbg("Adding commit summary...")
log = shell(f"""git log {latest_tag}..HEAD --pretty=format:' * %cs [%h](https://github.com/{args.repository}/commit/%H) &bull; *%aN* &bull; %s ' --reverse""")
log = shell(
f"""git log {latest_tag}..HEAD --pretty=format:' * %cs [%h](https://github.com/{args.repository}/commit/%H) &bull; *%aN* &bull; %s ' --reverse"""
)
diff = shell(f"""git diff --no-color --stat {latest_tag}..HEAD""")
args.output_file.write(f"""
content += f"""
## Commit details
<details>
@@ -113,11 +122,14 @@ def generate_changelog(args: argparse.Namespace) -> bool:
</details>
""")
"""
args.output_file.write_text(content)
print(f"Done, the changelog file was written to `{args.output_file.name}`")
if args.push_release:
shell(f"""git tag --annotate "{args.version}" --message "Release {args.version} - {args.codename}" --sign""")
shell(
f"""git tag --annotate "{args.version}" --message "Release {args.version} - {args.codename}" --sign"""
)
shell(f"""git push origin "{args.version}" """)
return True
@@ -128,32 +140,70 @@ def test_token(args) -> bool:
req = requests.get(url, headers={"Authorization": f"token {args.token}"})
if req.status_code != 200:
print(f"test_token(): return HTTP code {req.status_code}")
print(f"Get a token from {GITHUB_NEW_TOKEN_URL} with 'Read-Only' privilege on Issues for the {args.repository} repository")
print(
f"Get a token from {GITHUB_NEW_TOKEN_URL} with 'Read-Only' privilege on Issues for the {args.repository} repository"
)
return req.status_code == 200
if __name__ == "__main__":
parser = argparse.ArgumentParser(usage = __usage__, description = __desc__, prog = __file__)
parser.add_argument("--debug", action="store_true", default=DEBUG,
help="Enable debug output")
parser.add_argument("-r", "--repository", type=str, default=REPOSITORY,
help="Specify the repository (default: '%(default)s')")
parser.add_argument("-t", "--token", dest="token", type=str, metavar="TOKEN",
default=GITHUB_TOKEN, help="Specify the Github token to use (requires `repo` scope)")
parser.add_argument("-o", "--output-file", type=argparse.FileType('w', encoding='UTF-8'), default=open(str(OUTPUT_FILE.absolute()), 'w'),
metavar="/path/to/output_file.md", help=f"Specify the output file (default: '{OUTPUT_FILE}')")
parser.add_argument("--version", type=str, default=datetime.date.today().strftime("%Y.%m"),
help="Specify the version number (default: '%(default)s')")
parser.add_argument("--codename", type=str, default=shell("random-word").title(),
help="Specify the version codename (default: '%(default)s')")
parser.add_argument("--push-release", action="store_true", default=False,
help="Create the new tag and publish the release on Github")
parser = argparse.ArgumentParser(
usage=__usage__, description=__desc__, prog=__file__
)
parser.add_argument(
"--debug", action="store_true", default=DEBUG, help="Enable debug output"
)
parser.add_argument(
"-r",
"--repository",
type=str,
default=REPOSITORY,
help="Specify the repository (default: '%(default)s')",
)
parser.add_argument(
"-t",
"--token",
dest="token",
type=str,
metavar="TOKEN",
default=GITHUB_TOKEN,
help="Specify the Github token to use (requires `repo` scope)",
)
parser.add_argument(
"-o",
"--output-file",
type=pathlib.Path,
default=OUTPUT_FILE.absolute(),
metavar="/path/to/output_file.md",
help=f"Specify the output file (default: '{OUTPUT_FILE}')",
)
parser.add_argument(
"--version",
type=str,
default=datetime.date.today().strftime("%Y.%m"),
help="Specify the version number (default: '%(default)s')",
)
parser.add_argument(
"--codename",
type=str,
default="GENERATE_ME",
help="Specify the version codename (default: '%(default)s')",
)
parser.add_argument(
"--push-release",
action="store_true",
default=False,
help="Create the new tag and publish the release on Github",
)
args = parser.parse_args()
DEBUG = args.debug
if args.codename == "GENERATE_ME":
args.codename = shell("random-word").title()
if not test_token(args):
dbg(f"The GITHUB_TOKEN is not valid")
dbg("The GITHUB_TOKEN is not valid")
exit(1)
generate_changelog(args)
+5 -4
View File
@@ -19,15 +19,16 @@ class RemoteDebugService(rpyc.Service):
def exposed_eval(self, cmd):
return eval(cmd)
exposed_gdb = gdb
exposed_gdb = gdb # noqa: F821
exposed_gef = gef
exposed_gef = gef # noqa: F821
def start_rpyc_service(port: int = RPYC_PORT):
logging.info(f"RPYC service listening on tcp/{port}")
def start_rpyc_service(port: int = RPYC_PORT, bind_host: str = "127.0.0.1"):
logging.info(f"RPYC service listening on {bind_host}:tcp/{port}")
svc = rpyc.utils.server.OneShotServer(
RemoteDebugService,
hostname=bind_host,
port=port,
protocol_config={
"allow_public_attrs": True,
-1
View File
@@ -2,7 +2,6 @@
test module for deprecated functions
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import WARNING_DEPRECATION_MESSAGE
-1
View File
@@ -2,7 +2,6 @@
`gef.arch` test module.
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
+19 -20
View File
@@ -2,14 +2,16 @@
`gef.heap` test module.
"""
import pytest
import random
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ARCH, debug_target, is_64b
TCACHE_BINS = 64
class GefHeapApi(RemoteGefUnitTestGeneric):
"""`gef.heap` test module."""
@@ -17,24 +19,25 @@ class GefHeapApi(RemoteGefUnitTestGeneric):
self._target = debug_target("heap")
return super().setUp()
# from https://elixir.bootlin.com/glibc/latest/source/malloc/malloc.c#L326
# With rounding and alignment, the bins are...
# idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit)
# idx 1 bytes 25..40 or 13..20
# idx 2 bytes 41..56 or 21..28
# etc.
# from https://elixir.bootlin.com/glibc/latest/source/malloc/malloc.c#L326
# With rounding and alignment, the bins are...
# idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit)
# idx 1 bytes 25..40 or 13..20
# idx 2 bytes 41..56 or 21..28
# etc.
# fmt: off
valid_sizes_32b = [16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120,
128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216,
224, 232, 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320,
328, 336, 344, 352, 360, 368, 376, 384, 392, 400, 408, 416, 424,
432, 440, 448, 456, 464, 472, 480, 488, 496, 504, 512, 520, ]
128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216,
224, 232, 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320,
328, 336, 344, 352, 360, 368, 376, 384, 392, 400, 408, 416, 424,
432, 440, 448, 456, 464, 472, 480, 488, 496, 504, 512, 520, ]
valid_sizes_64b = [32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240,
256, 272, 288, 304, 320, 336, 352, 368, 384, 400, 416, 432, 448,
464, 480, 496, 512, 528, 544, 560, 576, 592, 608, 624, 640, 656,
672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848, 864,
880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1040]
256, 272, 288, 304, 320, 336, 352, 368, 384, 400, 416, 432, 448,
464, 480, 496, 512, 528, 544, 560, 576, 592, 608, 624, 640, 656,
672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848, 864,
880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1040]
# fmt: on
@property
def valid_sizes(self):
@@ -42,7 +45,6 @@ class GefHeapApi(RemoteGefUnitTestGeneric):
return self.valid_sizes_64b
return self.valid_sizes_32b
def test_func_gef_heap_tidx2size(self):
gdb, gef = self._gdb, self._gef
gdb.execute("run")
@@ -51,7 +53,6 @@ class GefHeapApi(RemoteGefUnitTestGeneric):
size = gef.heap.tidx2size(idx)
assert size in self.valid_sizes, f"idx={idx}"
def test_func_gef_heap_csize2tidx(self):
gdb, gef = self._gdb, self._gef
gdb.execute("run")
@@ -60,7 +61,6 @@ class GefHeapApi(RemoteGefUnitTestGeneric):
idx = gef.heap.csize2tidx(size)
assert idx in range(TCACHE_BINS), f"size={size}"
@pytest.mark.skipif(ARCH not in ("x86_64",), reason=f"Skipped for {ARCH}")
def test_func_gef_heap_malloc_align_address(self):
gdb, gef = self._gdb, self._gef
@@ -76,7 +76,6 @@ class GefHeapApi(RemoteGefUnitTestGeneric):
res = gef.heap.malloc_align_address(x)
assert res == y
def test_class_glibcarena_main_arena(self):
gdb, gef = self._gdb, self._gef
gdb.execute("run")
+18 -9
View File
@@ -74,7 +74,7 @@ class GefMemoryApi(RemoteGefUnitTestGeneric):
if self.gdb_version < (11, 0):
# expect an exception
with pytest.raises(AttributeError):
next(root.eval("gef.memory.parse_gdb_info_proc_maps()") )
next(root.eval("gef.memory.parse_gdb_info_proc_maps()"))
else:
sections = list(root.eval("gef.memory.parse_gdb_info_proc_maps()"))
@@ -137,7 +137,9 @@ class GefMemoryApi(RemoteGefUnitTestGeneric):
sections = gef.memory.maps
assert len(sections) > 0
@pytest.mark.skipif(ARCH == "aarch64" and IN_GITHUB_ACTIONS, reason=f"Skipped for {ARCH} on CI")
@pytest.mark.skipif(
ARCH == "aarch64" and IN_GITHUB_ACTIONS, reason=f"Skipped for {ARCH} on CI"
)
def test_func_parse_maps_remote_qemu(self):
gdb, gef = self._gdb, self._gef
# When in a gef-remote qemu-user session `parse_gdb_info_proc_maps`
@@ -153,7 +155,9 @@ class GefMemoryApi(RemoteGefUnitTestGeneric):
sections = gef.memory.maps
assert len(sections) > 0
@pytest.mark.skipif(ARCH == "aarch64" and IN_GITHUB_ACTIONS, reason=f"Skipped for {ARCH}")
@pytest.mark.skipif(
ARCH == "aarch64" and IN_GITHUB_ACTIONS, reason=f"Skipped for {ARCH}"
)
def test_func_parse_maps_realpath(self):
gef, gdb = self._gef, self._gdb
# When in a gef-remote session `parse_gdb_info_proc_maps` should work to
@@ -176,8 +180,11 @@ class GefMemoryApi(RemoteGefUnitTestGeneric):
# probably corrected the path to account for gdb bug #23764
#
for section in sections:
if(section.is_executable() and section.path.startswith("/usr") and
"/usr" not in section.realpath):
if (
section.is_executable()
and section.path.startswith("/usr")
and "/usr" not in section.realpath
):
assert pathlib.Path(section.realpath).is_file()
break
@@ -188,9 +195,11 @@ class GefMemoryApi(RemoteGefUnitTestGeneric):
gdb.execute("start")
section = gef.memory.maps[0]
oob_val = gef.memory.read_cstring(section.page_start, section.page_end -
section.page_start + 0x100)
val = gef.memory.read_cstring(section.page_start, section.page_end -
section.page_start)
oob_val = gef.memory.read_cstring(
section.page_start, section.page_end - section.page_start + 0x100
)
val = gef.memory.read_cstring(
section.page_start, section.page_end - section.page_start
)
assert val == oob_val
+3 -3
View File
@@ -52,8 +52,8 @@ class RemoteGefUnitTestGeneric(unittest.TestCase):
if not hasattr(self, "_target"):
setattr(self, "_target", debug_target("default"))
else:
assert isinstance(self._target, pathlib.Path) # type: ignore pylint: disable=E1101
assert self._target.exists() # type: ignore pylint: disable=E1101
assert isinstance(self._target, pathlib.Path)
assert self._target.exists()
#
# Select a random tcp port for rpyc
@@ -90,7 +90,7 @@ pi start_rpyc_service({self._port})
"-ex",
f"source {self._initfile.name}",
"--",
str(self._target.absolute()), # type: ignore pylint: disable=E1101
str(self._target.absolute()),
]
self._process = subprocess.Popen(self._command)
assert self._process.pid > 0
-1
View File
@@ -28,7 +28,6 @@ class ArchCommand(RemoteGefUnitTestGeneric):
assert " Architecture(X86, 32, LITTLE_ENDIAN)" in res
assert " The architecture has been set manually" in res
gdb.execute("arch set ppc")
res = gdb.execute("arch get", to_string=True)
-1
View File
@@ -2,7 +2,6 @@
`aslr` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
+13 -4
View File
@@ -2,10 +2,17 @@
`canary` command test module
"""
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE, debug_target, p64, p32, is_64b, u32
from tests.utils import (
ERROR_INACTIVE_SESSION_MESSAGE,
debug_target,
p64,
p32,
is_64b,
u32,
)
from tests.base import RemoteGefUnitTestGeneric
class CanaryCommand(RemoteGefUnitTestGeneric):
"""`canary` command test module"""
@@ -14,7 +21,9 @@ class CanaryCommand(RemoteGefUnitTestGeneric):
return super().setUp()
def test_cmd_canary(self):
assert ERROR_INACTIVE_SESSION_MESSAGE == self._gdb.execute("canary", to_string=True)
assert ERROR_INACTIVE_SESSION_MESSAGE == self._gdb.execute(
"canary", to_string=True
)
self._gdb.execute("start")
res = self._gdb.execute("canary", to_string=True)
assert "The canary of process" in res
@@ -30,4 +39,4 @@ class CanaryCommand(RemoteGefUnitTestGeneric):
else:
gef.memory.write(canary_address, p32(0xDEADBEEF))
res = u32(gef.memory.read(canary_address, gef.arch.ptrsize))
assert 0xdeadbeef == res
assert 0xDEADBEEF == res
+3 -3
View File
@@ -18,7 +18,7 @@ class ChecksecCommandNoCanary(RemoteGefUnitTestGeneric):
gef = self._gef
res = gdb.execute("checksec", to_string=True)
assert "Canary : ✘" in res
assert gef.binary.checksec["Canary"] == False
assert not gef.binary.checksec["Canary"]
class ChecksecCommandNoNx(RemoteGefUnitTestGeneric):
@@ -31,7 +31,7 @@ class ChecksecCommandNoNx(RemoteGefUnitTestGeneric):
gef = self._gef
res = gdb.execute("checksec", to_string=True)
assert "NX : ✘" in res
assert gef.binary.checksec["NX"] == False
assert not gef.binary.checksec["NX"]
class ChecksecCommandNoPie(RemoteGefUnitTestGeneric):
@@ -44,4 +44,4 @@ class ChecksecCommandNoPie(RemoteGefUnitTestGeneric):
gef = self._gef
res = gdb.execute("checksec", to_string=True)
assert "PIE : ✘" in res
assert gef.binary.checksec["PIE"] == False
assert not gef.binary.checksec["PIE"]
+8 -5
View File
@@ -2,17 +2,14 @@
`context` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
class ContextCommand(RemoteGefUnitTestGeneric):
"""`context` command test module"""
cmd = "context"
# TODO See https://github.com/hugsy/gef/projects/10
def test_duplicate_pane_name(self):
@@ -25,12 +22,18 @@ class ContextCommand(RemoteGefUnitTestGeneric):
current_layout = gef.config["context.layout"]
assert not current_layout.endswith(new_pane_id)
res = gdb.execute(f"pi register_external_context_pane('{new_pane_id}', print, print, None)", to_string=True)
res = gdb.execute(
f"pi register_external_context_pane('{new_pane_id}', print, print, None)",
to_string=True,
)
assert "Python Exception" not in res
new_layout = gef.config["context.layout"]
assert new_layout.endswith(new_pane_id)
res = gdb.execute(f"pi register_external_context_pane('{new_pane_id}', print, print, None)", to_string=True)
res = gdb.execute(
f"pi register_external_context_pane('{new_pane_id}', print, print, None)",
to_string=True,
)
assert "Python Exception" not in res
new_layout2 = gef.config["context.layout"]
assert new_layout == new_layout2
+1 -2
View File
@@ -2,11 +2,10 @@
`edit-flags` command test module
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ARCH, ERROR_INACTIVE_SESSION_MESSAGE
from tests.utils import ARCH
@pytest.mark.skipif(ARCH not in ("i686", "x86_64"), reason=f"Skipped for {ARCH}")
-2
View File
@@ -2,14 +2,12 @@
elf-info command test module
"""
from tests.base import RemoteGefUnitTestGeneric
class ElfInfoCommand(RemoteGefUnitTestGeneric):
"""`elf-info` command test module"""
def test_cmd_elf_info(self):
gdb = self._gdb
res = gdb.execute("elf-info", to_string=True)
-1
View File
@@ -2,7 +2,6 @@
`entry-break` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
+1 -4
View File
@@ -2,7 +2,6 @@
`format-string_helper` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import debug_target
@@ -19,9 +18,7 @@ class FormatStringHelperCommand(RemoteGefUnitTestGeneric):
gdb.execute("set args testtest")
res = gdb.execute("format-string-helper", to_string=True)
assert res.endswith(
"[+] Enabled 5 FormatString breakpoints\n"
)
assert res.endswith("[+] Enabled 5 FormatString breakpoints\n")
res = gdb.execute("run", to_string=True)
assert "Possible insecure format string:" in res
-1
View File
@@ -2,7 +2,6 @@
`functions` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
+6 -2
View File
@@ -36,7 +36,9 @@ class GefRemoteCommand(RemoteGefUnitTestGeneric):
with gdbserver_session(port=port):
gdb.execute(f"gef-remote {GDBSERVER_DEFAULT_HOST} {port}")
res: str = root.eval("str(gef.session.remote)")
assert res.startswith(f"RemoteSession(target='{GDBSERVER_DEFAULT_HOST}:{port}', local='/tmp/")
assert res.startswith(
f"RemoteSession(target='{GDBSERVER_DEFAULT_HOST}:{port}', local='/tmp/"
)
assert res.endswith(f"pid={gef.session.pid}, mode={gdbserver_mode})")
@pytest.mark.slow
@@ -55,7 +57,9 @@ class GefRemoteCommand(RemoteGefUnitTestGeneric):
cmd = f"gef-remote --qemu-user --qemu-binary {self._target} {GDBSERVER_DEFAULT_HOST} {port}"
gdb.execute(cmd)
res = root.eval("str(gef.session.remote)")
assert res.startswith(f"RemoteSession(target='{GDBSERVER_DEFAULT_HOST}:{port}', local='/tmp/")
assert res.startswith(
f"RemoteSession(target='{GDBSERVER_DEFAULT_HOST}:{port}', local='/tmp/"
)
assert res.endswith(f"pid={gef.session.pid}, mode={qemu_mode})")
def test_cmd_target_remote(self):
+5 -4
View File
@@ -21,11 +21,12 @@ class GotCommand(RemoteGefUnitTestGeneric):
self._target = debug_target("format-string-helper")
return super().setUp()
def test_cmd_got(self):
gdb = self._gdb
self.assertEqual(ERROR_INACTIVE_SESSION_MESSAGE,gdb.execute("got", to_string=True))
self.assertEqual(
ERROR_INACTIVE_SESSION_MESSAGE, gdb.execute("got", to_string=True)
)
gdb.execute("start")
res = gdb.execute("got", to_string=True)
@@ -41,12 +42,12 @@ class GotCommand(RemoteGefUnitTestGeneric):
if not lines:
return None
if "format-string-helper.out" in lines[0]:
res = ''.join(lines)
res = "".join(lines)
self.assertIn(" printf", res)
self.assertNotIn(" strcpy", res)
return "format-string-helper.out"
if "/libc" in lines[0]:
res = ''.join(lines)
res = "".join(lines)
self.assertNotIn(" printf", res)
self.assertNotIn(" strcpy", res)
return "libc"
+9 -2
View File
@@ -187,7 +187,14 @@ class HeapCommandNonMain(RemoteGefUnitTestGeneric):
res = gdb.execute(cmd, to_string=True)
self.assertIn("size=0x20", res)
@pytest.mark.skipif(ARCH not in ("i686", "x86_64",), reason=f"Skipped for {ARCH}")
@pytest.mark.skipif(
ARCH
not in (
"i686",
"x86_64",
),
reason=f"Skipped for {ARCH}",
)
@pytest.mark.skipif(is_glibc_ge(2, 42), reason="Skipped for glibc >= 2.42")
def test_cmd_heap_bins_tcache(self):
gdb = self._gdb
@@ -238,7 +245,7 @@ class HeapCommandClass(RemoteGefUnitTestGeneric):
assert len(lines) > 0
self.assertEqual("== Chunk distribution by size ==", lines[0])
self.assertIn("== Chunk distribution by flag ==", lines)
assert any( map(lambda x: "B<TraitA, TraitB>" in x, lines))
assert any(map(lambda x: "B<TraitA, TraitB>" in x, lines))
class HeapCommandFastBins(RemoteGefUnitTestGeneric):
-1
View File
@@ -2,7 +2,6 @@
`heap-analysis` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE, debug_target
+7 -7
View File
@@ -2,7 +2,6 @@
`hexdump` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
@@ -10,13 +9,14 @@ from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
class HexdumpCommand(RemoteGefUnitTestGeneric):
"""`hexdump` command test module"""
def test_cmd_hexdump(self):
gdb = self._gdb
self.assertEqual(ERROR_INACTIVE_SESSION_MESSAGE,gdb.execute("hexdump $pc", to_string=True))
self.assertEqual(
ERROR_INACTIVE_SESSION_MESSAGE, gdb.execute("hexdump $pc", to_string=True)
)
gdb.execute("start")
res = gdb.execute("hexdump qword $pc", to_string=True)
res = gdb.execute("hexdump dword $pc -s 1", to_string=True)
res = gdb.execute("hexdump word $pc -s 5 -r", to_string=True)
res = gdb.execute("hexdump byte $sp -s 32", to_string=True)
gdb.execute("hexdump qword $pc", to_string=True)
gdb.execute("hexdump dword $pc -s 1", to_string=True)
gdb.execute("hexdump word $pc -s 5 -r", to_string=True)
gdb.execute("hexdump byte $sp -s 32", to_string=True)
-1
View File
@@ -2,7 +2,6 @@
`highlight` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import Color
+1 -4
View File
@@ -2,17 +2,14 @@
`hijack_fd` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
class HijackFdCommand(RemoteGefUnitTestGeneric):
"""`hijack-fd` command test module"""
cmd = "hijack-fd"
def test_cmd_hijack_fd(self):
gdb = self._gdb
res = gdb.execute(f"{self.cmd}", to_string=True)
gdb.execute(f"{self.cmd}", to_string=True)
+1 -1
View File
@@ -88,4 +88,4 @@ class MemoryCommand(RemoteGefUnitTestGeneric):
ERROR_INACTIVE_SESSION_MESSAGE, gdb.execute("memory reset", to_string=True)
)
gdb.execute("start")
res = gdb.execute("memory reset", to_string=True)
gdb.execute("memory reset", to_string=True)
-1
View File
@@ -2,7 +2,6 @@
`name-break` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
+10 -7
View File
@@ -171,10 +171,13 @@ class NopCommand(RemoteGefUnitTestGeneric):
gef = self._gef
gdb.execute("start")
gef.memory.write(gef.arch.pc, p16(0x9191))
res = gdb.execute(
f"{self.cmd} --b",
to_string=True,
) or ""
res = (
gdb.execute(
f"{self.cmd} --b",
to_string=True,
)
or ""
)
assert res
mem = u16(gef.memory.read(gef.arch.pc, 2))
self.assertEqual(0x9190, mem)
@@ -199,7 +202,7 @@ class NopCommand(RemoteGefUnitTestGeneric):
res = gdb.execute(f"{self.cmd} --b --f", to_string=True)
mem = u16(gef.memory.read(gef.arch.pc, 2))
self.assertIn(r"will result in LAST-INSTRUCTION", res)
self.assertEqual(0xfe90, mem)
self.assertEqual(0xFE90, mem)
@pytest.mark.skipif(ARCH not in ("i686", "x86_64"), reason=f"Skipped for {ARCH}")
def test_cmd_nop_bytes_arg(self):
@@ -247,7 +250,7 @@ class NopCommandMmapKnownAddress(RemoteGefUnitTestGeneric):
def test_cmd_nop_invalid_end_address(self):
gdb = self._gdb
gdb.execute("run")
res = gdb.execute(f"nop --i 5 0x1337000+0x1000-4", to_string=True)
res = gdb.execute("nop --i 5 0x1337000+0x1000-4", to_string=True)
self.assertIn("reaching unmapped area", res)
@pytest.mark.skipif(ARCH not in ("i686", "x86_64"), reason=f"Skipped for {ARCH}")
@@ -256,7 +259,7 @@ class NopCommandMmapKnownAddress(RemoteGefUnitTestGeneric):
gef = self._gef
# Make sure we error out if writing nops into an unmapped or RO area
gdb.execute("run")
res = gdb.execute(f"nop --b --i 5 0x1337000+0x1000-4", to_string=True)
res = gdb.execute("nop --b --i 5 0x1337000+0x1000-4", to_string=True)
self.assertIn(
"Cannot patch instruction at 0x1337ffc: reaching unmapped area", res
)
-1
View File
@@ -2,7 +2,6 @@
patch command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE, debug_target, u16, u32, u64, u8
+2 -1
View File
@@ -1,6 +1,7 @@
"""
Pattern commands test module
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
@@ -91,4 +92,4 @@ class PatternCommand(RemoteGefUnitTestGeneric):
gdb.execute("set args aaaabaaacaaadaaaeaaafaaagaaahaaa")
gdb.execute("run")
res = gdb.execute(cmd, to_string=True)
self.assertIn(f"not found", res)
self.assertIn("not found", res)
+11 -7
View File
@@ -45,7 +45,7 @@ class PcustomCommand(RemoteGefUnitTestGeneric):
#
gdb.execute(f"gef config pcustom.struct_path {dirpath}")
res = gdb.execute("gef config pcustom.struct_path", to_string=True)
self.assertIn(f'pcustom.struct_path (Path) = {dirpath}', res)
self.assertIn(f"pcustom.struct_path (Path) = {dirpath}", res)
#
# List the structures in the files inside dirpath
@@ -59,8 +59,12 @@ class PcustomCommand(RemoteGefUnitTestGeneric):
#
gdb.execute("run")
bad_struct_name = "meh_t"
res = gdb.execute(f"pcustom {bad_struct_name} 0x1337100", to_string=True).strip()
self.assertEqual(f"[!] No structure named '{bad_struct_name}' found", res)
res = gdb.execute(
f"pcustom {bad_struct_name} 0x1337100", to_string=True
).strip()
self.assertEqual(
f"[!] No structure named '{bad_struct_name}' found", res
)
print(res)
def test_cmd_pcustom_show(self):
@@ -102,13 +106,13 @@ class PcustomCommand(RemoteGefUnitTestGeneric):
res = gdb.execute("pcustom goo_t 0x1337100", to_string=True)
if is_64b():
self.assertIn(
f"""0x1337100+0x00 a : 3 (c_int)
"""0x1337100+0x00 a : 3 (c_int)
0x1337100+0x04 b : 4 (c_int)
0x1337100+0x08 c : """,
res,
)
self.assertIn(
f""" 0x1337000+0x00 a : 1 (c_int)
""" 0x1337000+0x00 a : 1 (c_int)
0x1337000+0x04 b : 2 (c_int)
0x1337100+0x10 d : 12 (c_int)
0x1337100+0x14 e : 13 (c_int)""",
@@ -116,13 +120,13 @@ class PcustomCommand(RemoteGefUnitTestGeneric):
)
else:
self.assertIn(
f"""0x1337100+0x00 a : 3 (c_long)
"""0x1337100+0x00 a : 3 (c_long)
0x1337100+0x04 b : 4 (c_long)
0x1337100+0x08 c : """,
res,
)
self.assertIn(
f""" 0x1337000+0x00 a : 1 (c_long)
""" 0x1337000+0x00 a : 1 (c_long)
0x1337000+0x04 b : 2 (c_long)
0x1337100+0x0c d : 12 (c_long)
0x1337100+0x10 e : 13 (c_long)""",
+1 -4
View File
@@ -44,10 +44,7 @@ class PieCommand(RemoteGefUnitTestGeneric):
gdb = self._gdb
# breakpoint at a random instruction and run
gdb.execute(f"pie breakpoint {self.pie_offset}")
res = gdb.execute(
"pie run",
to_string=True
)
res = gdb.execute("pie run", to_string=True)
# check we stopped for a breakpoint
res = removeuntil('Name: "default.out", stopped ', res).splitlines()[0]
self.assertIn("in main (), reason: BREAKPOINT", res)
+3 -2
View File
@@ -2,7 +2,6 @@
print-format command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE, p32
@@ -41,7 +40,9 @@ class PrintFormatCommand(RemoteGefUnitTestGeneric):
gef.memory.write(gef.arch.sp, p32(0x41414141))
res = gdb.execute("print-format --lang bytearray -l 4 $sp", to_string=True).strip()
res = gdb.execute(
"print-format --lang bytearray -l 4 $sp", to_string=True
).strip()
gef_var = res.split("$_gef")[1].split("'")[0]
self.assertEqual(f"Saved data b'AAAA'... in '$_gef{gef_var}'", res)
+1 -4
View File
@@ -2,7 +2,6 @@
`process-search` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import debug_target
@@ -28,9 +27,7 @@ class ProcessSearchCommand(RemoteGefUnitTestGeneric):
lines = gdb.execute("process-search gdb.*fakefake", to_string=True).splitlines()
self.assertEqual(len(lines), 0)
lines = gdb.execute(
f"process-search gdb.*", to_string=True
).splitlines()
lines = gdb.execute("process-search gdb.*", to_string=True).splitlines()
self.assertGreaterEqual(len(lines), 1)
def test_cmd_process_search_smartscan(self):
-1
View File
@@ -2,7 +2,6 @@
`process-status` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
-1
View File
@@ -2,7 +2,6 @@
`registers` command test module
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
-2
View File
@@ -2,14 +2,12 @@
`reset-cache` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
class ResetCacheCommand(RemoteGefUnitTestGeneric):
"""`reset-cache` command test module"""
def test_cmd_reset_cache(self):
gdb = self._gdb
gdb.execute("start")
+11 -2
View File
@@ -5,7 +5,13 @@ scan command test module
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ARCH, ERROR_INACTIVE_SESSION_MESSAGE, IN_GITHUB_ACTIONS, debug_target, is_glibc_ge
from tests.utils import (
ARCH,
ERROR_INACTIVE_SESSION_MESSAGE,
IN_GITHUB_ACTIONS,
debug_target,
is_glibc_ge,
)
class ScanCommand(RemoteGefUnitTestGeneric):
@@ -15,7 +21,10 @@ class ScanCommand(RemoteGefUnitTestGeneric):
self._target = debug_target("default")
return super().setUp()
@pytest.mark.skipif(ARCH == "aarch64" and IN_GITHUB_ACTIONS and is_glibc_ge(2, 41), reason=f"Skipped for {ARCH} on CI with glibc >= 2.41")
@pytest.mark.skipif(
ARCH == "aarch64" and IN_GITHUB_ACTIONS and is_glibc_ge(2, 41),
reason=f"Skipped for {ARCH} on CI with glibc >= 2.41",
)
def test_cmd_scan(self):
gdb = self._gdb
cmd = "scan libc stack"
+2 -3
View File
@@ -2,7 +2,6 @@
search_pattern command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import BIN_SH, ERROR_INACTIVE_SESSION_MESSAGE
@@ -26,7 +25,7 @@ class SearchPatternCommand(RemoteGefUnitTestGeneric):
gdb.execute("set {char[6]} $sp = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x00 }")
res = gdb.execute(
r"search-pattern --regex $sp $sp+7 ([\\x20-\\x7E]{2,})(?=\\x00)",
to_string=True
to_string=True,
)
self.assertTrue(r"b'ABCDE'" in res)
@@ -34,6 +33,6 @@ class SearchPatternCommand(RemoteGefUnitTestGeneric):
gdb.execute("set {char[6]} $sp = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x03 }")
res = gdb.execute(
r"search-pattern --regex $sp $sp+7 ([\\x20-\\x7E]{2,})(?=\\x00)",
to_string=True
to_string=True,
)
self.assertNotIn(r"b'ABCDE'", res)
-43
View File
@@ -1,43 +0,0 @@
"""
Shellcode commands test module
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import BIN_SH
class ShellcodeCommand(RemoteGefUnitTestGeneric):
"""`shellcode` command test module"""
def test_cmd_shellcode(self):
gdb = self._gdb
gdb.execute("start")
res = gdb.execute("shellcode", to_string=True)
self.assertIn("Missing sub-command (search|get)", res)
@pytest.mark.online
@pytest.mark.slow
def test_cmd_shellcode_search(self):
gdb = self._gdb
cmd = f"shellcode search execve {BIN_SH}"
gdb.execute("start")
res = gdb.execute(cmd, to_string=True)
self.assertIn(f"setuid(0) + execve({BIN_SH}) 49 bytes", res)
@pytest.mark.online
@pytest.mark.slow
def test_cmd_shellcode_get_ok(self):
gdb = self._gdb
gdb.execute("start")
res = gdb.execute("shellcode get 77", to_string=True)
self.assertIn("Shellcode written to ", res)
@pytest.mark.online
@pytest.mark.slow
def test_cmd_shellcode_get_nok(self):
gdb = self._gdb
n = 1111111111111
gdb.execute("start")
res = gdb.execute(f"shellcode get {n}", to_string=True)
self.assertIn(f"Failed to fetch shellcode #{n}", res)
+2 -1
View File
@@ -50,7 +50,8 @@ class SkipiCommand(RemoteGefUnitTestGeneric):
gdb.execute("start")
gef.memory.write(gef.arch.pc, p64(0x9090FEEBFEEBFEEB))
res = gdb.execute(
f"{self.cmd} $pc+2 --n 2", to_string=True # from the second short jump
f"{self.cmd} $pc+2 --n 2", # from the second short jump
to_string=True,
)
assert res
mem = u16(gef.memory.read(gef.arch.pc, 2)) # read 2 bytes
+1 -3
View File
@@ -2,21 +2,19 @@
`smart_eval` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
class SmartEvalCommand(RemoteGefUnitTestGeneric):
"""`smart_eval` command test module"""
def test_cmd_smart_eval(self):
gdb = self._gdb
gef = self._gef
gdb.execute("start")
examples = (
("$ $pc+1", str(gef.arch.pc+1)),
("$ $pc+1", str(gef.arch.pc + 1)),
("$ -0x1000", "-4096"),
("$ 0x00007ffff7812000 0x00007ffff79a7000", "1658880"),
("$ 1658880", "0b110010101000000000000"),
+3 -3
View File
@@ -5,7 +5,7 @@
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ARCH, ERROR_INACTIVE_SESSION_MESSAGE, p32, p64, u16, u32
from tests.utils import ARCH, ERROR_INACTIVE_SESSION_MESSAGE, u16
class Stepover(RemoteGefUnitTestGeneric):
@@ -24,7 +24,7 @@ class Stepover(RemoteGefUnitTestGeneric):
gef = self._gef
payload = b"\xe8\x05\x00\x00\x00\x90\x90\x6a\x00\xc3\xb8\x69\x69\x69\x69\xc3"
'''
"""
call movtag <- 'stepover' execution from this point
nop <- 'stepover' should stops here and eax value should be 0x69696969
nop
@@ -33,7 +33,7 @@ class Stepover(RemoteGefUnitTestGeneric):
movtag:
mov eax, 0x69696969
ret
'''
"""
gdb.execute("start")
gef.memory.write(gef.arch.pc, payload)
-1
View File
@@ -2,7 +2,6 @@
stub command test module
"""
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
-2
View File
@@ -2,7 +2,6 @@
theme command test module
"""
from tests.base import RemoteGefUnitTestGeneric
@@ -40,6 +39,5 @@ class ThemeCommand(RemoteGefUnitTestGeneric):
v = "blue blah 10 -1 0xfff bold"
gdb.execute(f"theme {t} {v}")
res = gdb.execute("theme ___I_DONT_EXIST___", to_string=True)
self.assertIn("Invalid key", res)
-1
View File
@@ -2,7 +2,6 @@
trace-run command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import TMPDIR, ERROR_INACTIVE_SESSION_MESSAGE
-1
View File
@@ -2,7 +2,6 @@
`version` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
+3 -2
View File
@@ -2,7 +2,6 @@
vmmap command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
@@ -24,7 +23,9 @@ class VmmapCommand(RemoteGefUnitTestGeneric):
self.assertEqual(len(res.splitlines()), 9)
res = gdb.execute("vmmap $pc", to_string=True)
assert "`$pc` has no type specified. We guessed it was an address filter." in res
assert (
"`$pc` has no type specified. We guessed it was an address filter." in res
)
self.assertEqual(len(res.splitlines()), 8)
def test_cmd_vmmap_addr(self):
+1 -2
View File
@@ -2,7 +2,6 @@
`xfiles` command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
@@ -17,4 +16,4 @@ class XfilesCommand(RemoteGefUnitTestGeneric):
)
gdb.execute("start")
res = gdb.execute("xfiles", to_string=True)
self.assertGreaterEqual(len(res.splitlines()) , 3)
self.assertGreaterEqual(len(res.splitlines()), 3)
-1
View File
@@ -2,7 +2,6 @@
xinfo command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE, debug_target
+4 -4
View File
@@ -2,25 +2,25 @@
xor-memory command test module
"""
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE
class XorMemoryCommand(RemoteGefUnitTestGeneric):
"""`xor-memory` command test module"""
def test_cmd_xor_memory_display(self):
gdb = self._gdb
cmd = "xor-memory display $sp 0x10 0x41"
self.assertEqual(ERROR_INACTIVE_SESSION_MESSAGE, gdb.execute(cmd, to_string=True))
self.assertEqual(
ERROR_INACTIVE_SESSION_MESSAGE, gdb.execute(cmd, to_string=True)
)
gdb.execute("start")
res = gdb.execute(cmd, to_string=True)
assert "Original block" in res
assert "XOR-ed block" in res
def test_cmd_xor_memory_patch(self):
gdb = self._gdb
gdb.execute("start")
+6 -4
View File
@@ -37,9 +37,9 @@ class TestGefConfigUnit(RemoteGefUnitTestGeneric):
for line in lines:
parts = line.replace(GEF_RIGHT_ARROW, "").split()
opcode: str = parts[1].replace("...", "").lower()
assert (
len(opcode) <= max_opcode_len * 2
), f"Invalid length for {opcode=}: {len(opcode)}"
assert len(opcode) <= max_opcode_len * 2, (
f"Invalid length for {opcode=}: {len(opcode)}"
)
assert all(map(lambda c: c in "0123456789abcdef", opcode))
def test_config_hook_validator(self):
@@ -75,7 +75,9 @@ class TestGefConfigUnit(RemoteGefUnitTestGeneric):
gdb.execute("gef config gef.debug 0")
# debug disable -> set setting should not raise but print error
output = (gdb.execute("gef config gef.debug 'fooo'", to_string=True) or "").strip()
output = (
gdb.execute("gef config gef.debug 'fooo'", to_string=True) or ""
).strip()
assert output == "[!] Cannot parse 'fooo' as bool"
def test_config_libc_version(self):
-1
View File
@@ -2,7 +2,6 @@
GDB function test module for ELF section convenience functions
"""
import pytest
from tests.utils import ERROR_INACTIVE_SESSION_MESSAGE, debug_target, is_64b
@@ -1,5 +1,3 @@
import pytest
from tests.base import RemoteGefUnitTestGeneric
from tests.utils import debug_target
+3 -1
View File
@@ -8,7 +8,9 @@ from tests.utils import (
class RegressionGdbserverConnection(RemoteGefUnitTestGeneric):
@pytest.mark.skipif(ARCH == "aarch64" and IN_GITHUB_ACTIONS, reason=f"Skipped for {ARCH} on CI")
@pytest.mark.skipif(
ARCH == "aarch64" and IN_GITHUB_ACTIONS, reason=f"Skipped for {ARCH} on CI"
)
def test_can_establish_connection_to_gdbserver_again_after_disconnect(self):
"""Ensure that gdb can connect to a gdbserver again after disconnecting (PR #896)."""
gdb = self._gdb
@@ -74,7 +74,7 @@ class RegressionRegisterOrderNested(RemoteGefUnitTestGeneric):
lines1 = gdb.execute("registers", to_string=True).splitlines()
gdb.execute("frame 5")
lines2 = gdb.execute("registers", to_string=True).splitlines()
rips = [x for x in lines1+lines2 if x.startswith("$rip")]
rips = [x for x in lines1 + lines2 if x.startswith("$rip")]
self.assertEqual(len(rips), 2) # we must have only 2 entries
self.assertNotEqual(rips[0], rips[1]) # they must be different
self.assertIn("<f10", rips[0]) # the first one must be in the f10 frame
+1 -1
View File
@@ -1,4 +1,3 @@
pylint
pytest
pytest-cov
pytest-xdist
@@ -8,3 +7,4 @@ coverage
pre-commit
rpyc>=5
requests
ruff
+5 -3
View File
@@ -1,10 +1,10 @@
import pathlib
import unittest
import tempfile
import subprocess
import requests
import tempfile
import unittest
import pytest
import requests
from tests.utils import GEF_PATH
@@ -15,6 +15,8 @@ class GefInstallScript(unittest.TestCase):
def setUp(self):
url = "https://api.github.com/repos/hugsy/gef/tags"
res = requests.get(url)
if res.status_code == 403:
pytest.skip("API rate limit exceeded")
assert res.status_code == 200
self.latest_release = res.json()[0]["name"]
+19 -19
View File
@@ -12,7 +12,6 @@ import struct
import subprocess
import tempfile
import time
from typing import Iterable, List, Optional, Union
from urllib.request import urlopen
@@ -57,31 +56,32 @@ WARNING_DEPRECATION_MESSAGE = "is deprecated and will be removed in a feature re
IN_GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true"
class Color(enum.Enum):
"""Used to colorify terminal output."""
NORMAL = "\001\033[0m\002"
GRAY = "\001\033[1;38;5;240m\002"
LIGHT_GRAY = "\001\033[0;37m\002"
RED = "\001\033[31m\002"
GREEN = "\001\033[32m\002"
YELLOW = "\001\033[33m\002"
BLUE = "\001\033[34m\002"
PINK = "\001\033[35m\002"
CYAN = "\001\033[36m\002"
BOLD = "\001\033[1m\002"
UNDERLINE = "\001\033[4m\002"
UNDERLINE_OFF = "\001\033[24m\002"
HIGHLIGHT = "\001\033[3m\002"
HIGHLIGHT_OFF = "\001\033[23m\002"
BLINK = "\001\033[5m\002"
BLINK_OFF = "\001\033[25m\002"
NORMAL = "\001\033[0m\002"
GRAY = "\001\033[1;38;5;240m\002"
LIGHT_GRAY = "\001\033[0;37m\002"
RED = "\001\033[31m\002"
GREEN = "\001\033[32m\002"
YELLOW = "\001\033[33m\002"
BLUE = "\001\033[34m\002"
PINK = "\001\033[35m\002"
CYAN = "\001\033[36m\002"
BOLD = "\001\033[1m\002"
UNDERLINE = "\001\033[4m\002"
UNDERLINE_OFF = "\001\033[24m\002"
HIGHLIGHT = "\001\033[3m\002"
HIGHLIGHT_OFF = "\001\033[23m\002"
BLINK = "\001\033[5m\002"
BLINK_OFF = "\001\033[25m\002"
def is_glibc_ge(major, minor):
ver = platform.libc_ver()
if ver[0] == 'glibc':
(glibc_major, glibc_minor, *glibc_patch) = list(map(int, ver[1].split('.')))
if ver[0] == "glibc":
(glibc_major, glibc_minor, *_) = list(map(int, ver[1].split(".")))
return (glibc_major, glibc_minor) >= (major, minor)
return False