    
             ____                     __       __                
            /  _/_ _  __ _  ___  ____/ /____ _/ /                 
           _/ //  ' \/  ' \/ _ \/ __/ __/ _ `/ /                   
          /___/_/_/_/_/_/_/\___/_/  \__/\_,_/_/                    
            ____                          __          __           
           / __ \___ ___ _______ ___  ___/ /__ ____  / /____       
          / /_/ / -_|_-</ __/ -_) _ \/ _  / _ `/ _ \/ __(_-<       
         /_____/\__/___/\__/\__/_//_/\_,_/\_,_/_//_/\__/___/       
                                                                   
     Web: http://www.immortaldescendants.org                       
     EFnet: #immortaldescendants                                   
     Author: Muad'Dib [ muaddib@immortaldescendants.org ]          
     Topic: Securing Sentry                                        
     Date: 4/18/2000                                               
     Level:                                                        
     ( ) Beginner (X) Intermediate (X) Advanced ( ) Expert         
                                                                   
      
      
        






Source code and additional links:
http://www.immortaldescendants.org/
http://playtools.cjb.net/ - Procdump/SoftICE/W32DASM/HIEW
http://neudump.cjb.net/ - OPGen
http://muad.cjb.net/
http://www.spytech-web.com/ - Sentry



The long awaited tutorial is finally here!  Come one come all
to watch the splendor we call REVERSING!

Actually I've been procrastinating this for quite some time so
I think it is a welcome tutorial (especially to Volatility :).

Tools needed:
SoftICE
IDA or W32DASM (I use IDA)
HIEW or Hex Workshop (I used both for some reason :)
OPGen
Procdump

Here goes:


Enter your sentry password and enable it.  You will get a message
saying "Sentry lockdown has been enabled".  Disable it and then
disassemble sentry.  Search for the string that says sentry has
been enabled.

We get this:

.text:00403115 6A 30                   push    30h
.text:00403117 68 04 B5 40 00          push    offset aTheSentry_0; "The Sentr
.text:0040311C 68 10 B6 40 00          push    offset aTheSentryHasNo; "The Se
.text:00403121 FF B4 24 4C 03 00 00    push    dword ptr [esp+34Ch]
.text:00403128 FF 15 1C 92 40 00       call    ds:MessageBoxA


Now, if you remember from my previous tutorial the serial is
stored in "c:\windows\system\qtime20.dat".  If we page up a bit
we find some relevant code:

.text:00402F24 50                      push    eax
.text:00402F25 57                      push    edi
.text:00402F26 55                      push    ebp
.text:00402F27 68 2C C1 40 00          push    offset unk_0_40C12C
.text:00402F2C 53                      push    ebx
.text:00402F2D 53                      push    ebx
.text:00402F2E FF 15 2C 91 40 00       call    ds:GetPrivateProfileStringA
.text:00402F34 FF 35 44 C1 40 00       push    dword_0_40C144


Lets look up GetPrivateProfileString in our API guide and check
which paramater the serial will be stored in (remember LIFO).  When
we look in the API guide we see this:

DWORD GetPrivateProfileString(

    LPCTSTR lpAppName,	// points to section name 
    LPCTSTR lpKeyName,	// points to key name 
    LPCTSTR lpDefault,	// points to default string 
    LPTSTR lpReturnedString,	// points to destination buffer 
    DWORD nSize,	// size of destination buffer 
    LPCTSTR lpFileName 	// points to initialization filename 
   );	

Looking at the code, EBP contains our password.  Now lets overwrite
the push that comes after GetPrivateProfileStringA because we can always
put that back later.

Now comes Procdump.  Open up sentry.exe with Procdump and click the
"sections" button.  The raw offset is 1000 and the size is 784A.  Open
sentry.exe in your hex editor and go to the offset 884A (1000 + 784A).
Well would you look at that, we have a bunch of null bytes!  Go to the
offset 2F34 (402F34 - 400000).  Now it's time for Opgen.  Opgen will
generate a jump for you.  Since the end of the code is 884A, we want 
to jump from 2F34 to 884A.  Opgen gives us this:

E9 11 59 00 00

But first we want to note down the old opcode so we can add it again:

FF 35 44 C1 40 00

Since the new opcode is 1 byte less than the old one we add a nop at the
end:

E9 11 59 00 00 90

Now we need to make a stupid little encryption code that is strong enough
to keep our little sisters and our mothers out.

.386
code32 segment para public use32
assume cs:code32,ds:code32
org 100h
main:
pushad
looper:
mov al,byte ptr [ebp]
cmp al,0
je endit
xor al,'' ; (238)
mov byte ptr [ebp],al
inc ebp
jmp looper
endit:
popad

code32 ends
end main

Compile this with TASM:

C:\id\projects\sentry>tasm stupid.asm
Turbo Assembler  Version 4.1  Copyright (c) 1988, 1996 Borland International

Assembling file:   stupid.ASM
Error messages:    None
Warning messages:  None
Passes:            1
Remaining memory:  443k


C:\id\projects\sentry>tlink /t stupid.obj
Turbo Link  Version 7.1.30.1. Copyright (c) 1987, 1996 Borland International

And open the file in your hex editor.  You will get the following bytes
of code:

60 8A 45 00 3C 00 74 0C 90 90 90 90-34 8C 88 45 00 45 EB ED 61


Insert this code and then insert our old push:

FF 35 44 C1 40 00

Then we have to jump back (8865 to 2F3A):

E9 D0 A6 FF FF

Well, now that we've got this done, the rest should be easy.  The
next name checking portion uses the exact same code so lets overwrite
the push again and use the almost the exact same bit of code.

.text:004031D3                 push    eax
.text:004031D4                 push    edi
.text:004031D5                 push    ebp
.text:004031D6                 push    offset unk_0_40C12C
.text:004031DB                 push    ebx
.text:004031DC                 push    ebx
.text:004031DD                 call    ds:GetPrivateProfileStringA
.text:004031E3                 push    dword_0_40C144

We want to overwrite the push at 31E3 with a jump to 886A:

E9 82 56 00 00 90

And then insert our code:

60 8A 45 00 3C ... etc

And then jump back to 31E9 from 8885:

E9 5F A9 FF FF

That's that.  Now we have to edit the password changing portion (don't
worry, we're almost done ;).  Search for "Sentry password has been" in
your disassembly and you come up with this:

.text:00401F7A                 push    30h
.text:00401F7C                 push    offset aPasswordChange
.text:00401F81                 push    offset aSentryPassword
.text:00401F86                 push    esi


If we page up a bit we get this:

Wait a minute!  The GetPrivateProfileStringA call is missing!  This looks
like a job for SoftICE!  Open up your sentry (edited or otherwise) and
put a bpx on GetPrivateProfileStringA.  Click "Options/Passwords" and it
will break.  Note the offset and go to your disassembly (It's just easier :)
This is what we see:

.text:004020A5 68 E0 C7 40 00          push    offset unk_0_40C7E0
.text:004020AA 68 FF 00 00 00          push    0FFh
.text:004020AF 68 E0 CA 40 00          push    offset unk_0_40CAE0
.text:004020B4 68 2C C1 40 00          push    offset unk_0_40C12C
.text:004020B9 68 B8 B2 40 00          push    offset a1 ; "1"
.text:004020BE 68 B8 B2 40 00          push    offset a1 ; "1"
.text:004020C3 FF 15 2C 91 40 00       call    ds:GetPrivateProfileStringA
.text:004020C9 BF E0 CA 40 00          mov     edi, offset unk_0_40CAE0


So the password is stored in 40CAE0 and then put into EDI.  Looks like we
will have to overwrite "mov edi, offset unk_0_40CAE0".  We can always
replace it at the memory location our code jumps to.  So we need to jump
from 20C9 to 888A:

E9 BC 67 00 00

Remember to write down the old opcode for the mov so we can replace it.  Now
put the old opcode in starting at 888A.

Now we need to modify our code a bit so that it uses EDI.

.386
code32 segment para public use32
assume cs:code32,ds:code32
org 100h
main:
pushad
looper:
mov al,byte ptr [edi]
cmp al,0
je endit
xor al,'' ; (238)
mov byte ptr [edi],al
inc edi
jmp looper
endit:
popad

code32 ends
end main

Compile it and we get the following series of bytes:

60 8A 07 3C 00 74 0B 90 90 90 90 34 8C 88 07 47 EB EF 61

Let's just put this right on in....

Got it?  Good job.  Now once again lets jump back to the old location
(88A2 to 20CE):

E9 27 98 FF FF

Now lets go back up and make our last change!

.text:00401F91 68 E0 C7 40 00          push    offset unk_0_40C7E0
.text:00401F96 50                      push    eax
.text:00401F97 68 B8 B2 40 00          push    offset a1 ; "1"
.text:00401F9C 68 B8 B2 40 00          push    offset a1 ; "1"
.text:00401FA1 FF 15 84 90 40 00       call    ds:WritePrivateProfileStringA


Time to take another look at our API guide:

BOOL WritePrivateProfileString(

    LPCTSTR lpAppName,	// pointer to section name 
    LPCTSTR lpKeyName,	// pointer to key name 
    LPCTSTR lpString,	// pointer to string to add 
    LPCTSTR lpFileName 	// pointer to initialization filename 
   );


Looks like EAX is the password. Time to modify the code again:

.386
code32 segment para public use32
assume cs:code32,ds:code32
org 100h
main:
pushad
looper:
mov al,byte ptr [eax]
cmp bl,0
je endit
xor bl,'' ; (238)
mov byte ptr [eax],bl
inc eax
jmp looper
endit:
popad

code32 ends
end main

This time we have to use "BL" as the byte register that holds the letter
being changed because EAX is being taken by the name.  Compile it and get
this:

60 8A 18 80 FB 00 74 0C 90 90 90 90-80 F3 8C 88 18 40 EB ED 61


We can overwrite the call to WritePrivateProfileStringA at 1FA1 and replace
it later.  Make a jump from 1FA1 to 88A7:

E9 01 69 00 00 90 

We do the nop because the call is 1 byte longer than the jump. Make sure you
wrote down the opcode for calling WritePrivateProfileStringA.

Just add our encryption code and then jump back from 88C2 to 1FA7:

E9 E0 96 FF FF

That's it!  We're done!  Just a bit of janitorial work to do.  Erase the file
c:\windows\system\qtime20.dat and then open up your modified sentry.  Set a
new password and then test everything out!  It all works!

Enjoy!

Very special thanks go out to Carpathia for helping me when I was a wee 
reverser! Thanks to Volatility for being a good friend and a great leader!  
Thanks to NeuRaL_NoiSE for making OPGen and thanks to G-RoM, Lorian, and 
Stone for Procdump, another excellent tool!

Greetings go out to WarezPup, TheSmurf, Prophecy, nchanta, Dawai, JosephC, 
grrrman, Nitrus, noos, night, quantico, sortof, everyone in uCF and tNO, 
everyone in The Immortal Descendants, and everyone I know and may have 
forgotten!

-Muad'Dib