Check whether an executable is pure C or CPP

Distinguishing between a pure C and a C++ executable can be achieved by examining the symbols and library dependencies of the binary file. C++ compilers employ a technique called “name mangling” to support function overloading and namespaces, which is absent in C. Furthermore, C++ programs have a distinct set of standard library dependencies.

Inspecting Symbol Tables for Name Mangling

A primary indicator of C++ code is the presence of “mangled” names in the executable’s symbol table. C++ compilers alter function and variable names to encode information about their types and namespaces, a process that C compilers do not perform.

On Linux and other Unix-like systems, you can use command-line tools like nm or objdump to view the symbol table.

  • Using nm: The nm utility lists the symbols from object files. A tell-tale sign of C++ is the presence of complex, decorated symbol names.codeBashnm <executable_name> | grep ' T '
    • Pure C symbols will typically look clean and straightforward, often with a leading underscore, like _main or _my_function.
    • C++ mangled symbols will be more elaborate. For instance, a function int MyClass::myFunction(int) might be mangled into something like _ZN7MyClass10myFunctionEi. The presence of such decorated names is a strong indication of C++ code.
  • Using objdump: Similar to nm, objdump can display the symbol table.codeBashobjdump -t <executable_name>Look for function names that are not simple identifiers.

Inspecting library dependencies

In Linux, you can read the dependencies of an executable file using several command-line tools. These utilities analyze the executable and list the shared libraries it needs to run.

The ldd Command

The most common and straightforward tool for this purpose is ldd (List Dynamic Dependencies). It prints the shared libraries required by a program.

How to use ldd:

To check the dependencies of an executable, simply pass the path to the executable as an argument to the ldd command:codeBash

ldd /path/to/your/executable

For example, to check the dependencies of the ls command, you would run:codeBash

ldd /bin/ls

Understanding the output of ldd:

The output of ldd is typically formatted into three columns:

  • Library Name: The first column shows the name of the shared library the executable depends on.
  • Path to the Library: The second column, following the => symbol, indicates the full path to where the system’s dynamic linker has found that library. If a library is not found, you will see a “not found” message.
  • Memory Address: The third column, in parentheses, displays the memory address where the library is loaded.

Here is an example of the output for ldd /bin/bash and what it means:codeCode

linux-vdso.so.1 (0x00007ffc1b7d8000)
    libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f5b8d8a4000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5b8d89e000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5b8d6b8000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f5b8d90d000)

In this output:

  • libtinfo.so.6 is a required library.
  • The system found it at /lib/x86_64-linux-gnu/libtinfo.so.6.
  • It is loaded at the memory address 0x00007f5b8d8a4000.

A special entry, linux-vdso.so.1, is a virtual dynamic shared object provided by the kernel to accelerate certain system calls and is not a file on disk. The /lib64/ld-linux-x86-64.so.2 is the dynamic linker itself, which is responsible for loading the other shared libraries.

Important Security Note: You should never run ldd on an untrusted executable. In some cases, ldd might directly execute the program to determine its dependencies, which could be a security risk.

Alternative Tools

While ldd is the most common tool, there are other utilities that can provide dependency information, sometimes with more detail or in a safer manner for untrusted files.

readelf: The readelf command can display information from ELF (Executable and Linkable Format) files, which is the standard binary file format on Linux. To see the list of needed shared libraries, you can use the -d or –dynamic option and filter for “NEEDED”.

readelf -d /path/to/your/executable | grep 'NEEDED'

This method is safer than ldd for untrusted executables because it only reads the file’s metadata and does not execute any code.

objdump: Another versatile tool for inspecting binary files is objdump. While it doesn’t have a direct option to list dependencies in the same way as ldd, it can be used to examine the dynamic linking information within the executable. It is generally more complex for this specific task.

lddtree: For a more comprehensive, hierarchical view of dependencies (including the dependencies of the dependencies), you can use lddtree (also known as pax-utils on some distributions).This tool presents the information in an easy-to-understand tree format.

lddtree /path/to/your/executable

By using these tools, you can effectively inspect and understand the library dependencies of any executable on a Linux system.

Leave a Reply

Your email address will not be published. Required fields are marked *