Blockchains are essentially a one dimensional database where each block (section) is mathematically reliant on the block before it. This provides data integrity because it is mathematically impractical and virtually impossible to fabricate an earlier block in the blockchain or to predict a future block.
There are special functions in Computer Science called "One-way functions" that are easy to do one way, but hard to reverse. One such one-way function is a cryptographic hash, which I explained a little bit about in by blog post Understanding the Recent SHA1 Collision. A good example of a cryptographic hash is SHA3-256. For any input, SHA3-256 creates a 256 bit output that is cryptographically difficult to predict but always consistent when provided with the same input. One small change in the input should result in an entirely different output. For example, "Hello World" would result in the hash output of "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51", but "Hello world" (Note the lowercase w) would result in the hash output of "369183d3786773cef4e56c7b849e7ef5f742867510b676d6b38f8e38a222d8a2".
Now that we know a little bit about cryptographic hashing functions, we can start chaining the blocks together. Every block has a decent amount of unique and unpredictable content (from transactions, contracts, etc...) in it that we can create a hash of. So how do we chain the blocks together? For any new block, we can create a full block hash. This full block hash can be made by combining the hash of the block's contents and the previous block's full block hash and hashing that combination. Because we're using the full block hash of the previous block, we need the full block hash of the block before that block as well, which means we need the full block hash of the block before that block too, and so on so forth. This chains all of the blocks together and makes the data in the blockchain imutable. The closer to the beginning of the blockchain the block is, the more tamper resistant the block becomes.
We do run into a problem when trying to create the full block hash of the first block... there is no 0th block. For this, we can cheat a little bit and say that the full block hash of the 0th block is "0000000000000000000000000000000000000000000000000000000000000000". This allows the blockchain to start and further blocks to be created.