The other two answers are good in that they cover the part about Pedersen commitments, and how those are used to check that the sum of the amounts in the outputs created doesn't exceed that of the sum of the real inputs consumed (the homomorphic cryptography part).
On the other hand, since the amounts involved are being taken from a finite range where modular arithmetic is being used, the sender could still use "negative" numbers to produce very large output amounts. To prevent this, range proofs are needed as well, and those too are implemented as well in ringCT's code.
I don't have a very deep knowledge of how they are implemented in Monero's code specifically, but the gist of it is this (I am writing this all from memory, so there might be some imprecisions):
The amount a
being commited is broken down into its constituting digits. Imagine in base 10, each digit would be a number between 0 and 9.
Now for each digit's position, and for each of the ten digits a public key is created. The user knows the private keys corresponding to the actual digits of a
in each position, and uses that to produce a ring signatures involving those 10 public keys, signing with the actual digit key in each position.
In reality there is a trade off between the number of digits used to represent a number (each requires an extra ring) and the ring sizes themselves, so that there is an optimal way to represent a
. I believe that this turns out to be base 4, instead of base 10.
See Borromean ring signatures.