9

Say I am using an open source library of someone who does not know what they're doing well. (no encapsulation for important members) Really it's a coworker who's code I'm not allowed to modify, nor is he willing to modify it for me.

How can I forcefully access a private member without doing something like rewriting a fake class or modifying the original class?

I've tried things like #define private public, but the class file includes some standard namespace files and this will give a compilation error.

I've tried memory manipulation, but this requires member identification which isn't going to work. (See the following)

#define PX_ACCESS_PRIVATE( pObject, _Member ) ( static_cast< std::size_t >( pObject ) + static_cast< std::size_t >( &( ( decltype( pObject )( nullptr ) )->_Member ) ) )

Any ideas?

man of asdf
  • 111
  • 7
  • 6
    scream bloody murder at your manager because this won't get to sustainable solutions. – Tarick Welling May 21 '19 at 07:13
  • @TarickWelling haha that's a good plan b. – man of asdf May 21 '19 at 07:15
  • 1
    Presumably, the member is private because of encapsulation, not lack of it. Discuss why you can't access it, and why you feel a need to, with your coworker instead of demanding that they bend the code to your will. You're much more likely to arrive at a proper solution that way. – molbdnilo May 21 '19 at 07:22
  • any memory manipulation with non-public member addresses may cause UB, because class no longer have a standard memory layout. On way to do so is either request proper interface for your task, provide user\developer story to manager. Or create own analog, claiming that "this module doesn't provide required function". That's a last ditch effort, right before ramming wall with that other developer's head :P – Swift - Friday Pie May 21 '19 at 07:25
  • @molbdnilo the member absolutely needs an encapsulation function that he does not feel is worth the time to implement because I am the only use-case. It's not a quick implementation, but I'd be more than happy to do it if I had the ability to modify the code. I'm actually trying to do it manually myself around the member. – man of asdf May 21 '19 at 07:29
  • @Swift-FridayPie In my time reverse engineering malware, I've come to learn that it's not as unexpected as it is said to be. Sure, it's "undefined" behavior, but it works perfectly and it should because of C++'s class structuring. I could hard code the offset from the base for each member I need and then encapsulate it that way, but that will literally take forever. – man of asdf May 21 '19 at 07:31
  • @manofasdf Encapsulation means hiding, not exposing. Getters (and setters) break encapsulation, they don't provide it. It's possible that you're disagreeing because of terminology confusion. – molbdnilo May 21 '19 at 07:31
  • @molbdnilo Encapsulation means access to a private member through managed means (getters and setters). It is "encapsulated" by the function-members as a middleman to the original member. The members are already private, and there is a lack of that middleman getter/setter implemented due to laziness. – man of asdf May 21 '19 at 07:32
  • @George Yeah, I thought of `offsetof`. The problem is it won't compile because the `offsetof` macro accesses the members very similarly to my `PX_ACCESS_PRIVATE` macro, it requires the member identification which is set as private to the class :/ – man of asdf May 21 '19 at 07:33
  • FYI, `static_cast< std::size_t >( &( ( decltype( pObject )( nullptr ) )->_Member` can be simplified to `offsetof(decltype(*p Object), _Member)` Also, you should use `std::(u)intptr_t` instead of `std::size_t` when casting a pointer to an integer. However, once you have adjusted the integer to refer to `_Member`, you need to cast the integer to `_Member`'s type in order to actually access the member, eg cast to `decltype(pObject->_Member)&` – Remy Lebeau May 21 '19 at 07:37
  • @manofasdf: Does the class whose member you want to access have any template? – P.W May 21 '19 at 07:38
  • @RemyLebeau good practices, thanks for the info. – man of asdf May 21 '19 at 07:49
  • @P.W unfortunately not. – man of asdf May 21 '19 at 07:49
  • @manofasdf: the answer given already uses the template approach I've thought about. – P.W May 21 '19 at 08:12
  • @P.W right but `class foo` does not use templates whatsoever. – man of asdf May 21 '19 at 08:26
  • 1
    @manofasdf: Yeah, the answer given would not have required the helper template(s) if your class already had it. That is why I first wanted to find out if your class already had a template. – P.W May 21 '19 at 08:27
  • I certainly hope no-one tries to forcefully access **my** private member! – Boann May 21 '19 at 17:35

1 Answers1

15

Oh, you can break encapsulation gloriously. The type system has a loophole that can be leveraged to that effect. Explicit instantiations of templates don't do access checks on their arguments. You can pass anything there. So with a bit of plumbing...

template<typename Tag>
struct contraband_ {
    using type = typename Tag::type;
    inline static type ptr;
};

template<typename Tag>
inline auto const contraband = contraband_<Tag>::ptr;

template<typename Tag, typename Tag::type ptr_>
class steal : contraband_<Tag> {
    static inline const char filler = [] {
        steal::contraband_::ptr = ptr_;
        return '\0';
    }();
};

... you can have yourself indirect access to any private member via a pointer to it...

class foo {
    int x = 3;
};

struct x_tag { using type = int foo::*; };

template class steal<x_tag, &foo::x>;

int main()
{
    foo f;
    // return f.x; ill-formed! Private!
    return f.*contraband<x_tag>; // Okay!
}

See it live.

A fun exercise, but you really should work things out with your colleague instead of resorting to this. Use at your own peril.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458