Skip to content

Client API Reference

SightHouseAnalysis

SightHouseAnalysis(url: str, username: str, password: str, logger: LoggingSighthouse, verify_host: bool = True, force_submission: bool = False, options: AnalysisOptions = None)

Parameters:

  • url

    (str) –

    URL of Sighthouse server

  • username

    (str) –

    username to connect to server

  • password

    (str) –

    password to connect to server

  • logger

    (LoggingSighthouse) –

    A Sighthouse Logging linked to SRE

  • verify_host

    (bool, default: True ) –

    Option to enable or disable certificate verification

  • force_submission

    (bool, default: False ) –

    Delete cached information on the server side if any before starting a new analysis

  • options

    (AnalysisOptions | None, default: None ) –

    Options for the analysis

Methods:

Source code in sighthouse/client/SightHouseClient.py
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
def __init__(
    self,
    url: str,
    username: str,
    password: str,
    logger: LoggingSighthouse,
    verify_host: bool = True,
    force_submission: bool = False,
    options: AnalysisOptions = None,
) -> None:
    """Initialize SightHouseAnalysis

    Args:
        url (str): URL of Sighthouse server
        username (str): username to connect to server
        password (str): password to connect to server
        logger (LoggingSighthouse): A Sighthouse Logging linked to SRE
        verify_host (bool): Option to enable or disable certificate verification
        force_submission (bool): Delete cached information on the server side if any
                                 before starting a new analysis
        options (AnalysisOptions | None): Options for the analysis
    """
    self._username = username
    self._password = password
    self._logger = logger
    self._client = SightHouseClient(url, self._logger, verify_host=verify_host)
    self._force_submission = force_submission
    self._processor = self.get_current_arch()
    if self._processor is None:
        self._logger.error("architecture not found or not supported yet")
        return None

    self._options = options or AnalysisOptions()

add_tag

add_tag(address: int, tag: str, message: str) -> None

Add a tag on the SRE

Parameters:

  • address

    (int) –

    address where put the tag

  • tag

    (str) –

    tag of message

  • message

    (str) –

    message to show

Source code in sighthouse/client/SightHouseClient.py
787
788
789
790
791
792
793
794
795
def add_tag(self, address: int, tag: str, message: str) -> None:
    """Add a tag on the SRE

    Args:
        address (int): address where put the tag
        tag (str): tag of message
        message (str): message to show
    """
    raise NotImplementedError("add_tag")

get_current_arch

get_current_arch() -> None

get current architecture and translate to ghidra one

Source code in sighthouse/client/SightHouseClient.py
767
768
769
def get_current_arch(self) -> None:
    """get current architecture and translate to ghidra one"""
    raise NotImplementedError("get_current_arch")

get_current_binary

get_current_binary() -> bytes

Retrieve the current binaries in bytes

Returns:

  • bytes ( bytes ) –

    the content in bytes of the current binaries

Source code in sighthouse/client/SightHouseClient.py
779
780
781
782
783
784
785
def get_current_binary(self) -> bytes:
    """Retrieve the current binaries in bytes

    Returns:
        bytes: the content in bytes of the current binaries
    """
    raise NotImplementedError("get_current_binary")

get_functions

get_functions(section: Section) -> List[Function]

get functions

Parameters:

Returns:

  • List[Function] –

    List[Function]: list of function inside the section

Source code in sighthouse/client/SightHouseClient.py
813
814
815
816
817
818
819
820
821
822
def get_functions(self, section: Section) -> List[Function]:
    """get functions

    Args:
        section (Section): section

    Returns:
        List[Function]: list of function inside the section
    """
    raise NotImplementedError("get_functions")

get_hash_program

get_hash_program() -> str

get hash of program

Returns:

  • str ( str ) –

    sha256 string

Source code in sighthouse/client/SightHouseClient.py
824
825
826
827
828
829
830
def get_hash_program(self) -> str:
    """get hash of program

    Returns:
        str: sha256 string
    """
    raise NotImplementedError("get_hash_program")

get_program_name

get_program_name() -> str

Get program name

Returns:

  • str ( str ) –

    the program name

Source code in sighthouse/client/SightHouseClient.py
797
798
799
800
801
802
803
def get_program_name(self) -> str:
    """Get program name

    Returns:
        str: the program name
    """
    raise NotImplementedError("get_program_name")

get_sections

get_sections() -> List[Section]

Get sections

Returns:

  • List[Section] –

    List[Section]: list sections

Source code in sighthouse/client/SightHouseClient.py
805
806
807
808
809
810
811
def get_sections(self) -> List[Section]:
    """Get sections

    Returns:
        List[Section]: list sections
    """
    raise NotImplementedError("get_sections")

run

run() -> bool

Run the complete analysis

