Well, i do not think such an auto-disinfection would be that easy. I don't think
a virus puts itself at the absolute beginning of the executable, but rather
somewhere inside the header section, or start of the code section.
So simply cutting of the beginning will not do the trick.
However, checking for changes to the executable and aborting is no problem.
I have played around with this a little and here is what i came up with:
Basically you have a patcher program, that creates a checksum of the executable
and adds it to the executable itself. Then in your code, you must read
that checksum, remove the checksum (because it was not included in the original calculation)
and re-calculate a new checksum of the executable.
If both match, the exe is unchanged. If not, there is a problem.
The new IDE makes automating such patching stuff very easy.
Of course this is no cracker protection, as the code that does the check
can be easily removed by a cracker, but it should do a good job against viruses or a corruped executable.
Ok, first the patcher program:
Code: Select all
; ============================================
; Executable patcher for the MD5 file check
; ============================================
;
; Compile this and add it to the new IDE as two tools for
; these triggers:
; After Compile/Run
; After Create Executable
;
; Commandline: "%EXECUTABLE"
;
; Important: check the "Wait until tool quits" checkbox !!
; Also check the "Hide tool from main menu" checkbox, because
; executing from the menu makes no sense here.
;
; ============================================
; load the given executable file
File$ = ProgramParameter()
If OpenFile(0, File$)
Size = Lof()
*Buffer = AllocateMemory(Size)
If *Buffer
ReadData(*Buffer, Size)
; search the executable file for the marker used to insert the MD5 string
*Pointer.BYTE = *Buffer
*BufferEnd = *Buffer + Size-32
While *Pointer < *BufferEnd
If CompareMemoryString(*Pointer, @"<=== MD5 Executable Check =====>", 0, 32) = 0
; marker found. now overwrite the marker with spaces
; for the MD5 check. (the validation check in the exe does the same)
;
PokeS(*Pointer, Space(32))
; Get the MD5 sum of the buffer
;
MD5Sum$ = MD5Fingerprint(*Buffer, Size)
; write the MD5 string into the actual executable file
FileSeek(*Pointer-*Buffer)
WriteString(MD5Sum$)
Break
EndIf
*Pointer + 1
Wend
FreeMemory(*Buffer)
Else
MessageRequester("MD5 Patcher", "Not enough memory!")
EndIf
CloseFile(0)
Else
MessageRequester("MD5 Patcher", "Cannot open executable file!"+Chr(13)+File$)
EndIf
Just compile this to an exe and configure the IDE as described in the comments.
It searches for a "marker" in the executable, that we will later put there.
It then replaces the marker with spaces for the MD5 calculation. Then
the resulting MD5 string is put at the position of the marker.
Ok, now a little include file, that does all the checking...
Code: Select all
; ============================================
; Includefile for the MD5 file check
; ============================================
;
; Include this file into your projects that need
; a check for the executable and call
; ExecutableCheck() to check the file. It returns
; 1 if the file is ok and 0 otherwise.
;
; ============================================
Procedure ExecutableCheck()
result = 0
; get the MD5 sum from the datasection
MD5Sum$ = PeekS(?MD5ExeChecksum)
; now we must open our own executable file
FileName$ = Space(1000)
If GetModuleFileName_(0, @FileName$, 1000)
file = ReadFile(#PB_Any, FileName$)
If file
Size = Lof()
*Buffer = AllocateMemory(Size)
If *Buffer
ReadData(*Buffer, Size)
; in the file, we must search for the real MD5 sum and
; replace it with spaces, so the calculations will match.
*Pointer.BYTE = *Buffer
*BufferEnd = *Buffer + Size-32
While *Pointer < *BufferEnd
If CompareMemoryString(*Pointer, MD5Sum$, 0, 32) = 0
PokeS(*Pointer, Space(32))
; calculate the new MD5 sum from the executable
RealMD5$ = MD5Fingerprint(*Buffer, Size)
; compare the two
If RealMD5$ = MD5Sum$
result = 1
EndIf
Break
EndIf
*Pointer + 1
Wend
FreeMemory(*Buffer)
EndIf
CloseFile(file)
EndIf
EndIf
ProcedureReturn result
EndProcedure
; this is our marker or placeholder for the patcher to
; insert the MD5 string.
; What is important is that the string found here is unique and
; does not appear anywhere else in your code. Otherwise, the patcher
; might insert the MD5 at the wrong place!
DataSection
MD5ExeChecksum:
Data$ "<=== MD5 Executable Check =====>"
EndDataSection
It has both the placeholder for the MD5 string as well as the check
procedure in it.
The only really important thing as noted in the code is that the string that
is originally in the datasection does not appear anywhere else in the code.
(or in another project that is not supposed to be patched by the patcher).
This is important, because our patcher replaces the first occurance it finds
with an MD5 string.
Ok, now for an example:
Code: Select all
XIncludeFile "md5include.pb" ; that is the above include file
If ExecutableCheck()
MessageRequester("","Executable OK")
Else
MessageRequester("","Executable changed!")
EndIf
End
If the patcher is setup correctly, you should be able to run it with no trouble.
Now create an executable. it should run ok. Now use a hex-editor
and change just 1 single byte. it will now display the "changed" message.
btw, the patcher will do nothing for files that do not include the above
includefile, so it is ok that the tool is executed with every compiled file.
Of course only as long as the datasection string does not appear in them,
so it must be something unique.