C, C++, JS, etc, have more instances where someone committed a fix for a bug (as opposed to new code).
Clojure, Haskell, etc, required fewer bugfix commits.
Somewhere in the program the validation code will either pass or fail. This is done with a conditional branch instruction in the assembly. Crackers use a debugger to find where this branch is, then change it to an instruction that will always branch to the pass condition.
Of course there are countermeasures used, and sometimes crackers will be able to reverse-engineer the validation check to create a keygen, etc, but the general process is still to disassemble the executable and modify or inspect the validation check.