Making an EXE that self-disinfects?
Making an EXE that self-disinfects?
I had this idea for a program I was working on.. As we should know exactly the size of our EXE, we could have the EXE check itself. If it's too big, it does a search for a known string in the beginning of our EXE. Using that as a point of reference, it truncates everything before it. Then, it truncates everything after the known size of out EXE. Assuming most viruses work by putting most of themselves at the end of the EXE, and a small pointer at the beginning, or everything at the beginning, this would self-disinfect our EXE from most viruses. As I'm still a PureBasic newbie, I don't even know if this could be done from within PureBasic.
Has anyone done anything like this?
Has anyone done anything like this?
Re: Making an EXE that self-disinfects?
I always make my apps check their byte size and "End" them if incorrect,
simply to stop people unpacking them for running (I use UPX on them).
I did this as a primitive sort of anti-cracker device, although I since learnt
it won't stop them at all. I still do it though because, as you said, it's a
good way for the app to know if it's been tampered with in some way.
simply to stop people unpacking them for running (I use UPX on them).
I did this as a primitive sort of anti-cracker device, although I since learnt
it won't stop them at all. I still do it though because, as you said, it's a
good way for the app to know if it's been tampered with in some way.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
"PureBasic won't be object oriented, period" - Fred.
- Joakim Christiansen
- Addict
- Posts: 2452
- Joined: Wed Dec 22, 2004 4:12 pm
- Location: Norway
- Contact:
Re: Making an EXE that self-disinfects?
Sounds handy, could you give us the code for this?PB wrote:I always make my apps check their byte size and "End" them if incorrect,
simply to stop people unpacking them for running (I use UPX on them).
I did this as a primitive sort of anti-cracker device, although I since learnt
it won't stop them at all. I still do it though because, as you said, it's a
good way for the app to know if it's been tampered with in some way.
I like logic, hence I dislike humans but love computers.
Re: Making an EXE that self-disinfects?
I'm at work without the code at the moment, I'll send it later when I get
home (in about 5 hours from now; got some things to do after work and
before I get home).
home (in about 5 hours from now; got some things to do after work and
before I get home).
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
"PureBasic won't be object oriented, period" - Fred.
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:
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...
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:
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.
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
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
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
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.
Last edited by freak on Mon Aug 15, 2005 3:49 pm, edited 1 time in total.
quidquid Latine dictum sit altum videtur
crackers, not hackers 
and: i would just use crc32 for this md5 is not needed. however that doesnt matter.
Yes it is a good way to check if any vira infected your program. Of course it will not stop the virus from running though, as it (normally) wants to be run first. But it will give the user a hint that there is something wrong.
Also: it protects from running a corupt file. good for example when dealing with sfx-ers.
For crackers, it wont really help. Simply disabling the check would do it!
However this is a rather good way to do it! And if implemented correctly, protected with self modifying code, jumps [spaghetti code], jumps using stack, fake code etc, then this is a good thing. I would say all protected exe's should at least contain 1 checks like these.
As for self-disinfection, i got an idea:
It IS possible to rename a running exe! Then if the exe is small, contain a compressed copy of ITSELF inside itself. so:
Rename the running corrupt exe, extract to original filename, give error, quit and then delete the renamed file.

and: i would just use crc32 for this md5 is not needed. however that doesnt matter.
Yes it is a good way to check if any vira infected your program. Of course it will not stop the virus from running though, as it (normally) wants to be run first. But it will give the user a hint that there is something wrong.
Also: it protects from running a corupt file. good for example when dealing with sfx-ers.
For crackers, it wont really help. Simply disabling the check would do it!
However this is a rather good way to do it! And if implemented correctly, protected with self modifying code, jumps [spaghetti code], jumps using stack, fake code etc, then this is a good thing. I would say all protected exe's should at least contain 1 checks like these.
As for self-disinfection, i got an idea:
It IS possible to rename a running exe! Then if the exe is small, contain a compressed copy of ITSELF inside itself. so:
Rename the running corrupt exe, extract to original filename, give error, quit and then delete the renamed file.
Last edited by thefool on Mon Aug 15, 2005 3:37 pm, edited 1 time in total.
> crackers, not hackers.
hey, it was 6am and i was not thinking anymore... of course i know the difference
the reason i choose md5 is that the md5 string is long (and unique) enough
to be found by the patcher and the check routine. If you use crc32 (which is one value only)
you have to put an extra marker to find it in the executable.
hey, it was 6am and i was not thinking anymore... of course i know the difference

the reason i choose md5 is that the md5 string is long (and unique) enough
to be found by the patcher and the check routine. If you use crc32 (which is one value only)
you have to put an extra marker to find it in the executable.
quidquid Latine dictum sit altum videtur
Oh sure...freak wrote:hey, it was 6am and i was not thinking anymore... of course i know the difference

Oh sorry about that. Also, the speed doesnt really matter in this case.freak wrote:the reason i choose md5 is that the md5 string is long (and unique) enough
to be found by the patcher and the check routine. If you use crc32 (which is one value only)
you have to put an extra marker to find it in the executable.
-
- User
- Posts: 43
- Joined: Wed Jun 28, 2006 6:02 am
MD5 executable check
I simply want to check the MD5 thing so I know if a file has been changed. However, the patcher etc in this thread doesn't work with version 4.
Can anyone help me with a revised code as is beyond my coding ability
thanks
Dan Raymond
Can anyone help me with a revised code as is beyond my coding ability
thanks
Dan Raymond
-
- Enthusiast
- Posts: 731
- Joined: Wed Apr 21, 2004 7:12 pm
I'm up late, and I thought I may as well make my insomnia useful. Here's PB4 versions of freak's code.
Patcher Program:
Include file.
Example: See above.
Hope that helps
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(0)
*Buffer = AllocateMemory(Size)
If *Buffer
ReadData(0,*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(0,*Pointer-*Buffer)
WriteString(0,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
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(file)
*Buffer = AllocateMemory(Size)
If *Buffer
ReadData(file,*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
Hope that helps

Last edited by Killswitch on Thu Oct 26, 2006 2:54 pm, edited 1 time in total.
~I see one problem with your reasoning: the fact is thats not a chicken~
-
- User
- Posts: 43
- Joined: Wed Jun 28, 2006 6:02 am
thanks but!
Thanks for help, but still won't compile without errors, have you tried it or just converted it???
thanks
Dan Raymond
thanks
Dan Raymond
-
- Enthusiast
- Posts: 731
- Joined: Wed Apr 21, 2004 7:12 pm
- Joakim Christiansen
- Addict
- Posts: 2452
- Joined: Wed Dec 22, 2004 4:12 pm
- Location: Norway
- Contact: