They keep track of
Transfer events emitted by that smart contract. Most likely they record them in an SQL database and maintain a ledger based on these events. The event is defined in the ERC20 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
There is no way to look up this information from the smart contract directly. Even though the
balances variable is public, the
mapping data type in Solidity doesn't support enumerating the keys. Reading the low level database of an Ethereum client wouldn't help either since all storage keys are hashed before they are persisted.
I have created a standalone tool which does the same.
Take a token contract address
Iterate over all
Transferevents for token using
Build a local database of these events
Allow you to use SQL to query any account balance on any point of time (block num)
There are some quirks here and there: for example detecting mint / creation event for some tokens is not straightforward. Thus, you will may negative balance on the account receiving initial total supply if you rely on
Transfer event only.
As ERC20 tokens distribution is stored in
balances variable inside the token smart-contract and as variable is public, by listing the transactions
out you can then know all the holding token addresses. As reading a variable state doesn't cost any gas, you can perform this at almost no cost ( other than the power you need to perform the checkings )
Another solution is to host a synchronized node in which you could then check the state of the
balances inside the EVM.