Source code in sighthouse/client/SightHouseClient.py
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
def run(self) -> bool:
    """Run the complete analysis"""
    try:
        self.update_progress("Logging in to the signature server...")
        if not self._client.login(self._username, self._password):
            return False

        binary = self.get_current_binary()
        if binary == b"":
            return False

        self.update_progress("Uploading current binary...")
        # potentially check if file already upload
        program_name = self.get_program_name()
        if not self._client.upload(program_name, binary):
            return False

        self.update_progress("Importing current binary...")
        # Check for previous program
        program_id = self._client.get_program(program_name)
        do_import = True
        if program_id is None:
            # No program found, create a new one
            if not self._client.create_program(program_name, self._processor):
                return False

        elif self._force_submission:
            self._client.delete_program(program_id)
            self._client.create_program(program_name, self._processor)
        else:
            # Program exists and force_submission is false -> use cache
            do_import = False

        if do_import:
            self.update_progress("Importing sections binary...")
            if not self._client.delete_sections():
                return False

            sections = self.get_sections()
            for section in sections:
                if not self._client.create_section(section):
                    return

                if section.perms[-1] == "X":
                    functions = self.get_functions(section)
                    if not self._client.add_functions(functions, section):
                        return False

            self.update_progress("Analyzing the binary file...")
            if not self._client.start_analysis(options=self._options):
                return False

            self.update_progress("Analysis started.")

            # Poll periodically
            while self._client.is_analyzing():
                self.wait()

        self.update_progress("Request for matches...")
        signatures = self._client.get_matches()
        if isinstance(signatures, list):
            self.update_progress(f"Got {len(signatures)} potential signatures!")
            for signature in signatures:
                self.add_tag(
                    signature.address, "SightHouse matches", "\n" + str(signature)
                )

            return True
    except Exception as e:
        self._logger.error(str(e))
        raise e

    return False

update_progress

update_progress(message: str) -> None

show an update progress

Parameters:

  • message

    (str) –

    message to show

Source code in sighthouse/client/SightHouseClient.py
771
772
773
774
775
776
777
def update_progress(self, message: str) -> None:
    """show an update progress

    Args:
        message (str): message to show
    """
    raise NotImplementedError("update_progress")

wait

wait(seconds: int = 10) -> None

Some analyzers will need to handle sleeping differently. The default implementation rely on time.sleep.

Parameters:

  • seconds

    (int, default: 10 ) –

    The number of seconds to wait for

Source code in sighthouse/client/SightHouseClient.py
832
833
834
835
836
837
838
839
def wait(self, seconds: int = 10) -> None:
    """Some analyzers will need to handle sleeping differently.
       The default implementation rely on time.sleep.

    Args:
        seconds (int): The number of seconds to wait for
    """
    time.sleep(seconds)

Section

Section(name: str, start: int, end: int, fileoffset: int, perms: str, kind: str, id: int = -1)

Bases: object

Manipulate Section object

Source code in sighthouse/client/SightHouseClient.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def __init__(
    self,
    name: str,
    start: int,
    end: int,
    fileoffset: int,
    perms: str,
    kind: str,
    id: int = -1,
):
    self.name: str = name
    self.start: int = start
    self.end: int = end
    self.perms: str = perms
    self.kind: str = kind
    self.fileoffset = fileoffset
    self.id: int = id

Function

Function(name: str, offset: int, details: dict = None)

Bases: object

Manipulate Function object

Source code in sighthouse/client/SightHouseClient.py
85
86
87
88
89
90
def __init__(self, name: str, offset: int, details: dict = None):
    self.name: str = name
    self.offset: int = offset
    self.id: int = -1
    # Details are architecture/SRE dependent information
    self.details: dict = details or {}

Match

Match(executable: str, function: str, score: float, nb_match: int)

Bases: object

Show match

Source code in sighthouse/client/SightHouseClient.py
38
39
40
41
42
43
44
45
46
47
48
def __init__(self, executable: str, function: str, score: float, nb_match: int):
    self.executable = json.loads(executable)
    self.metadatas = self.executable.get("metadata", None)
    if self.metadatas is None:
        self.metadatas = [
            (self.executable.get("name"), self.executable.get("version"))
        ]
    self.origin = self.executable["origin"]
    self.function = function
    self.score = score
    self.nb_match = nb_match

Signature

Signature(function: str, address: int, matches: list[Match])

Bases: object

show signature

Source code in sighthouse/client/SightHouseClient.py
96
97
98
99
def __init__(self, function: str, address: int, matches: list[Match]):
    self.function = function
    self.address = address
    self.matches = matches

LoggingSighthouse

LoggingSighthouse()

Bases: object

Initialize logging class

Methods:

  • error –

    Show an error message

  • info –

    Show an info message

  • warning –

    Show an warning message

Source code in sighthouse/client/SightHouseClient.py
702
703
704
def __init__(self) -> None:
    """Initialize logging class"""
    raise NotImplementedError("LoggingSighthouse")

error

error(message: str)

Show an error message

Parameters:

  • message

    (str) –

    The message to show

Source code in sighthouse/client/SightHouseClient.py
706
707
708
709
710
711
712
def error(self, message: str):
    """Show an error message

    Args:
        message (str): The message to show
    """
    raise NotImplementedError("error")

info

info(message: str)

Show an info message

Parameters:

  • message

    (str) –

    The message to show

Source code in sighthouse/client/SightHouseClient.py
722
723
724
725
726
727
728
def info(self, message: str):
    """Show an info message

    Args:
        message (str): The message to show
    """
    raise NotImplementedError("info")

warning

warning(message: str)

Show an warning message

Parameters:

  • message

    (str) –

    The message to show

Source code in sighthouse/client/SightHouseClient.py
714
715
716
717
718
719
720
def warning(self, message: str):
    """Show an warning message

    Args:
        message (str): The message to show
    """
    raise NotImplementedError("warning")