²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ²² ____ __ __ ²²ßÛ ²² / _/_ _ __ _ ___ ____/ /____ _/ / ²² ÛßÛ ²² _/ // ' \/ ' \/ _ \/ __/ __/ _ `/ / ²² Û Û ²² /___/_/_/_/_/_/_/\___/_/ \__/\_,_/_/ ²² Û Û ²² ____ __ __ ²² Û Û ²² / __ \___ ___ _______ ___ ___/ /__ ____ / /____ ²² Û Û ²² / /_/ / -_|_-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