+HCU's special Project: 'Our protections'
SELF32: THE SOLUTION
by +RCG, 14 January 1998
I have chosen this path to introduce +RCG's new essays because I believe
that our readers would be good adviced to 'deepen' first +RCG's self32 protection
(and to study +Zer0's solution to it) before attempting to go further.
SELF32: THE SOLUTION
The protection was perfectly explained by +Zer0, so I
will only comment how I was able to Create a Self-Modificable
code on the fly (I publish this because now I have some new info
and I can create real encrypted programms not using crafty
methods as you will see.)
How can we create a self-modificable code?
Look at this:
Code Segment
Call GetUserNAme
Call GetUserCode
Call Get_Password_With_Name_and_Code
Call Decrypt_Code
Call LoadDecryptedCode
Jump Decrypted_Code
Decrypted_Code:
dd 1000h dup (90) ;nops or whatever you like
LoadDecryptedCode:
push L NULL
push L FILE_ATTRIBUTE_NORMAL
push L OPEN_EXISTING
push L NULL
push L NULL
push L GENERIC_READ+GENERIC_WRITE
push offset DecryptedFileName
call CreateFileA ;Open file
cmp eax,-1
je File_Error
mov File_Handle,eax
push L NULL
push offset NbytesReaded
push L NumBytesToRead
push offset Decrypted_Code <==This is the bug
push [File_Handle]
call ReadFile
cmp eax,FALSE
je File_Error
ret
File_Error:
xor eax,eax
ret
ENDS
How W95 prevents this?
*Remember Kernel is at Segment 137h ==> Privilege
level 3. (137h=......11b) ==> 11b=3h
Setting a bpx at Readfile we will get this Code:
esp+18:null
esp+14:offset NbytesReaded
esp+10:NumBytesToRead
esp+0C:Destination (Decrypted_Code)
esp+08:File_Handle
esp+04:Return address
esp+00:BFF76ED7 (for ReadFile)
Exported fn(): ReadFile - Ord:0241h
:BFF75806 push BFF76ED7 ;go here at ret to read
:BFF7580B jmp BFF75812
Exported fn(): WriteFile - Ord:02E2h
:BFF7580D push BFF76E80 ;or here to write
:BFF75812 mov eax, dword ptr [esp+14] ;NBytesReaded
:BFF75816 push 00000004
:BFF75818 push eax
:BFF75819 call BFF784F0 ;IsBadHugeWritePtr
:BFF7581E test eax, eax
:BFF75820 jne BFF7582D
:BFF75822 mov eax, dword ptr [esp+14]
:BFF75826 mov dword ptr [eax], 00000000 ;Clear NbytesReaded
:BFF7582C ret ==> Go to Read/Write
:BFF7582D pop eax
:BFF7582E push 00000057
:BFF75830 call BFF7DACA ;SetLastError
:BFF75835 sub eax, eax
:BFF75837 ret 0014
ReadFile (BFF76ED7):
:BFF76ECF add esp, 00000004
:BFF76ED2 jmp BFF75B2E
.
.
:BFF76ED7 sub edx, edx ;ReadFile goes here
:BFF76ED9 push BFF9DF58 ;this let the stack equal
:BFF76EDE push dword ptr fs:[edx] ;This add 4, so:
esp+1C:null
esp+18:offset NbytesReaded
esp+14:NumBytesToRead
esp+10:Destination (Decrypted_Code)
esp+0C:File_Handle
esp+08:Return address
esp+04:BFF76ED7 (for ReadFile)
esp+00:dword ptr fs:[edx]
:BFF76EE1 mov dword ptr fs:[edx], esp
:BFF76EE4 mov eax, dword ptr [esp+10] ;Destination
:BFF76EE8 mov ecx, dword ptr [esp+14] ;NbytesToRead
:BFF76EEC jcxz BFF76F05 ;Read zero bytes?
:BFF76EEE dec ecx
:BFF76EEF lea ecx, dword ptr [ecx+eax] ;ecx=end of destination
:BFF76EF2 add byte ptr [ecx], 00 ;E Voila!!!!
;if destination is code segment then
;write into it is forbidden and
;an exception is generated and trapped
;by the OS giving us the error code.
:BFF76EF5 cmp eax, ecx ;Is end of dest.=begin of dest.
:BFF76EF7 je BFF76F05
:BFF76EF9 add byte ptr [eax], 00 ;try to write at
:BFF76EFC add eax, 00001000 ;next page of 4Kb
:BFF76F01 cmp eax, ecx ;Finished?
:BFF76F03 jb BFF76EF9
:BFF76F05 mov ecx, dword ptr [esp+18] ;NbytesReaded
:BFF76F09 add dword ptr [ecx], 00000000 ;Again with
;NbytesReaded
:BFF76F0C mov ecx, dword ptr [esp+1C] ;Overlapped struct
:BFF76F10 jcxz BFF76F19 ;if null go and read
:BFF76F12 add byte ptr [ecx], 00 ;else check begin and
:BFF76F15 add byte ptr [ecx+13], 00 ;end of structure
:BFF76F19 pop dword ptr fs:[edx]
:BFF76F1C add esp, 00000004 ;restore true return address
:BFF76F1F jmp BFF7583A ;go read
All right, now we know where is the problem, so we can
try to jump directly to BFF7583A.
How to get the correct jump?...look!!!
GetJmp:
mov esi,[CFile] ;ReadFile jmp offset in data.
mov esi,[esi] ;ReadFile jmp offset in program.
mov esi,[esi] ;ReadFile jmp in dll (1st push)
mov esi,[esi+1] ;Get 2nd push value (BFF76ED7)
NOK: mov al,[esi]
cmp al,0E9h ;check for jmp opcode
je OK
inc esi
jmp NOK
OK: mov CFile,esi ;now esi is the direct jmp. add.
ret
Final comment, try to put any address like C0110000 (VxD
addresses) and you will see there are no problems, you
can modify VxD without restrictions (is this a bug?).... and
we can prevent SoftIce using this 'bug'....work on it!!!!!!
My Kernel Version is 4.00.950 but I have downloaded other
versions and all worked.... also I have discovered that some
versions were patched preventing this fact (why?????).
Well, like +Zer0 said this way is a little hard to implement
in High Level Languages, but now we are going to implement
it very easily.
Back to Our protections
No, no, no! I want to go FURTHER and read +RCG's new essay:
CRYPTOGRAPHY AND MATHEMATICS OF CHAOS!
No, no, no! I want to go FURTHER and read +RCG's new essay:
A FIRST INTRODUCTION TO VxD!