Where do hash functions get their preimage resistance? [migrated]


I read through this answer and it seemed to make sense to me, but when I try to make a simpler answer to explain it to myself I lose something in the process.

Here is the much simpler hash function I wrote after reading the description of how MD5 works.

  1. Take in a single digit integer input as M
  2. Define A[0] to be some public constant
  3. for int i=1; i<=4; i++:
    A[i] = (A[i-1] + M) mod 10
  4. return A[4]

This hash function uses the message word in multiple rounds, which is what the answer says leads to preimage resistance. But with some algebra using mod addition we can reduce this "hash function" to just A[i] = (A[0] + i*M) mod 10.

A[1] = (A[0] + M) mod 10 A[2] = (A[1] + M) mod 10    //Substitute A[1] in      = ((A[0] + M) mod 10 + M) mod 10   // Distribute outer mod 10 in      = ((A[0] + M) mod 10 mod 10 + M mod 10) mod 10 // simplify mod 10 mod 10 to mod 10      = ((A[0] + M) mod 10 + M mod 10) mod 10    // Distribute inner mod 10      = ((A[0] mod 10 + M mod 10) mod 10 + M mod 10) mod 10  //factor mod 10 out      = ((A[0] mod 10 + M mod 10) + M) mod 10    // remove redudent paraens      = (A[0] mod 10 + M mod 10 + M) mod 10  // factor mod 10 in      = (A[0] mod 10 mod 10 + M mod 10 mod 10 + M mod 10) mod 10 // simplify mod 10 mod 10 to mod 10      = (A[0] mod 10 + M mod 10 + M mod 10) mod 10   // factor mods 10 out      = (A[0] + M + M) mod 10      = (A[0] + 2M) mod 1 // Repeat with A[3] to find A[3] = (A[0] + 3M) mod 10 and so on 

Because A[i] = (A[0] + i*M) mod 10 is not preimage resistant, I’m confused as to what action in a hash function gives it its preimage resistance. To phrase my question another way, if I wanted to write a super simple hash function, what would I need to include to be preimage resistant?