Antivirus is only ever going to catch broad attacks, or default payloads from commonly used tools.
A skilled attacker will be able to modify, encode, or obfuscate his payload to avoid this type of detection.
That being said, most antivirus will also search the executable file for strings known to only be found in the malware. For example, here is a snippet from Invoke-Mimikatz.ps1
:
$e_res2Field = $TypeBuilder.DefineField('e_res2', [UInt16[]], 'Public, HasFieldMarshal')
Antivirus can search for strings like this within the file, and then flag it if it detects a match. This can also be defeated fairly easily. One example would be to take the file and break it up into small strings. Like this:
"$e_res2Fi" + "eld = $TypeBui" + "lder.DefineField('e_res2'," + " [UInt16[]], 'Public, HasFieldMarshal')"
(not trying to be syntactically correct here, but you get the idea)
And then use a wrapper script to piece the strings together in memory and execute the original code.
Another more common example would be encrypting the primary payload and then have a stub decrypt and execute the payload in memory.
Some antivirus will also conduct dynamic analysis, where the file is ran in a virtualized or simulated environment to detect the actions that the executable would perform, or to analyze post decryption memory.
This type of antivirus can usually be bypassed simply by consuming enough of either time or memory before decrypting the primary payload.