Skip to content

Final words

The final script looks like this

#  Copyright 2022-2023 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.


"""BIONIC User ID extractor

This snippet uses Quokka to extract the user ID mapping from a Bionic LibC

Usage:
    python ./script <bionic_path>

Author:
    Written by dm (Alexis Challande) in 2022.
"""

import quokka
from quokka import Data
from quokka.types import AddressT, DataType


def print_usertable(bionic: quokka.Program):
    """Extract the user table with a bionic libc"""

    # Step1 : Find the function
    getpwuid = bionic.get_function("getpwuid", approximative=False)

    # Step 2: find the data ref
    user_table: Data = getpwuid.data_references[1]

    # Step 3: Read the first entry
    users = []

    first_user = bionic.executable.read_string(user_table.value)
    first_id = bionic.get_data(user_table.address + 0x4).value
    users.append((first_user, first_id))

    # Read other entries
    def read_userid(prog: quokka.Program, address: AddressT) -> int:
        return prog.executable.read_data(
            prog.addresser.file(address), DataType.DOUBLE_WORD
        )

    # Gather all components together
    start = user_table.address + 0x8
    while True:
        data: Data = bionic.get_data(start)
        if data.code_references:
            break

        user_name = bionic.executable.read_string(data.value)
        user_id = read_userid(bionic, data.address + 0x4)

        print(f"New user {user_name} with ID {user_id}")
        users.append((user_name, user_id))

        start += 0x8

    # Print the user table
    for user_name, user_id in users:
        print(f"{user_name=} : {user_id=}")


if __name__ == "__main__":
    program: quokka.Program = quokka.Program.from_binary(sys.argv[1])
    print_usertable(program)