From b6232d07056d6d33363fc55df067d828f0ea9361 Mon Sep 17 00:00:00 2001 From: "A. Challande" Date: Thu, 17 Nov 2022 16:29:44 +0100 Subject: [PATCH] feat: Allow to read string without their size if they are null-terminated --- bindings/python/quokka/executable.py | 27 ++++++++++++++++++++------- tests/python/tests/test_executable.py | 25 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 tests/python/tests/test_executable.py diff --git a/bindings/python/quokka/executable.py b/bindings/python/quokka/executable.py index a34aaf0..b513f16 100644 --- a/bindings/python/quokka/executable.py +++ b/bindings/python/quokka/executable.py @@ -75,14 +75,17 @@ def read(self, offset: int, size: int) -> bytes: except IndexError as exc: raise ValueError(f"Content not found at offset {offset}") from exc - def read_string(self, offset: int, size: int) -> str: + def read_string(self, offset: int, size: Optional[int] = None) -> str: """Read a string in the file. + + If the size is not given, Quokka will try to read the string until the + first null byte. That works only for null-terminated strings. If the string is null terminated, remove the trailing 0. Arguments: - offset: String file offset - size: String size + offset: String file offset + size: String size if known. Returns: The decoded string @@ -90,10 +93,20 @@ def read_string(self, offset: int, size: int) -> str: Raises: ValueError: If the string is not found nor decoded. """ - try: - string = self.read(offset, size).decode("utf-8") - except UnicodeDecodeError as exc: - raise ValueError("Unable to read or decode the string.") from exc + + if size is not None: + try: + string = self.read(offset, size).decode("utf-8") + except UnicodeDecodeError as exc: + raise ValueError("Unable to read or decode the string.") from exc + + else: + try: + null_byte = self.content.index(b"\x00", offset) + except ValueError as exc: + raise ValueError("String is not null-terminated and size was not given") from exc + + string = self.content[offset: null_byte].decode("utf-8") # FIX: When returning a single character string, it does not end with a '\0' if len(string) > 1 and string.endswith("\x00"): diff --git a/tests/python/tests/test_executable.py b/tests/python/tests/test_executable.py new file mode 100644 index 0000000..0d414a8 --- /dev/null +++ b/tests/python/tests/test_executable.py @@ -0,0 +1,25 @@ +# Copyright 2022 Quarkslab +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import quokka + + +def test_read_string_unknown_size(prog: quokka.Program): + data_address: int = 0x3088 + assert prog.executable.read_string(data_address) == "F00d1e" + + +def test_read_string(prog: quokka.Program): + data = prog.data_holder[20] + assert prog.executable.read_string(0x3088, data.size) == "F00d1e"