Reading decompiled (reverse-engineered) code is not as insanely hard as it sounds. You can usually find functions, and then it's a matter of finding _what_ a function does.
If you can somehow attach a debugger or get breakpoints, it's even easier.
In some cases, oddly, the intent of a function can actually become clearer when the logic gets stripped of all the bad naming protocols and names for the moving pieces have to be reconstructed from only its actions and contexts.
In a perfect world, this shouldn't be true and the content embedded within those symbols in the source code should be an easy lever towards relatively perfect understanding of both intent and implementation; however, software is a relatively young discipline and this is actually a difficult linguistic problem.
On an open source architecture, many eyes hypothetically leave few places for malicious action to hide. This is not always 100% foolproof, but it seems to work out pretty well most of the time.
On a closed source architecture, this sort of thing is generally safeguarded by contract and law. Company can get away with it once, but if the law and contracts were properly crafted there will be fines and jail time that discourages them from doing it again.