Skip to content

Issues with has_arc() and has_canary() Functions Not Detecting Symbols in Mach-O Files #44

Open
@cpuu

Description

@cpuu

Environment

  • Rust version: rustc 1.73.0 (cc66ad468 2023-10-03)
  • Goblin version: goblin = "0.5.2"
  • Operating System and version: Apple M2 Pro, macOS Sonoma 14.1

Description

I've encountered a potential issue with the has_arc() and has_canary() functions in the macho.rs file. These functions are intended to check for the presence of specific keywords in the imports of a Mach-O binary: _objc_release for has_arc(), which should return true if ARC is being used, and either ___stack_chk_fail or ___stack_chk_guard for has_canary(), which should return true if stack protection is enabled.

Expected Behavior

When provided with a Mach-O binary that has ARC and stack canaries properly applied, the has_arc() function is expected to return true if the _objc_release symbol is present

$ nm ~/Desktop/HelloWorld | grep _objc_release
                 U _objc_release

and has_canary() should return true if stack protection symbols are present.

$  nm ~/Desktop/hello_canary
                 U ___stack_chk_fail
                 U ___stack_chk_guard
0000000100000000 T __mh_execute_header
0000000100003f2c T _main
                 U _read

Actual Behavior

Despite supplying a Mach-O file that I've verified to have ARC enabled, the has_arc() function returned false. Upon further inspection, it appears that the list of imports retrieved within the function is empty. This same behavior is observed with the has_canary() function, suggesting that both functions may consistently return false regardless of the actual contents of the Mach-O binary.

$ ./checksec -f ~/Desktop/hello_canary
MachO64: | 
ARC: false 
Canary: false 
...
 | File: /Users/cpuu/Desktop/hello_canary

Investigation

To further investigate the issue, I added additional print statements to the has_arc() function to trace the flow and check where it might be failing. Below is the modified version of the has_arc() function:

fn has_arc(&self) -> bool {
    println!("Starting has_arc check...");

    match self.imports() {
        Ok(imports) => {
            println!("Successfully retrieved imports. Number of imports: {}", imports.len());
            if imports.is_empty() {
                println!("No imports found. Exiting check.");
            }

            for import in &imports {
                println!("Import name: {}", import.name);
                if import.name == "_objc_release" {
                    println!("Found '_objc_release' import. ARC is used. Exiting check.");
                    return true;
                }
            }

            println!("'_objc_release' import not found. ARC is not used.");
            false
        },
        Err(e) => {
            println!("Error while getting imports: {:?}", e);
            false
        }
    }
}

When running the above code with a Mach-O binary that is known to have ARC enabled, the output was as follows:

Starting has_arc check...
Successfully retrieved imports. Number of imports: 0
No imports found. Exiting check.
'_objc_release' import not found. ARC is not used.

This output indicates that the imports() call is successful, but it retrieves an empty list of imports, leading to the function incorrectly reporting that ARC is not used. Given that I have verified the binary has ARC enabled through other means, this result seems to be inaccurate.

Additional Information

I have verified the presence of ARC and stack canaries in my Mach-O binary using both otool and nm command-line tools, which show the expected symbols. This leads me to believe there might be a discrepancy in how the macho.rs file handles the parsing or detection of these symbols.

I am wondering if there could be an underlying issue with how imports are being retrieved or if there's an assumption made by the checker that doesn't hold true for all Mach-O binaries.

Any insights or suggestions on this matter would be greatly appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions