Page 2 of 2

Posted: Tue Oct 16, 2007 1:17 am
by pdwyer
Right!

It creates an interesting problem though doesn't it. Assuming you have some key how do you get it in there to decrypt? You probably don't want one key unlocks all apps but it'd be an admin nightmare to have to manage all the exe's separately (compile for each customer?).

I know that this is not being brought up as foolproof or anything but perhaps if we put a few heads together on the design we can improve it a bit as the base idea looks good, just still a little hard to use in real life

Posted: Tue Oct 16, 2007 8:40 am
by DoubleDutch
:shock:

It's just to stop script kiddies! Don't for one moment think that you will ever be able to create something that will defeat the big boys.

Posted: Tue Oct 16, 2007 10:25 am
by Inf0Byt3
Yup, DoubleDutch is totally right. The idea looks good on the paper hehe. The main bad thing about this is that the code is decrypted at runtime. That means that all the code between the labels is going to be visible to the cracker's eyes. So they can come up with a sort of loader to give control to your exe and then patch directly in memory. This, however, implemented with a good encryption algo can protect your app for a limited time from usual byte-patching.

Posted: Tue Oct 16, 2007 2:22 pm
by Inf0Byt3
Major update (multi-label support, better encryption, masked labels by DoubleDutch):

Encryptor:

Code: Select all

;By Inf0Byt3, 10OCT07
;
;Based on code by Rings/Pdwyer/Franky/Wayne Diamond
;Mods/Fixes/Improvements by DoubleDutch/Thefool
;
;Free to use, credits appreciated
;It would be nice to improve it if you have time and if you want to share the knowledge
;
;Now with multi-label support ;)
;Don't forget to enable Inline ASM

Structure Block
 StartOffset.l
 EndOffset.l
 Length.l
EndStructure

Structure CharArray 
 char.c[0] 
EndStructure

Global NewList Blocks.Block()

Procedure BZ_CompareMemory(*Src, *Dst, Len)
  MOV esi, *Src
  MOV edi, *Dst
  MOV eax, Len
  MOV ecx, eax
  AND eax, 3
  SHR ecx, 2
  XOR ebx, ebx
  REPE CMPSD
  !JNE .not_eq
  MOV ecx, eax
  XOR ebx, ebx
  REPE CMPSB
  !JNE .not_eq
  ProcedureReturn 1
  !.not_eq:
  ProcedureReturn 0
EndProcedure

Procedure XorWithKey (sText.l, LenText.l, sKey.l, LenKey.l) 
  XOR ecx, ecx 
  MOV esi, sText 
  MOV edi, sKey 
  MOV edx, LenText 
  MOV ebp, LenKey 
  ADD ebp, esi 
  xornextbyte: 
  MOV al, [esi] 
  MOV bl, [edi] 
  XOR al, bl 
  MOV [esi], al 
  INC ecx 
  INC esi 
  INC edi 
  CMP esi, ebp 
  JGE l_xorcomplete 
  CMP ecx, edx 
  JGE l_xornextround 
  JMP l_xornextbyte 
  xornextround: 
  XOR ecx, ecx 
  SUB edi, edx 
  JMP l_xornextbyte 
  xorcomplete: 
EndProcedure 

Procedure BinSearch(*Object.CharArray, ObjectLength.l, StartOffset.l, *String.CharArray, StringLength.l)
  Dim SkipLength.l(255)
  For i = 0 To 255
   SkipLength(i) = StringLength + 1
  Next
  For i = 0 To StringLength -1
   SkipLength(*String\char[i]) = StringLength - i   
  Next     
  CurrentOffset.l = StartOffset
  MaxOffset.l = ObjectLength - StringLength
  While CurrentOffset <= MaxOffset
   If BZ_CompareMemory(*Object + CurrentOffset, *String, StringLength) = 1
    FoundPos = CurrentOffset + 1
    Break
  EndIf
  CurrentOffset + SkipLength(*Object\char[CurrentOffset + StringLength])
  Wend
  ProcedureReturn FoundPos
EndProcedure 

Procedure Callback(Message.s)

 Debug Message
 
 ProcedureReturn 1

EndProcedure

Procedure EncryptExecutablePieces(File.s,*Callback)
 
 BlockStr.s = Chr($eb)+Chr($06)+Chr($eb)+Chr($fc)+Chr($eb)+Chr($fa)+Chr($eb)+Chr($f8)
 BlockEnd.s = Chr($eb)+Chr($04)+Chr($eb)+Chr($04)+Chr($eb)+Chr($fc)+Chr($eb)+Chr($fc)
 
 EXE_Block_Key.s = "this is the enc key"
 
 If FileSize(File) = 0 Or FileSize(File) = -1
  CallFunctionFast(*Callback,"No file or empty file...")
  ProcedureReturn 0
 EndIf
 
 FLRH = OpenFile(#PB_Any,File)
 If IsFile(FLRH) 
  
  CallFunctionFast(*Callback,"Opened file...")
  
  ;Read the file in memory
  TotalLength = Lof(FLRH)
  *MainMem = AllocateMemory(TotalLength)
  ReadData(FLRH,*MainMem,TotalLength)
  
  ;Now search for the blocks that need encryption
  CallFunctionFast(*Callback,"Searching for blocks...")
  While Pos <= TotalLength
   EStart = BinSearch(*MainMem,TotalLength,Pos,@BlockStr,Len(BlockStr))
   EEnd = BinSearch(*MainMem,TotalLength,Pos,@BlockEnd,Len(BlockEnd))
   If EStart > 0 And EEnd > 0
    AddElement(Blocks())
    Blocks()\StartOffset = EStart+Len(BlockStr)-1
    Blocks()\EndOffset = EEnd-1
    Blocks()\Length = Blocks()\EndOffset-Blocks()\StartOffset
   Else
    Break
   EndIf
   Pos + (EEnd-Pos)
  Wend
  
  ;Read and encrypt the data
  If CountList(Blocks()) > 0
   CallFunctionFast(*Callback,Str(CountList(Blocks()))+" block(s) were found.")
   ForEach Blocks()
    CallFunctionFast(*Callback,"Block start at offset: "+Str(Blocks()\StartOffset))
    CallFunctionFast(*Callback,"Block end at offset: "+Str(Blocks()\EndOffset))
    CallFunctionFast(*Callback,"Block length: "+Str(Blocks()\Length))
    *MemArea = AllocateMemory(Blocks()\Length)
    FileSeek(FLRH,Blocks()\StartOffset)
    ReadData(FLRH,*MemArea,Blocks()\Length)
    
    XorWithKey (*MemArea, Blocks()\Length, @EXE_Block_Key, Len(EXE_Block_Key)) 

    FileSeek(FLRH,Blocks()\StartOffset)
    WriteData(FLRH,*MemArea,Blocks()\Length)
    CallFunctionFast(*Callback,"Block patched...")
    FreeMemory(*MemArea)
   Next
   CallFunctionFast(*Callback,"")
  Else
   CallFunctionFast(*Callback,"No blocks found...")
  EndIf
  CallFunctionFast(*Callback,"Closing file...")
  CloseFile(FLRH)
  CallFunctionFast(*Callback,"Ready...")
 Else
  ProcedureReturn -1
 EndIf

EndProcedure

EncryptExecutablePieces("C:\Test.exe",@Callback())
Test executable

Code: Select all

;By Inf0Byt3, 10OCT07
;
;Based on code by Rings/Pdwyer/Franky/Wayne Diamond
;Mods/Fixes/Improvements by DoubleDutch/Thefool
;
;Free to use, credits appreciated
;It would be nice to improve it if you have time and if you want to share the knowledge
;
;Now with multi-label support ;)
;Don't forget to enable Inline ASM

Procedure XorWithKey (sText.l, LenText.l, sKey.l, LenKey.l) 
  XOR ecx, ecx 
  MOV esi, sText 
  MOV edi, sKey 
  MOV edx, LenText 
  MOV ebp, LenKey 
  ADD ebp, esi 
  xornextbyte: 
  MOV al, [esi] 
  MOV bl, [edi] 
  XOR al, bl 
  MOV [esi], al 
  INC ecx 
  INC esi 
  INC edi 
  CMP esi, ebp 
  JGE l_xorcomplete 
  CMP ecx, edx 
  JGE l_xornextround 
  JMP l_xornextbyte 
  xornextround: 
  XOR ecx, ecx 
  SUB edi, edx 
  JMP l_xornextbyte 
  xorcomplete: 
EndProcedure 

Procedure.l Scramble(StartAddress,Length)
 EXE_Block_Key.s = "this is the enc key"
 Mode = #PAGE_READWRITE
 Result=VirtualProtect_(StartAddress,Length,Mode,@OrigMode)
 XorWithKey (StartAddress,Length,@EXE_Block_Key,Len(EXE_Block_Key))
 VirtualProtect_(StartAddress,Length,OrigMode,Mode)
 ProcedureReturn 1
EndProcedure

;The code address
CStart = ?S1
CEnd = ?E1
CDiff = ?E1-?S1

Scramble(CStart,CDiff)

;Here's the protected code!
!_MarkBegin1 db $eb,$06,$eb,$fc,$eb,$fa,$eb,$f8
S1:
MessageRequester("","This code here is scrambled")
For t = 97 To 122
 a$ + Chr(t)
Next
MessageRequester("","Result "+a$)
E1:
!_MarkEnd1 db $eb,$04,$eb,$04,$eb,$fc,$eb,$fc
;The protected code ends here

MessageRequester("","OUT MWAHAHAHAHAHAHAHAHAHAHA")
Enjoy!

Posted: Tue Oct 16, 2007 3:22 pm
by DoubleDutch
Why do you have to implement a complex search when the whole search mask will fit in a quad?

That's why I made it 8 bytes long. :)

edit: I like the newer xor method though.

Posted: Tue Oct 16, 2007 3:24 pm
by Inf0Byt3
Yup, you are right, but the whole search/replace stuff was made before you added your corrected version :).

Posted: Tue Oct 16, 2007 3:25 pm
by DoubleDutch
If you use the quad search from bit I posted then the code will get a lot shorter. :)

Re: Encrypt code in exes (decrypt at runtime)

Posted: Tue Apr 13, 2010 7:32 pm
by PeterH
Excuse me for bumping.

For one, are there any verifications that the above code (except for the xor-encryption) still works? It seems interesting.
Using the correction I've posted in http://www.purebasic.fr/english/viewtop ... 62#p321431 this could be a pretty nice way to scare off the little amateur with a hex editor. Combined with other methods it could get pretty good.

The corrected xor-encryption routine:

UPDATED CODE (Fred reminded me of register preservation):

Code: Select all

Procedure XorWithKey (sText.l, LenText.l, sKey.l, LenKey.l)
  PUSHA
  MOV ebx, LenKey
  MOV ecx, LenText
  DEC ecx
  MOV edi, sKey
  MOV esi, sText
 xornextbyte:
  MOV eax, ecx
  CDQ
  DIV ebx
  MOV al, [edx + edi]
  XOR [ecx + esi], al
  DEC ecx
  JNS l_xornextbyte
  POPA
EndProcedure

Re: Encrypt code in exes (decrypt at runtime)

Posted: Fri Jan 14, 2011 3:20 pm
by sput
Doesn't work with PB 4.51

Can you post a working version ?

Thanks

Re: Encrypt code in exes (decrypt at runtime)

Posted: Fri Jan 14, 2011 5:34 pm
by ultralazor
A cracker will just use the stub to decrypt the blocks(which will stand out in most tools) and dump it.

If you want to do this proper just get PE pointer from 0x3C, then get entry point which is usually 4 bytes from that section, and insert stub there, and decrypt the entire code section. You can actually decrypt all sections from there, just make sure to change size offsets in header if you make them bigger, and make sure encrypted sections are writable.

How to improve it:
-RC5 encrypt resource section and realign if needed, also rename it
-VM with handler stub at OEP that decrypts VM entry points on the fly and creates timer threads on calls
-Have ring3 anti debugs inside VM
-VM handles all JMP, and CALL instructions
-use enduser labels for VM where blocks first goes through RC5 decryption then the VM which emulates JMP,CALL,CMP and more
-use many polymorphic functions
-insert garbage in VM blocks, code section(s) and a little in heaps
-implement some heap checksums

Also allow another label to insert some form of trigger. An make a VM scheme like a jump decrypts next one and encrypts self, and vm handles decrypted same way. Also some server auther where there is a keygen to decrypt the first VM handler or prompt and exit.

Armadillo is a joke BTW, they embed a DLL that actually helps the cracker bypass license. There is actually an up-to-date tool that does it for you. TheMida and SecurEngine and maybe VMProtect are the only ones that are remotely hard, and scripts exist for rebuilding latest versions with all options on..Securom and Starforce are just vm protectors with disc based crypt used on the VM.

You have to actually rebuild a PE protected with VM, crypter stubs you just run and dump. Skilled reversers will just publish scripts for rebuilding either way...this only hurts independent devs IMO cause it keeps the poor poor and the rich competing with the poor..economics

EDIT:All you have to do to defeat the latest code here is BP on unrecognized code in code section, step over it, then patch if needed and dump. A noob could do it in minutes with ollydbg. Also jump the stub, or wipe it and realign. Or even better inline patch it at runtime to use your own key :p

EDIT2:If anyone is interested in PB code that will VM+encrypt protect any EXE/DLL/SYS/SCR without having to write labels in the target code, then you can contact me; a solution for Linux and Mac ELF is also available with same features. I'm not interested in publishing one cause people don't want to pay license fees that cover the time developing it, and act like you lied when someone defeats it...

Re:

Posted: Tue Apr 26, 2011 10:05 pm
by 4RESTER
Rook Zimbabwe wrote:Not to flog a dead pony or anything, BUT!!!

With some slight revision of this you could create a Armadillo like Software security system.

:D
Armadillo is TOO EASY TO GET OFF :lol:

(I can break TEA/XTEA/XXTEA at seconds on the hardware "mate" somelike to "copacobana").

Re: Re:

Posted: Wed May 11, 2011 9:28 am
by ultralazor
4RESTER wrote:
Rook Zimbabwe wrote:Not to flog a dead pony or anything, BUT!!!

With some slight revision of this you could create a Armadillo like Software security system.

:D
Armadillo is TOO EASY TO GET OFF :lol:

(I can break TEA/XTEA/XXTEA at seconds on the hardware "mate" somelike to "copacobana").
why keygen and do crypto when you can just do a loader, or inline their DLL and rebuild? The DLL method bypasses nano and everything else..the loader methods works on the latest still and is noob-easy xD

If a protector isn't at least VM based with it's engine and keys encrypted using non-standard routines, then there are going to be very few people who can't defeat it with minimal effort and time..shareware level warez teams currently do any protector including dongle based inside a day, usually an hour with ones most 'skilled' people can't.

Only exception is some dongle ones that do isolated crypto properly, but these are rarely used..

methods shown here defeat themselves..breakpoint..jmp..done. PB compacts code around syscalls, making RCE even easier too.

Re: Encrypt code in exes (decrypt at runtime)

Posted: Sat Mar 31, 2012 12:24 am
by MisterDr
It is almost useless because you cannot encrypt functions.
Reason for that is because Fred is using macros to assemble ASM file ( macro MP6{
_Procedure6: ......... )

and after that he is calling macros at the end of ASM file so your code will end up like this:

Code: Select all

; !_MarkEnd1 db $ea,$04,$ea,$04,$ea,$fc,$ea,$fc
_MarkEnd1 db $ea,$04,$ea,$04,$ea,$fc,$ea,$fc
; 
_PB_EOP_NoValue:
  PUSH   dword 0
_PB_EOP:
  CALL  _PB_EndFunctions
  PUSH   dword [PB_MemoryBase]
  CALL  _HeapDestroy@4
  CALL  _ExitProcess@4
_PB_EndFunctions:
  CALL  _PB_FreeMemorys@0
  CALL  _PB_FreeLibraries@0
  CALL  _PB_FreeGadgets@0
  CALL  _PB_FreeWindows@0
  CALL  _PB_FreeImages@0
  CALL  _PB_EndAlphaImage@0
  RET
; 
MP4
MP72
MP14
MP16
MP18
MP50
MP52
MP56
MP58
MP8
MP78
MP80
MP82
MP86
MP102
MP88
MP104
MP70
MP106
MP90
MP108
MP92
MP94
MP112
MP54
MP64
MP74
MP110
MP76
MP84
MP100
MP96
MP98
MP68
MP128
MP130
MP134
MP132
MP62
MP60
MP116
MP124
MP122
MP120
MP126
MP114
MP118
MP66
MP136
MP146
MP154
MP138
MP162
MP2
MP164
MP0
And to achieve full encryption you need to put encryption routine in all procedures, also .data section is not encrypted so your key can be easily viewed from hex edit.

Re: Encrypt code in exes (decrypt at runtime)

Posted: Sat Mar 31, 2012 2:24 pm
by Thorium
MisterDr wrote: And to achieve full encryption you need to put encryption routine in all procedures, also .data section is not encrypted so your key can be easily viewed from hex edit.
I wouldnt care about the key at all. Just wait for the procedure to decrypt itself and then dump it.