Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major Change #4

Merged
merged 3 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Python package

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings.
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=180 --statistics
- name: Test with pytest
run: |
pytest
16 changes: 5 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,19 @@ build-backend = "setuptools.build_meta"

[project]
name = "smalig"
version = "0.1.6"
version = "0.1.7"
description = "Smali ByteCode info (grammar) fetch tool written in Python"
authors = [
{ name = "AbhiTheModder", email = "allinoneallinone00@gmail.com" },
]
license = {file = "LICENSE"}
authors = [{ name = "AbhiTheModder", email = "allinoneallinone00@gmail.com" }]
license = { file = "LICENSE" }
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.10"
keywords = ["smali", "grammar", "parser", "android", "reverse-engineering"]
classifiers = [
"Development Status :: 4 - Beta",
"Natural Language :: English",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -29,10 +26,7 @@ classifiers = [
"Operating System :: OS Independent",
]

dependencies = [
"PyYAML",
"jsbeautifier",
]
dependencies = ["PyYAML", "jsbeautifier"]

[project.urls]
homepage = "https://github.com/RevEngiSquad/smalig"
Expand Down
6 changes: 3 additions & 3 deletions smalig/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .utils import YamlReader, InstructionFetch, cls
from .cli.app import main, app, help
from .utils import YamlReader, InstructionFetch, cls, grammar_yaml
from .cli.app import main

__all__ = ["YamlReader", "InstructionFetch", "main", "app", "help", "cls"]
__all__ = ["YamlReader", "InstructionFetch", "main", "cls", "grammar_yaml"]
59 changes: 2 additions & 57 deletions smalig/__main__.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,4 @@
import sys
from smalig import app, help, cls
from smalig import main

if __name__ == "__main__":
args = sys.argv[1:]

if "-h" in args or "--help" in args:
help()
sys.exit(0)

if "-m" in args:
exact_match = False
else:
exact_match = True

if "-o" in args:
try:
output_file = args[args.index("-o") + 1]
except IndexError:
output_file = None
else:
output_file = None

try:
if "-f" in args:
try:
file_path = args[args.index("-f") + 1]
except IndexError:
file_path = None
else:
file_path = input(f"Enter the path to the file: ")

if "-t" in args:
try:
target = args[args.index("-t") + 1]
except IndexError:
target = ""
else:
target = input(f"Enter Query: ")
cls()
except KeyboardInterrupt:
print("\nExiting...")
sys.exit(0)

if "-j" in args:
json = True
else:
if output_file and output_file.endswith(".json"):
json = True
else:
json = False

if target == "":
raise Exception("Query is empty")

if file_path == "":
raise Exception("File path is empty")

app(file_path=file_path, target=target, json=json, out=output_file, exact_match=exact_match)
main()
147 changes: 69 additions & 78 deletions smalig/cli/app.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,22 @@
import sys
import argparse
import json as js
import jsbeautifier
import importlib.resources
import textwrap

from smalig import YamlReader, InstructionFetch, cls
from smalig import YamlReader, InstructionFetch, cls, grammar_yaml


def help() -> None:
help_message = """
smalig: Smali ByteCode info (grammar) fetch tool

Usage: smalig [-t TARGET [-j] [-o OUTPUT_FILE]

Options:
-t TARGET Specify the Smali instruction to fetch. If omitted,
prompts the user for input.
-j Output the result as JSON. If -o is also specified and the
OUTPUT_FILE ends in '.json', this flag is automatically set.
-o OUTPUT_FILE Write the output to the specified file. If omitted, prints to console.

Examples:
smalig -t "const-string" # Fetch information for the 'const-string' instruction.
smalig -t "invoke-virtual" -j -o output.json # Fetch and save as JSON
smalig -o my_output.txt # Prompts for instruction then saves to my_output.txt


If no target is specified using -t, the tool will prompt for input.

If no -o flag is used, the output goes to stdout. If a file is specified without a .json extension, plain text output is generated.
"""
print(textwrap.dedent(help_message))
EXAMPLES = """
examples:
smalig # Prompts for instruction then fetch it's information.
smalig -m # Prompts for instruction then fetch it's information with fuzzy match.
smalig -t "move" # Fetch information for the 'move' instruction.
smalig -t "move" -j # Output as JSON
smalig -t "invoke-virtual" -j -o output.json # Fetch and save as JSON
smalig -o my_output.txt # Prompts for instruction then saves to my_output.txt
smalig -t "move" -m # Fuzzy match
smalig -t "move" -o my_output.json # Save as JSON
smalig -t "move" -o my_output.txt # Save as plain text
"""


def app(file_path, target, json, out, exact_match) -> None:
Expand Down Expand Up @@ -74,60 +60,65 @@ def app(file_path, target, json, out, exact_match) -> None:
return


def main() -> None:
"""
Main function
"""
args = sys.argv[1:]

if "-h" in args or "--help" in args:
help()
return

if "-m" in args:
exact_match = False
else:
exact_match = True

if "-o" in args:
try:
output_file = args[args.index("-o") + 1]
except IndexError:
output_file = None
def parse_args():
parser = argparse.ArgumentParser(
prog="smalig",
description="Smali ByteCode info (grammar) fetch tool",
epilog=EXAMPLES,
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument("-m", action="store_true", help="Enable fuzzy match")
parser.add_argument(
"-o",
metavar="OUTPUT_FILE",
help="Specify output file. If omitted, prints to console.",
)
parser.add_argument(
"-t",
metavar="TARGET",
help="Specify the Smali instruction to fetch. If omitted, prompts the user for input.",
)
parser.add_argument(
"-j",
action="store_true",
help="Enable JSON output. If omitted and OUTPUT_FILE ends in '.json', this flag is automatically set.",
)
return parser.parse_args()


def get_target(args):
if args.t:
return args.t
else:
output_file = None
target = input("Search instruction: ")
cls()
return target

with importlib.resources.path("smalig", "grammar.yaml") as file_path:
file_path = str(file_path)

if "-t" in args:
try:
target = args[args.index("-t") + 1]
except IndexError:
target = ""
else:
try:
target = input(f"Enter Query: ")
cls()
except KeyboardInterrupt:
print("\nExiting...")
return

if "-j" in args:
json = True
def get_json(args, output_file):
if args.j:
return True
elif output_file and output_file.endswith(".json"):
return True
else:
if output_file and output_file.endswith(".json"):
json = True
else:
json = False

if target == "":
raise Exception("Query is empty")

if file_path == "":
raise Exception("File path is empty")

app(file_path=file_path, target=target, json=json, out=output_file, exact_match=exact_match)
return False


def main():
args = parse_args()
file_path = grammar_yaml()
target = get_target(args)
if not target:
exit("Query is empty!")
json_output = get_json(args, args.o)

app(
file_path=file_path,
target=target,
json=json_output,
out=args.o,
exact_match=not args.m,
)


if __name__ == "__main__":
Expand Down
48 changes: 48 additions & 0 deletions smalig/grammar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,54 @@
example: "1500 2041 - const/high16 v0, 0x41200000 (#float 10.0)"
example_disc: "Moves the floating literal value 0x41200000(10.0) into v0. The 16 bit literal in the instruction carries the top 16 bits of the floating point number."

- opcode: "16"
name: "const-wide/16"
format: "AA|op BBBB"
format_id: "21s"
syntax: "const-wide/16 vAA, #+BBBB"
args_info: "A: destination register (8 bits), B: signed int (16 bits)"
short_desc: "Move the given literal value (sign-extended to 64 bits) into the specified register-pair."
long_desc: "Moves the literal value BBBB into register-pair (vAA, vAA+1), expanding the integer constant into a long constant. BBBB is sign-extended to 64 bits. The value of BBBB is in the range -32768 to 32767 (-0x8000 to 0x7FFF)."
note: ""
example: "1600 0A00 - const-wide/16 v0, 0xa (#long 10.0)"
example_disc: "Moves the long literal value 0xa(10) into (v0,v1) register-pair."

- opcode: "17"
name: "const-wide/32"
format: "AA|op BBBBlo"
format_id: "31i"
syntax: "const-wide/32 vAA, #+BBBBBBBB"
args_info: "A: destination register (8 bits), B: signed int (32 bits)"
short_desc: "Move the given literal value (sign-extended to 64 bits) into the specified register-pair."
long_desc: "Moves the literal value BBBBBBBB into register-pair (vAA, vAA+1), expanding the integer constant into a long constant. BBBBBBBB is sign-extended to 64 bits. The value of BBBBBBBB is in the range -2147483648 to 2147483647 (-0x80000000 to 0x7FFFFFFF)."
note: ""
example: "1702 4E61 BC00 - const-wide/32 v2, 0x00bc614e"
example_disc: "Moves the long literal value 0x00bc614e into (v2,v3) register-pair."

- opcode: "18"
name: "const-wide"
format: "AA|op BBBBlo BBBB BBBB BBBBhi"
format_id: "51l"
syntax: "const-wide vAA, #+BBBBBBBBBBBBBBBB"
args_info: "A: destination register (8 bits), B: signed int (64 bits)"
short_desc: "Move the given literal value into the specified register-pair."
long_desc: "Moves the literal value constant BBBBBBBBBBBBBBBB into register-pair (vAA, vAA+1). The value of BBBBBBBBBBBBBBBB is in the range -9223372036854775808 to 9223372036854775807 (-0x8000000000000000 to 0x7FFFFFFFFFFFFFFF)."
note: ""
example: "1802 874b 6b5d 54dc 2b00- const-wide v2, 0x002bdc545d6b4b87 (#long 12345678901234567)"
example_disc: "Moves the long literal value 0x002bdc545d6b4b87 into (v2,v3) register-pair."

- opcode: "19"
name: "const-wide/high16"
format: "AA|op BBBB"
format_id: "21h"
syntax: "const-wide/high16 vAA, #+BBBB000000000000"
args_info: "A: destination register (8 bits), B: signed int (16 bits)"
short_desc: "Move the given literal value (right-zero-extended to 64 bits) into the specified register-pair."
long_desc: "Moves the literal value BBBB into register-pair (vAA, vAA+1). BBBB is right-zero-extended to 64 bits. The value of BBBB is in the range -32768 to 32767 (-0x8000 to 0x7FFF)."
note: "Generaly used to initialise double values."
example: "1900 2440 - const-wide/high16 v0, 0x402400000 (#double 10.0)"
example_disc: "Moves the double literal value 10.0 into (v0,v1) register-pair."

- opcode: "28"
name: "goto"
format: "AA|op"
Expand Down
Loading
Loading