Vector35 / Vector35/binaryninja-api

Types auto-detected from demangled symbol names are wrong for methods

Open
#2,757 7 comments 7 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Component: Demangler Effort: Medium Impact: Medium
Dominant language
C++
Stars
1.3k
Forks
298
Avg merge
5d 5h
Merged PRs (30d)
19

Description

Binary Ninja Version

2.4.3105-dev

Describe the bug

Binary Ninja appears to attempt to set the type of symbols based on the type information in their mangled names. However, when handling C++ methods, Binary Ninja does not properly handle the implicit this-pointer passed as their first argument - it treats all methods as though they were static. A method Foo::x(char const *) will be considered to take a single char const* argument, but this is incorrect- there is also an implicit this.

This can severely break analysis in some cases because all calls to methods affected by this issue are missing their final argument (BN thinks the function has one less argument than it really does) and are mistyped (all types are off by one).

To Reproduce
Steps to reproduce the behavior:

Compile a binary, or use the one attached: argh.gz
(gzipped for silly GitHub reasons):

[nix-shell:~/binja-poc]$ cat argh2.h
class Foo {
        public:
        Foo() {};
        int x(const char * somearg);
};

[nix-shell:~/binja-poc]$ cat argh2.cpp
#include "argh2.h"

int Foo::x(char const *somearg) {
        return 7;
}

[nix-shell:~/binja-poc]$ cat argh.cpp
#include "argh2.h"

int main(void) {
        Foo f;
        f.x("hello world");
}

[nix-shell:~/binja-poc]$ g++ argh2.cpp -shared -o argh2.so

[nix-shell:~/binja-poc]$ g++ argh.cpp argh2.so -o argh

Open the resulting binary in Binary Ninja, and observe that the argument to Foo::x ("hello world") is missing from HLIL

00401050  int32_t main(int32_t argc, char** argv, char** envp)

0040105b      void* fsbase
0040105b      int64_t rax = *(fsbase + 0x28)
00401070      void var_11
00401070      Foo::x(&var_11)
0040107a      *(fsbase + 0x28)
00401083      if (rax != *(fsbase + 0x28))
0040108c          __stack_chk_fail()
0040108c          noreturn
0040108b      return 0

Note that the type of Foo::x is int64_t Foo::x(char const* arg1).

Expected behavior
Foo::x should be considered to take two arguments (on platforms with Itanium-like ABIs and mangling rules). Changing this manually by retyping the function to int64_t Foo::x(void* this, char const* arg1) results in the argument being correctly displayed:

00401070 Foo::x(this: &var_11, "hello world")

Version and Platform (required):

  • Binary Ninja: Dev 2.4.3105-dev
  • OS: NixOS
  • Version: 21.11

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the issue with the attached argh.gz binary or the argh2.h, argh2.cpp, and argh.cpp example, then inspect the generated HLIL and the inferred type for Foo::x. Trace the demangled C++ method type handling from the relevant analysis entry point. Done means methods include the implicit this argument and calls display both this and the explicit argument correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
reverse-engineering
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.