unit Unit1; { CPHack v0.1.0 by Eddy L O Jansson / Released under the GPL. (my first real Delphi App, so no flames please :-) History =========================================================================== 0.0.1 eloj Preview #1 0.0.2 eloj Preview #2 0.0.3 eloj Internal 0.1.0 2000-03-11 eloj Last compile before first public release ToDo =========================================================================== * Do a nice 'free' of allocated memory on exit. * Fix the dictionary attacks to always be 'smart'. } interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, Menus, INIFiles, Clipbrd, ExtCtrls, ShellAPI, WinSock, CRC32, unitURLEntry, LexiconClass, HashStr; { my units } const VERSIONSTRING: String[8]='0.1.0'; type TForm1 = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Exit1: TMenuItem; N1: TMenuItem; Open1: TMenuItem; OpenDialog1: TOpenDialog; PageControl1: TPageControl; TabSheet1: TTabSheet; UserView: TListView; TabSheet2: TTabSheet; NewsList: TListView; Bevel1: TBevel; OpenNOTlist1: TMenuItem; TabSheet3: TTabSheet; GroupCat: TGroupBox; CatBox0: TCheckBox; CatBox1: TCheckBox; CatBox2: TCheckBox; CatBox3: TCheckBox; CatBox4: TCheckBox; CatBox7: TCheckBox; CatBox6: TCheckBox; CatBox5: TCheckBox; CatBox8: TCheckBox; CatBox9: TCheckBox; CatBox10: TCheckBox; CatBox11: TCheckBox; CatBox12: TCheckBox; CatBox13: TCheckBox; CatBox14: TCheckBox; CatBox15: TCheckBox; TabSheet4: TTabSheet; IPView: TTreeView; IPAliasPopup: TPopupMenu; GoTo1: TMenuItem; Lookup1: TMenuItem; LookupAll1: TMenuItem; Exporthosts1: TMenuItem; N2: TMenuItem; Importhosts1: TMenuItem; SaveDialog1: TSaveDialog; Lookuprootnodes1: TMenuItem; N3: TMenuItem; Generatereport1: TMenuItem; InfoLabel1: TLabel; InfoLabel2: TLabel; TabSheet5: TTabSheet; ConfigBox: TGroupBox; CfgDefaultPathEdit: TEdit; CfgDefaultPathLbl: TLabel; CfgLexiconLbl: TLabel; CfgLexiconEdit: TEdit; CfgReCheckNoAnswer: TCheckBox; CfgDefaultPathButton: TButton; CfgLexiconButton: TButton; CfgSaveButton: TButton; CfgLoadButton: TButton; CfgPrefixLabel: TLabel; CfgPrefixEdit: TEdit; CfgPrefixButton: TButton; CfgSuffixEdit: TEdit; CfgSuffixButton: TButton; CfgSuffixLbl: TLabel; URLView: TTreeView; URLPopup: TPopupMenu; URLOpen: TMenuItem; URLLookupIP: TMenuItem; URLLookupBranch: TMenuItem; URLLexiconURL: TMenuItem; URLLexiconBranch: TMenuItem; CFGSuffixEnabled: TCheckBox; CfgPrefixEnabled: TCheckBox; ProgressBar: TProgressBar; Bevel2: TBevel; TheCancelButton: TButton; ProgressLabel: TLabel; URLGroupCat: TGroupBox; Cat2Box0: TCheckBox; Cat2Box1: TCheckBox; Cat2Box2: TCheckBox; Cat2Box3: TCheckBox; Cat2Box4: TCheckBox; Cat2Box7: TCheckBox; Cat2Box6: TCheckBox; Cat2Box5: TCheckBox; Cat2Box8: TCheckBox; Cat2Box9: TCheckBox; Cat2Box10: TCheckBox; Cat2Box11: TCheckBox; Cat2Box12: TCheckBox; Cat2Box13: TCheckBox; Cat2Box14: TCheckBox; Cat2Box15: TCheckBox; CfgExcludeURLs: TCheckBox; CfgExcludeIPAliases: TCheckBox; CfgExcludeNewsgroups: TCheckBox; URLLexiconWholeTree: TMenuItem; Exportdictionary1: TMenuItem; URLLookupforward1: TMenuItem; CFGLockURLs: TCheckBox; ExportURLhashes1: TMenuItem; URLStatbox: TGroupBox; URLStatLbl1: TLabel; URLStatBar: TProgressBar; URLGotonextfullURL1: TMenuItem; ExportunresolvedIPs1: TMenuItem; CFGSkipNoAnswerOnImport: TCheckBox; Bevel4: TBevel; InfoHeader: TStaticText; MyHomepage: TStaticText; N4: TMenuItem; Smartdictionaryattack1: TMenuItem; SearchEdit: TEdit; SearchButton: TButton; CFGExclURLNotLookup: TCheckBox; CFGExclURLHashes: TCheckBox; Locatemaskedas1: TMenuItem; Intolerance1: TMenuItem; ViolenceProfanity1: TMenuItem; PartialNudity1: TMenuItem; Fullnudity1: TMenuItem; SexualactsText1: TMenuItem; GrossdepictionsText1: TMenuItem; SatanicCult1: TMenuItem; DrugsDrugculture1: TMenuItem; MilitantExtremist1: TMenuItem; Sexeducation1: TMenuItem; QuestionableIllegalGambling1: TMenuItem; Alcoholtobacco1: TMenuItem; Reserved41: TMenuItem; Reserved31: TMenuItem; Reserved21: TMenuItem; Reserved11: TMenuItem; procedure Exit1Click(Sender: TObject); procedure Open1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure OpenNOTlist1Click(Sender: TObject); procedure NewsListSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); procedure IPViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Lookup1Click(Sender: TObject); procedure LookupAll1Click(Sender: TObject); procedure Importhosts1Click(Sender: TObject); procedure Exporthosts1Click(Sender: TObject); procedure Lookuprootnodes1Click(Sender: TObject); procedure Generatereport1Click(Sender: TObject); procedure CfgSaveButtonClick(Sender: TObject); procedure CfgLoadButtonClick(Sender: TObject); procedure CfgDefaultPathButtonClick(Sender: TObject); procedure CfgLexiconButtonClick(Sender: TObject); procedure CfgPrefixButtonClick(Sender: TObject); procedure CfgSuffixButtonClick(Sender: TObject); procedure GoTo1Click(Sender: TObject); procedure URLOpenClick(Sender: TObject); procedure URLViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure URLLexiconURLClick(Sender: TObject); procedure URLViewChange(Sender: TObject; Node: TTreeNode); procedure URLLexiconBranchClick(Sender: TObject); procedure URLLexiconWholeTreeClick(Sender: TObject); procedure Exportdictionary1Click(Sender: TObject); procedure TheCancelButtonClick(Sender: TObject); procedure URLLookupIPClick(Sender: TObject); procedure URLGotonextfullURL1Click(Sender: TObject); procedure ExportunresolvedIPs1Click(Sender: TObject); procedure ExportURLhashes1Click(Sender: TObject); procedure URLLookupBranchClick(Sender: TObject); procedure URLLookupforward1Click(Sender: TObject); procedure MyHomepageClick(Sender: TObject); procedure Smartdictionaryattack1Click(Sender: TObject); procedure SearchButtonClick(Sender: TObject); procedure SearchEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure LocateCatByTag(Sender: TObject); private { Private declarations } public { Public declarations } end; const NODE_IS_NET = 0; NODE_IS_IP = 1; NODE_IS_URL = 2; NODE_IS_UNKNOWN = 255; Categories :Array[0..$F] of String[34]=( 'Violence / Profanity', 'Partial Nudity', 'Full Nudity', 'Sexual Acts / Text', 'Gross Depictions / Text', 'Intolerance', 'Satanic or Cult', 'Drugs / Drug Culture', 'Militant / Extremist', 'Sex Education', 'Questionable / Illegal & Gambling', 'Alcohol & Tobacco', 'Reserved 4', 'Reserved 3', 'Reserved 2', 'Reserved 1'); (* This answers the question: how many freely-chosen bits do I include * when I ask for a crc collision with input length (index)? *) freebits: Array[0..11] of Byte=(0,0,0,0,1,4,10,16,22,28,34,40); (* This says where each forced bit goes *) bitsforced: Array[0..31] of Byte=(0,1,2,3,4,6, 8,9,10,11,12,14,16,17,18,19,20,22,24,25,26,27,28,30, 32,33,34,35,38,40,41,42); (* This says where each free bit goes *) bitsfree: Array[0..39] of Byte=(36,43,44,46,48,49,50,51,52,54, 56,57,58,59,60,62,64,65,66,67,68,70,72,73,74,75,76,78,80,81, 82,83,84,86,88,89,90,91,92,94); (* The portion of the inverted matrix corresponding to the CRC bits *) crcmatrix: Array[0..31] of Cardinal=( $9BF7B4FE,$10CEBBDB,$3EC28E73,$E516F5B2, $3EB07172,$AC6CB91B,$2344667F,$25ECE58C, $D24109C4,$501CB10A,$97761211,$0A2EF700, $0C806D13,$55AE3901,$4C147270,$DAC3C857, $384B8A54,$F7583CAD,$A1DA1DC4,$0028BBDC, $B5BB7FE3,$99610C1A,$1FC446C4,$8DE0FF05, $01D3D128,$64FAC9B2,$3BC5E604,$E564A85C, $ADEB84A5,$CFCDBB2B,$3E7D9F68,$A102B971); (* The portion of the inverted matrix corresponding to the free bits *) freematrix: Array[0..39] of Cardinal=( $0CBFC054,$AEAB35B2,$315B20B2,$1F113696, $6DA65FB4,$08F3CFCD,$C0E8FCF1,$D928FA77, $58C085F6,$55F7A6A4,$726948CB,$BEE706A6, $DE9BCF28,$539FADD8,$A5D7713D,$A6B4900F, $3CA9547B,$C98AC9B5,$AF52FA18,$60098F5B, $142D2C51,$706AA085,$46494250,$54026BCE, $EBE4D0A3,$673646B9,$945A22D6,$7C5347FB, $C61C9B99,$97780ADB,$7E9DB1AE,$88C43E39, $55CEBFB3,$5C81ADC9,$0F3DD57C,$3D44BCF3, $0383F8DD,$73F38757,$A8F2D5CF,$2922BEA9); (* Matrix columns to take into account the canonicalization *) lengthmatrix: Array[0..11] of Cardinal=( $84741063,$C5273406,$E5A222DF,$9941CB2B, $D9EBE522,$CB93A8AF,$962E3D2D,$90029144, $5B298B04,$575F1D8A,$78EE4BEC,$47B6B86A); type PTArrayByte = ^TArrayByte; TArrayByte = Array[0..MaxLongInt-1] of Byte; PTNOTHeader = ^TNOTHeader; TNOTHeader = Packed Record Filetype :Word; HeaderSize :Word; HeaderID :Array[0..1] of Char; unknown1, unknown2, unknown3 :Word; TblEntries :SmallInt; end; PTNOTHeaderEntry = ^TNOTHeaderEntry; TNOTHeaderEntry = Packed Record TblType :Word; Offset :LongInt; Size :LongInt; end; TNewsgroupEntry = Record { internal only } Len :Byte; Cat :Word; ng :String; end; var Form1: TForm1; CfgINIFilename :String; CurrNOTTbl :Byte; F :File; INIBuf :PTArrayByte; INIBufSize :Integer; NOTBuf :PTArrayByte; NOTBufSize :Integer; NOTHeader :PTNOTHeader; NOTHeaderEntry :PTNOTHeaderEntry; Users, Passwords, Newsgroups :TStrings; StatisticsTotalURLHashes :LongInt; implementation {$R *.DFM} Function St(const I :LongInt): String; var s: String[10]; begin Str(I,S); St:=S; end; Function Va(const s: string): longint; var code: Integer; vas: Longint; begin Val(s,vas,code); Va:=vas end; Function LZ(tal: longint;antal: byte): String; var temp: String[20]; begin Str(tal,Temp); While length(temp)1) and (s[length(S)]<>'\') do Delete(S,Length(S),1); GetProgramPath:=S; end; Function ror(i: byte): byte; Assembler; asm mov al,i ror al,1 end; { Straigt conversion of Matthew Skala's original code } Function BreakHash(const hash1,hash2: Cardinal): String; var found :Boolean; res :String; gothash1, gothash2 :Cardinal; length,bflip,i :Integer; freeb :Array[0..5] of Char; plaintext :Array[0..11] of Char; Function GETBIT(const S: Array of Char;b :Byte): Byte; begin GetBit:=((ord(S[(b shr 3)]) shr (b and 7))) and 1; end; Procedure FLIPBITR(var S: Array of Char;b :Byte); begin if (length-1-(b shr 3))>=0 then S[length-1-(b shr 3)]:=char(ord((S[length-1-(b shr 3)])) xor (1 shl (b and 7))); end; Procedure FLIPBIT(var S: Array of Char;b :Byte); begin S[(b shr 3)]:=char(ord(S[(b shr 3)]) xor (1 shl (b and 7))); end; Procedure reverse_crc(const crc,length: Longint;var sin,sout: Array of Char); var bits :Cardinal; i :LongInt; begin { correct for output length } bits:=lengthmatrix[length-1]; { XOR in the CRC } for i:=0 to 31 do if (crc AND (1 SHL i))<>0 then bits:=bits XOR crcmatrix[i]; { XOR in the free bits } for i:=0 to freebits[length-1]-1 do if GETBIT(sin,i)<>0 then bits:=bits XOR freematrix[i]; { Set up output } for i:=0 to length-1 do sout[i]:=#$20; { output forced bits } for i:=0 to 31 do if (bits AND (1 SHL i))<>0 then FLIPBITR(sout,bitsforced[i]); { output free bits } for i:=0 to freebits[length-1]-1 do if GETBIT(sin,i)<>0 then FLIPBITR(sout,bitsfree[i]); end; Procedure cp_hash(const s: Array of Char;const length: Integer;var h1,h2: cardinal); var i :integer; ch :Byte; begin h1:=0; h2:=0; for i:=0 to length-1 do begin ch:=ord(s[i]) or $20; h1:=(h1 shr 8) xor crctable[(h1 and $FF) xor ch]; h2:=(((h2 shl 5) or (h2 shr $1B))+ch)-h1; end; end; begin res:=''; found:=false; for length:=1 to 8 do begin for i:=0 to 5 do freeb[i]:=#0; bflip:=0; repeat reverse_crc(hash1,length,freeb,plaintext); cp_hash(plaintext,length,gothash1,gothash2); if (hash1=gothash1) and (hash2=gothash2) then begin Setlength(res,length); for i:=0 to length-1 do res[i+1]:=plaintext[i]; found:=true; break; end; bflip:=0; while GETBIT(freeb,bflip)<>0 do begin FLIPBIT(freeb,bflip); Inc(bflip); end; FLIPBIT(freeb,bflip); until (bflip>=freebits[length-1]); if found then break; end; BreakHash:=res; end; Procedure SaveConfiguration(const fn: String); var DelphiIni :TIniFile; begin DelphiIni:=TIniFile.Create(fn); DelphiIni.WriteString('cphack','DefaultPath',Form1.CfgDefaultPathEdit.Text); DelphiIni.WriteString('cphack','Lexicon',Form1.CfgLexiconEdit.Text); DelphiIni.WriteString('cphack','PrefixFile',Form1.CfgPrefixEdit.Text); DelphiIni.WriteString('cphack','SuffixFile',Form1.CfgSuffixEdit.Text); DelphiIni.WriteBool('cphack','SuffixEnabled',Form1.CfgSuffixEnabled.Checked); DelphiIni.WriteBool('cphack','PrefixEnabled',Form1.CfgPrefixEnabled.Checked); DelphiIni.WriteBool('cphack','ExcludeNGs',Form1.CfgExcludeNewsgroups.Checked); DelphiIni.WriteBool('cphack','ExcludeIPAliases',Form1.CfgExcludeIPAliases.Checked); DelphiIni.WriteBool('cphack','ExcludeURLs',Form1.CfgExcludeURLs.Checked); DelphiIni.WriteBool('cphack','ExcludeNotRevIP',Form1.CFGExclURLNotLookup.Checked); DelphiIni.WriteBool('cphack','ExcludeNotRevHash',Form1.CFGExclURLHashes.Checked); DelphiIni.WriteBool('cphack','ReCheckNoAns',Form1.CfgReCheckNoAnswer.Checked); DelphiIni.WriteBool('cphack','LockFoundURLs',Form1.CfgLockURLs.Checked); DelphiIni.WriteBool('cphack','SkipNoAnswerImport',Form1.CFGSkipNoAnswerOnImport.Checked); Form1.ProgressLabel.Caption:='Configuration saved.'; Form1.ProgressLabel.Refresh; DelphiIni.Destroy; end; Procedure LoadConfiguration(const fn: String); var DelphiIni :TIniFile; begin DelphiIni:=TIniFile.Create(fn); Form1.CfgDefaultPathEdit.Text:=DelphiIni.ReadString('cphack','DefaultPath',Form1.CfgDefaultPathEdit.Text); Form1.CfgLexiconEdit.Text:= DelphiIni.ReadString('cphack','Lexicon',Form1.CfgLexiconEdit.Text); Form1.CfgPrefixEdit.Text:= DelphiIni.ReadString('cphack','PrefixFile',Form1.CfgPrefixEdit.Text); Form1.CfgSuffixEdit.Text:= DelphiIni.ReadString('cphack','SuffixFile',Form1.CfgSuffixEdit.Text); Form1.CfgSuffixEnabled.Checked:=DelphiIni.ReadBool('cphack','SuffixEnabled',Form1.CfgSuffixEnabled.Checked); Form1.CfgPrefixEnabled.Checked:=DelphiIni.ReadBool('cphack','PrefixEnabled',Form1.CfgPrefixEnabled.Checked); Form1.CfgExcludeNewsgroups.Checked:=DelphiIni.ReadBool('cphack','ExcludeNGs',Form1.CfgExcludeNewsgroups.Checked); Form1.CfgExcludeIPAliases.Checked:=DelphiIni.ReadBool('cphack','ExcludeIPAliases',Form1.CfgExcludeIPAliases.Checked); Form1.CfgExcludeURLs.Checked:=DelphiIni.ReadBool('cphack','ExcludeURLs',Form1.CfgExcludeURLs.Checked); Form1.CFGExclURLNotLookup.Checked:=DelphiIni.ReadBool('cphack','ExcludeNotRevIP',Form1.CFGExclURLNotLookup.Checked); Form1.CFGExclURLHashes.Checked:=DelphiIni.ReadBool('cphack','ExcludeNotRevHash',Form1.CFGExclURLHashes.Checked); Form1.CfgLockURLs.Checked:=DelphiIni.ReadBool('cphack','LockFoundURLs',Form1.CfgLockURLs.Checked); Form1.CfgReCheckNoAnswer.Checked:=DelphiIni.ReadBool('cphack','ReCheckNoAns',Form1.CfgReCheckNoAnswer.Checked); Form1.CFGSkipNoAnswerOnImport.Checked:=DelphiIni.ReadBool('cphack','SkipNoAnswerImport',Form1.CFGSkipNoAnswerOnImport.Checked); Form1.ProgressLabel.Caption:='Configuration loaded.'; DelphiIni.Destroy; end; Procedure Decrypt(var Buf: PTArrayByte;const BufSize: LongInt); var key :Byte; i,j :LongInt; begin key:=BufSize AND $FF; for j:=0 to 1 do for i:=0 to BufSize-1 do begin key:=ror(key); buf^[i]:=buf^[i] xor key; key:=buf^[i]; end; end; Function Array8ToStr(const BinBuf: PTArrayByte): String; var S :String[8]; i :Byte; begin for i:=1 to 8 do S[i]:=Char(BinBuf^[i-1]); S[0]:=#8; Array8ToStr:=S; end; Procedure HexaToArray8(const S: String;var BinBuf: PTArrayByte); var i :Byte; s1 :String[3]; begin for i:=0 to 7 do begin s1:='$'+S[1+(i*2)]+S[1+((i*2)+1)]; BinBuf^[i]:=Byte(Va(s1)); end; end; Procedure SplitHostIPs(const HIPs: String;var Host,IP: String); var i :Byte; begin host:=''; IP:=''; i:=Pos('(',HIPs); if i=0 then begin IP:=HIPs; end else begin host:=Copy(HIPs,1,pos(' ',HIPs)-1); IP:=Copy(HIPs,i+1,pos(')',HIPs)-i-1); end; end; Function HostIPsToIPs(const HIPs: String): String; var i :Byte; s :String; begin i:=Pos('(',HIPs); if i=0 then begin s:=HIPs end else begin s:=Copy(HIPs,i+1,pos(')',HIPs)-i-1); end; HostIPsToIPs:=s; end; Function ReverseHash(var BinBuf: PTArrayByte): String; begin ReverseHash:=''; end; Function ReverseLookupIPs(IPs :String): String; var MyIP :Pointer; aIP :LongInt; p :PHostEnt; begin aIP:=inet_addr(pchar(IPs)); MyIP:=@aIP; p:=gethostbyaddr(myIP,4,AF_INET); if (p=nil) then ReverseLookupIPs:='' else ReverseLookupIPs:=String(p^.h_name); Application.ProcessMessages; end; Function SelectAPath(const spath: String): String; begin With Form1.OpenDialog1 do begin DefaultExt:=''; Filename:=''; Filter:='All files (*.*)|*.*'; InitialDir:=spath; Title:='Choose a file'; if Execute then result:=GetProgramPath(Form1.OpenDialog1.FileName) else result:=spath; end; end; Function SelectAFile(const aTitle: String;var spath: String): Boolean; begin With Form1.OpenDialog1 do begin DefaultExt:=''; Filename:=''; Filter:='All files (*.*)|*.*'; InitialDir:=spath; Title:=aTitle; if Execute then begin spath:=Form1.OpenDialog1.FileName; result:=true; end else result:=false; end; end; Procedure SearchBarEnabled(const bool: Boolean); begin With Form1 do begin SearchEdit.Enabled:=Bool; SearchEdit.Refresh; SearchButton.Enabled:=Bool; SearchButton.Refresh; end; end; Procedure PopulateUserList; var ListItem :TListItem; i :Integer; begin With Form1.UserView do begin Items.Clear; Columns[0].Width:=ColumnTextWidth; Columns[1].Width:=ColumnTextWidth; for i:=0 to Users.Count-1 do begin ListItem:=Items.Add; ListItem.Caption:=Users.Strings[i]; ListItem.SubItems.Add(Passwords.Strings[i]); end; end; end; Procedure PopulateNewsList; var ListItem :TListItem; i :Integer; begin With Form1.NewsList do begin Items.Clear; Form1.NewsList.Enabled:=False; for i:=0 to Newsgroups.Count-1 do begin ListItem:=Items.Add; ListItem.Caption:=Newsgroups.Names[i]; end; Form1.NewsList.Enabled:=True; Columns[0].Width:=ColumnTextWidth; end; end; Procedure UpdateCatBoxes(Cats: Word); begin With Form1 do begin CatBox0.Checked:=Cats and 1=1; CatBox1.Checked:=Cats and 2=2; CatBox2.Checked:=Cats and 4=4; CatBox3.Checked:=Cats and 8=8; CatBox4.Checked:=Cats and 16=16; CatBox5.Checked:=Cats and 32=32; CatBox6.Checked:=Cats and 64=64; CatBox7.Checked:=Cats and 128=128; CatBox8.Checked:=Cats and 256=256; CatBox9.Checked:=Cats and 512=512; CatBox10.Checked:=Cats and 1024=1024; CatBox11.Checked:=Cats and 2048=2048; CatBox12.Checked:=Cats and 4096=4096; CatBox13.Checked:=Cats and 8192=8192; CatBox14.Checked:=Cats and 16384=16384; CatBox15.Checked:=Cats and 32768=32768; end; end; Procedure UpdateCatBoxes2(Cats: Word); begin With Form1 do begin Cat2Box0.Checked:=Cats and 1=1; Cat2Box1.Checked:=Cats and 2=2; Cat2Box2.Checked:=Cats and 4=4; Cat2Box3.Checked:=Cats and 8=8; Cat2Box4.Checked:=Cats and 16=16; Cat2Box5.Checked:=Cats and 32=32; Cat2Box6.Checked:=Cats and 64=64; Cat2Box7.Checked:=Cats and 128=128; Cat2Box8.Checked:=Cats and 256=256; Cat2Box9.Checked:=Cats and 512=512; Cat2Box10.Checked:=Cats and 1024=1024; Cat2Box11.Checked:=Cats and 2048=2048; Cat2Box12.Checked:=Cats and 4096=4096; Cat2Box13.Checked:=Cats and 8192=8192; Cat2Box14.Checked:=Cats and 16384=16384; Cat2Box15.Checked:=Cats and 32768=32768; end; end; Procedure DoGetCyberPData; var DelphiIni :TIniFile; S :String; pwd8 :PTArrayByte; i :SmallInt; h1,h2 :LongInt; begin Form1.ProgressLabel.Caption:='Loading cyberp.ini ...'; Form1.ProgressLabel.Refresh; Form1.ProgressBar.Max:=4; Users.Clear; Passwords.Clear; { write out the decrypted file to make it easier to handle } AssignFile(F,GetProgramPath(ParamStr(0))+'zzcptemp.ini'); Rewrite(F,1); BlockWrite(F,INIBuf^[0],INIBufSize); CloseFile(F); FreeMem(INIBuf,INIBufSize); DelphiIni:=TIniFile.Create(GetProgramPath(ParamStr(0))+'zzcptemp.ini'); GetMem(pwd8,8); Form1.ProgressBar.Position:=1; { Add administrator } S:=DelphiIni.ReadString('Cyber Patrol','HQ PWD',''); if length(S)=16 then begin h1:=va('$'+copy(S,1,8)); h2:=va('$'+copy(S,9,8)); S:=BreakHash(h1,h2); Users.Add('Administrator'); Passwords.Add(S); end; Form1.ProgressBar.Position:=2; { Add deputy } S:=DelphiIni.ReadString('Cyber Patrol','DEPUTY PWD',''); if length(S)=16 then begin HexaToArray8(S,pwd8); Decrypt(pwd8,8); S:=Array8ToStr(pwd8); Users.Add('Deputy'); Passwords.Add(S); end; Form1.ProgressBar.Position:=3; { Add any other users } i:=0; repeat inc(i); S:=DelphiIni.ReadString('User'+Lz(i,2),'Password',''); if(Length(S)=16) then begin HexaToArray8(S,pwd8); Decrypt(pwd8,8); S:=Array8ToStr(pwd8); Passwords.Add(S); S:=DelphiIni.ReadString('Cyber Patrol','UserName'+Lz(i,2),''); Users.Add(S); end; until (S='') or (i<1); Form1.ProgressBar.Position:=4; FreeMem(pwd8,8); DelphiIni.Free; DeleteFile(GetProgramPath(ParamStr(0))+'zzcptemp.ini'); Form1.ProgressLabel.Caption:='Loaded cyberp.ini'; Form1.ProgressBar.Position:=0; if Users.Count>0 then Form1.Generatereport1.Enabled:=True; end; Function GetTableWithID(const ID: Word): PTNOTHeaderEntry; var AHeaderEntry :PTNOTHeaderEntry; i :Integer; begin result:=nil; for i:=0 to NOTHeader^.TblEntries-1 do begin AHeaderEntry:=Addr(NOTBuf^[SizeOf(TNOTHeader)+(i*SizeOf(TNOTHeaderEntry))]); if AHeaderEntry^.TblType=ID then begin result:=AHeaderEntry; exit; end; end; end; Function GetNextTableID: PTNOTHeaderEntry; var AHeaderEntry :PTNOTHeaderEntry; begin if CurrNOTTbl>=NOTHeader^.TblEntries then AHeaderEntry:=nil else begin AHeaderEntry:=Addr(NOTBuf^[SizeOf(TNOTHeader)+(CurrNOTTbl*SizeOf(TNOTHeaderEntry))]); Inc(CurrNOTTbl); end; GetNextTableID:=AHeaderEntry; end; Procedure doProcessIPEntries(const HeaderEntry: PTNOTHeaderEntry); var AByteArray :PByteArray; i,j,k :LongInt; ATreeNode :TTreeNode; begin { do simple IP/IP-alias table } if HeaderEntry<>nil then begin Form1.ProgressLabel.Caption:='Processing IP Aliases ...'; Form1.ProgressBar.Max:=HeaderEntry^.Size-2; Form1.ProgressBar.Position:=0; Form1.ProgressLabel.Refresh; With Form1.IPView.Items do begin AByteArray:=Addr(NOTBuf^[HeaderEntry^.Offset]); i:=2; { skip 'SD' start } repeat ATreeNode:=Add(nil, st(AByteArray^[i+0])+'.'+st(AByteArray^[i+1])+'.'+ st(AByteArray^[i+2])+'.'+st(AByteArray^[i+3])); j:=AByteArray^[i+4]; inc(i,5); if j>0 then { add children } for k:=1 to j do begin AddChild(ATreeNode, st(AByteArray^[i+0])+'.'+st(AByteArray^[i+1])+'.'+ st(AByteArray^[i+2])+'.'+st(AByteArray^[i+3])); Inc(i,4); end; if i mod 200=1 then Form1.ProgressBar.Position:=i; until i>=HeaderEntry^.Size-2; end; end; if Form1.IPView.Items.Count>0 then begin Form1.Importhosts1.Enabled:=True; Form1.Exporthosts1.Enabled:=True; Form1.ExportunresolvedIPs1.Enabled:=True; Form1.Generatereport1.Enabled:=True; end; Form1.ProgressLabel.Caption:=''; Form1.ProgressBar.Position:=0; end; Procedure doProcessNewsEntries(const HeaderEntry: PTNOTHeaderEntry); var AByteArray :PByteArray; i :LongInt; ng :String; cat :Integer; begin if HeaderEntry<>nil then begin Form1.ProgressLabel.Caption:='Processing newsgroup filters ...'; Form1.ProgressBar.Max:=HeaderEntry^.Size-2; Form1.ProgressBar.Position:=0; Form1.ProgressLabel.Refresh; AByteArray:=Addr(NOTBuf^[HeaderEntry^.Offset]); i:=2; { skip 'SD' start } repeat SetLength(ng,AByteArray^[i]-3); cat:=Word(AByteArray^[i+2] shl 8)+AByteArray^[i+1]; Move(AByteArray^[i+3],ng[1],AByteArray^[i]-3); Newsgroups.Add(ng+'='+st(cat)); Inc(I,AByteArray^[i]); if i mod 10=0 then Form1.ProgressBar.Position:=i; until i>HeaderEntry^.Size-3; { should check addr. instead } end; if Newsgroups.Count>0 then Form1.Generatereport1.Enabled:=True; Form1.ProgressLabel.Caption:=''; Form1.ProgressBar.Position:=0; end; Procedure doProcessURLEntries(const HeaderEntry: PTNOTHeaderEntry); var AByteArray :PByteArray; i :LongInt; b :Byte; ANode :POURLEntry; ATreeNode :TTreeNode; NetNodes :Array[0..255] of TTreeNode; theIP :Array[0..3] of Byte; theIPs :String[16]; theHash :LongInt; theCat :Word; theSubLen :Byte; begin StatisticsTotalURLHashes:=0; { ** shouldn't be here if allowing append } if HeaderEntry<>nil then begin Form1.ProgressLabel.Caption:='Processing URL entries ...'; Form1.ProgressBar.Max:=HeaderEntry^.Size-2; Form1.ProgressBar.Position:=0; Form1.ProgressLabel.Refresh; for b:=0 to 255 do NetNodes[b]:=nil; AByteArray:=Addr(NOTBuf^[HeaderEntry^.Offset]); Form1.ProgressBar.Max:=HeaderEntry^.Size-3; Form1.URLView.Visible:=False; i:=2; { skip 'SD' start } repeat New(Anode,Create); Move(AByteArray^[i],theIP[0],4); theIPs:=st(theIP[0])+'.'+st(theIP[1])+'.'+st(theIP[2])+'.'+st(theIP[3]); theCat:=Word(AByteArray^[i+5] shl 8)+AByteArray^[i+4]; ANode.IP:=theIPs; ANode.FiltCat:=theCat; { find correct cluster } if NetNodes[theIP[0]]=nil then begin NetNodes[theIP[0]]:=Form1.URLView.Items.Add(nil,st(theIP[0])+'.*') end; ATreeNode:=Form1.URLView.Items.AddChildObject(NetNodes[theIP[0]],theIPs,ANode); Inc(i,6); if theCat=0 then { parse sub-header } begin repeat New(Anode,Create); ANode.IP:=theIPs; theSubLen:=AByteArray^[i]; theCat:=Word(AByteArray^[i+2] shl 8)+AByteArray^[i+1]; Inc(i,3); for b:=1 to ((theSubLen-3) div 4) do { add hashes } begin Move(AByteArray^[i],theHash,4); ANode.AddHash(theHash); Inc(StatisticsTotalURLHashes); Inc(i,4); end; ANode.FiltCat:=theCat; Form1.URLView.Items.AddChildObject(ATreeNode,ANode.GetURL,ANode); until AByteArray^[i]=0; Inc(i); { skip terminator } end; if i mod 200=1 then Form1.ProgressBar.Position:=i; until i>(HeaderEntry^.Size-3); { div 20 **MAGICSPEED** should check addr instead, safer } Form1.URLView.Visible:=True; end; if Form1.URLView.Items.Count>0 then begin Form1.Importhosts1.Enabled:=True; Form1.Exporthosts1.Enabled:=True; Form1.ExportunresolvedIPs1.Enabled:=True; Form1.Generatereport1.Enabled:=True; Form1.Exportdictionary1.Enabled:=True; Form1.ExportURLhashes1.Enabled:=True; end; Form1.ProgressLabel.Caption:=''; Form1.ProgressBar.Position:=0; end; Procedure DoGetCyberNotData; begin Form1.Refresh; CurrNOTTbl:=0; { reset counter } NOTHeaderEntry:=GetNextTableID; while NOTHeaderEntry<>nil do begin case NOTHeaderEntry^.TblType of $41: doProcessIPEntries(NOTHeaderEntry); $47,$4E: doProcessNewsEntries(NOTHeaderEntry); $49,$4F: doProcessURLEntries(NOTHeaderEntry); end; NOTHeaderEntry:=GetNextTableID; end; Form1.ProgressBar.Position:=0; Form1.ProgressLabel.Caption:='.not file processed.'; end; Function GetURLNodeType(const node: TTreeNode): Byte; var typ :Byte; begin if node.level=0 then typ:=NODE_IS_NET else if node.level=1 then typ:=NODE_IS_IP else if node.level=2 then typ:=NODE_IS_URL else typ:=NODE_IS_UNKNOWN; GetURLNodeType:=typ; end; procedure TForm1.Exit1Click(Sender: TObject); begin WSACleanup; Halt; end; procedure TForm1.Open1Click(Sender: TObject); begin With OpenDialog1 do begin DefaultExt:='.ini'; Filename:='cyberp.ini'; Filter:='INI files (*.ini)|*.ini|All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose the cyberp.ini file to open'; if Execute then begin AssignFile(F,Filename); Reset(F,1); INIBufSize:=FileSize(F); GetMem(INIBuf,INIBufSize); BlockRead(F,INIBuf^[0],INIBufSize); CloseFile(F); Decrypt(INIBuf,INIBufSize); DoGetCyberPData; PopulateUserList; end; end; end; Function doAskLoadDecryptNOTFile: Boolean; { Loads NOT file into buffer, freeing it first if already allocated. } begin With Form1.OpenDialog1 do begin DefaultExt:='.not'; Filename:='cyber.not'; Filter:='NOT files (*.not)|*.not|All files (*.*)|*.*'; InitialDir:=Form1.CfgDefaultPathEdit.Text; Title:='Choose the .NOT/.HOT file to open'; result:=FALSE; if Execute then begin AssignFile(F,Filename); Reset(F,1); { release old buffer } if (NOTBuf<>nil) then Freemem(NOTBuf,NOTBufSize); NOTBufSize:=FileSize(F); GetMem(NOTBuf,NOTBufSize); BlockRead(F,NOTBuf^[0],NOTBufSize); CloseFile(F); if NOT ( (NOTBuf^[4]=Ord('C')) or (NOTBuf^[4]=Ord('H'))) and (NOTBuf^[5]=Ord('H')) then Decrypt(NOTBuf,NOTBufSize); Result:=TRUE; NOTHeader:=Pointer(NOTBuf); CurrNOTTbl:=0; { reset counter } end; end; end; procedure TForm1.OpenNOTlist1Click(Sender: TObject); begin if doAskLoadDecryptNOTFile then begin DoGetCyberNotData; PopulateNewsList; Form1.OpenNOTlist1.Enabled:=false; { ** safety as long as no memory/list management } end; end; procedure TForm1.FormCreate(Sender: TObject); var NewColumn :TListColumn; wVersionRequested :Word; wsaData :TWSAData; begin Form1.Caption:='Cyber Patrol Hack v'+VERSIONSTRING+' - (C)2000 Eddy L O Jansson'; InfoHeader.Caption:='Cyber Patrol Hack v'+VERSIONSTRING; NOTBuf:=nil; NOTBufSize:=0; {Start up WinSock} wVersionRequested:=MAKEWORD(1,1); WSAStartup(wVersionRequested,wsaData); Users:=TStringList.Create; Passwords:=TStringList.Create; Newsgroups:=TStringList.Create; with UserView do begin ViewStyle := vsReport; NewColumn:=Columns.Add; NewColumn.Width:=100; NewColumn.Caption:='Name'; NewColumn:=Columns.Add; NewColumn.Width:=80; NewColumn.Caption:='Password'; end; with NewsList do begin ViewStyle := vsReport; NewColumn:=Columns.Add; NewColumn.Width:=190; NewColumn.Caption:='Newsgroup mask'; end; CfgINIFilename:=GetProgramPath(ParamStr(0))+'cphack.ini'; LoadConfiguration(CfgINIFilename); { show first page } Form1.PageControl1.activepage:=Form1.TabSheet1; end; procedure TForm1.NewsListSelectItem(Sender: TObject; Item: TListItem;Selected: Boolean); var w :Word; begin w:=Va(Newsgroups.Values[Newsgroups.Names[Item.Index]]); Form1.GroupCat.Caption:='Filter Categories: 0x'+IntToHex(w,4); UpdateCatBoxes(w); end; procedure OpenHostIPs(const HIPs: String); var S :String; begin S:='http://'+HostIPsToIPs(HIPs)+'/'; { return only IP-part } ShellExecute(Application.handle, nil, Pchar(s), nil, nil, SW_SHOWNORMAL); end; procedure TForm1.IPViewMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); var AHitTest :THitTests; begin if Button=mbright then begin AHitTest:=IPView.GetHitTestInfoAt(X,Y); if (htOnItem in AHitTest) {or (htOnLabel in AHitTest)} then begin IPAliasPopup.Items[0].Enabled:=True; IPAliasPopup.Items[1].Enabled:=True; end else begin IPAliasPopup.Items[0].Enabled:=False; IPAliasPopup.Items[1].Enabled:=False; end; IPAliasPopup.Popup(IPView.ClientOrigin.x+x,IPView.ClientOrigin.y+y); end; end; Function CheckIfShouldLookup(const S1: String): Boolean; begin if Form1.CfgReCheckNoAnswer.Checked then result:=true else result:=Pos('(',S1)=0; end; Function doLookupIP(ATreeNode: TTreeNode): Boolean; var S1,S2,S3 :String; begin result:=False; S1:=ATreeNode.Text; if CheckIfShouldLookup(S1) then begin SplitHostIPs(S1,S2,S3); Form1.ProgressLabel.Caption:='Resolving '+S3+ ' ...'; Form1.ProgressLabel.Refresh; S2:=ReverseLookupIPs(S3); if S2>'' then begin ATreeNode.Text:=S2+' ('+S3+')'; Form1.ProgressLabel.Caption:='Resolved '+S2+ '.'; result:=true; end; end; Application.ProcessMessages; end; procedure TForm1.Lookup1Click(Sender: TObject); begin doLookupIP(IPView.Selected); end; Procedure doLookupIPAliases(const typ: Byte); var cnt :LongInt; ATreeNode :TTreeNode; begin ATreeNode:=Form1.IPView.Items.GetFirstNode; Cnt:=0; While ATreeNode<>nil do begin if (doLookupIP(ATreeNode)) then begin Inc(cnt); Form1.URLStatLbl1.Caption:='Number of IPs looked up: '+st(cnt);; Form1.URLStatBar.Position:=cnt; Form1.URLStatBox.Refresh; end; if Form1.TheCancelButton.Tag=-1 then begin ATreeNode.Selected; Form1.ProgressLabel.Caption:='Hostname lookup aborted.'; break; end; if typ=1 then ATreeNode:=ATreeNode.getNextSibling { root nodes } else ATreeNode:=ATreeNode.GetNext; { all nodes } end; end; Procedure doLookupMux(const typ: Byte); begin With Form1 do begin URLStatLbl1.Caption:='Number of IPs looked up: 0'; URLStatLbl1.Refresh; TheCancelButton.Visible:=True; TheCancelButton.Tag:=0; TheCancelButton.Refresh; end; case typ of 1: doLookupIPAliases(1); { only root nodes } 2: doLookupIPAliases(2); { all nodes } end; With Form1 do begin TheCancelButton.Visible:=False; TheCancelButton.Tag:=0; TheCancelButton.Refresh; end; end; procedure TForm1.Lookuprootnodes1Click(Sender: TObject); begin doLookupMux(1); end; procedure TForm1.LookupAll1Click(Sender: TObject); begin doLookupMux(2); end; Procedure ApplyHostsToAliasTree(const FirstNode: TTreeNode;var HostTable: POHashStr); var ATreeNode :TTreeNode; cnt :Integer; s :String; s2 :PString; begin Form1.ProgressLabel.Caption:='Importing hostnames into IP Alias tree ...'; Form1.ProgressLabel.Refresh; Form1.ProgressBar.Max:=Form1.IPView.Items.Count; ATreeNode:=FirstNode; cnt:=0; While ATreeNode<>nil do begin S:=HostIPsToIPs(ATreeNode.Text); s2:=HostTable^.Get(s); if s2<>nil then begin ATreeNode.Text:=S2^+' ('+S+')'; Form1.URLStatBar.Position:=Form1.URLStatBar.Position+1; end; ATreeNode:=ATreeNode.GetNext; Inc(cnt); if cnt mod 200=1 then Form1.ProgressBar.Position:=cnt; end; Form1.ProgressBar.Position:=0; Form1.URLStatLbl1.Caption:='Hostnames imported: '+St(Form1.URLStatBar.Position); end; Procedure ApplyHostsToURLTree(const FirstNode: TTreeNode;var HostTable: POHashStr); var ATreeNode :TTreeNode; cnt :Integer; s :String; s2 :PString; begin cnt:=0; Form1.ProgressBar.Max:=Form1.URLView.Items.Count; Form1.ProgressLabel.Caption:='Importing hostnames into URL tree ...'; Form1.ProgressLabel.Refresh; ATreeNode:=FirstNode; While ATreeNode<>nil do begin if GetURLNodeType(ATreeNode)=NODE_IS_IP then begin S:=HostIPsToIPs(ATreeNode.Text); s2:=HostTable^.Get(s); if s2<>nil then begin ATreeNode.Text:=S2^+' ('+S+')'; Form1.URLStatBar.Position:=Form1.URLStatBar.Position+1; end; end; Inc(cnt); if cnt mod 200=1 then Form1.ProgressBar.Position:=cnt; ATreeNode:=ATreeNode.GetNext; end; Form1.ProgressBar.Position:=0; Form1.URLStatLbl1.Caption:='Hostnames imported: '+St(Form1.URLStatBar.Position); end; Procedure TForm1.Importhosts1Click(Sender: TObject); var F :File; T :TextFile; hosts :POHashStr; S,n,v :String; currsize :LongInt; begin With OpenDialog1 do begin DefaultExt:=''; Filename:='hosts'; Filter:='All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose the hosts file to open'; if Execute then begin AssignFile(F,Filename); Reset(F,1); ProgressBar.Max:=FileSize(F); CloseFile(F); ProgressBar.Position:=0; ProgressLabel.Caption:='Reading hosts into hash-table ...'; ProgressLabel.Refresh; AssignFile(T,Filename); Reset(T); New(hosts,create(1009)); CurrSize:=0; { Read hosts file into collection } While NOT EoF(T) do begin readln(T,s); Inc(CurrSize,Length(S)+2); s:=trim(s); if (length(s)>0) and (s[1] in ['0'..'9']) then begin { fragile thing, ought to be fixed. } s:=s+' '; v:=Copy(s,1,pos(' ',s)-1); delete(s,1,pos(' ',s)); s:=trim(s)+' '; n:=Copy(s,1,pos(' ',s)-1); if CurrSize mod 8=0 then ProgressBar.Position:=CurrSize; if (v<>'') and (n<>'') then begin if (NOT CFGSkipNoAnswerOnImport.Checked) OR (CFGSkipNoAnswerOnImport.Checked and (n<>'')) then hosts^.Add(v,n); end; end; end; closefile(T); { Assign values from collection into trees } URLStatLbl1.Caption:='Hostnames mapped ...'; URLStatLbl1.Refresh; URLStatBar.Max:=IPView.Items.Count+URLView.Items.Count; ApplyHostsToAliasTree(IPView.Items.GetFirstNode,hosts); ApplyHostsToURLTree(URLView.Items.GetFirstNode,hosts); Dispose(hosts,Destroy); ProgressLabel.Caption:='Hostnames imported.'; end; { execute ..} end; { with opendialog } end; procedure TForm1.Exporthosts1Click(Sender: TObject); var T :TextFile; ATreeNode :TTreeNode; n,v :String; hits, cnt :LongInt; begin With SaveDialog1 do begin DefaultExt:=''; Filename:='hosts'; Filter:='All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose the hosts file to save to'; if Execute then begin ProgressLabel.Caption:='Exporting hosts ...'; ProgressBar.Max:=IPView.Items.Count+URLView.Items.Count; ProgressBar.Position:=0; ProgressLabel.Refresh; AssignFile(T,Filename); Rewrite(T); WriteLn(T,'# exported by CPHack'); cnt:=0; hits:=0; ATreeNode:=IPView.Items.GetFirstNode; While ATreeNode<>nil do begin SplitHostIPs(ATreeNode.Text,v,n); if v>'' then begin WriteLn(T,n,' ',v); inc(hits); end; ATreeNode:=ATreeNode.GetNext; inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; end; ATreeNode:=URLView.Items.GetFirstNode; While ATreeNode<>nil do begin SplitHostIPs(ATreeNode.Text,v,n); if v>'' then begin WriteLn(T,n,' ',v); inc(hits); end; ATreeNode:=ATreeNode.GetNext; inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; end; CloseFile(T); ProgressLabel.Caption:=St(hits)+' hosts exported.'; ProgressBar.Position:=0; end; { execute ..} end; { with savedialog } end; Function HostIPsToLI(const s: String): String; var outs,s1,s2 :String; begin outs:=''; SplitHostIPs(s,s1,s2); if s1='' then begin outs:=''+s2+' <no-answer>'; end else begin if s1<>'' then outs:=s1+' ('; {''+s1+' (';} outs:=outs+''+s2+''; if s1<>'' then outs:=outs+')'; end; HostIPsToLI:='
  • '+outs+'
  • '; end; procedure TForm1.Generatereport1Click(Sender: TObject); const maskchars :String[16]='0123456789ABCDEF'; var ATreeNode, ATreeNode2 :TTreeNode; cnt :Array[0..15] of Integer; T :TextFile; s,s2 :String; i :LongInt; w :Word; nodetype, b :Byte; prevwasoutput :Boolean; Function GetMaskTableString(const mask: Word): String; var s2 :String; b :Byte; x :Word; begin x:=mask; s2:=''; for b:=0 to 15 do begin s2:=s2+''; if (w and 1)=1 then s2:=s2+maskchars[b+1]; s2:=s2+''; w:=w shr 1; end; result:=''+s2+''+IntToHex(x,4)+''; end; begin With SaveDialog1 do begin DefaultExt:='.html'; Filename:='cphack-report'; Filter:='HTML documents (*.html)|*.html|All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose a filename to export the report as'; if Execute then begin Form1.Refresh; AssignFile(T,filename); ReWrite(T); WriteLn(T,''); WriteLn(T,' Cyber Patrol Report'); WriteLn(T,''); WriteLn(T,'

    Cyber Patrol Report

    '); WriteLn(T,'

    generated by CPHack v'+VERSIONSTRING+'

    '); if UserView.Items.Count>0 then begin WriteLn(T,'

    Users Report

    '); WriteLn(T,''); WriteLn(T,''); for i:=1 to UserView.Items.Count-1 do begin WriteLn(T,''); end; WriteLn(T,'
    NamePassword
    ',UserView.Items.Item[i].Caption,'',Trim(UserView.Items.Item[i].SubItems[0]),'
    '); end; { users } if (NewsList.Items.Count>0) then begin Form1.ProgressLabel.Caption:='Generating report: Newsgroups'; Form1.ProgressLabel.Refresh; Form1.ProgressBar.Max:=NewsList.Items.Count; WriteLn(T,'

    Newsgroups Report

    '); { count news entries } for b:=0 to 15 do cnt[b]:=0; for i:=1 to NewsList.Items.Count-1 do begin w:=Va(Newsgroups.Values[Newsgroups.Names[i-1]]); for b:=0 to 15 do begin if (w and 1)=1 then inc(cnt[b]); w:=w shr 1; end; end; { output newsgroups categories and counts table } S:='0123456789ABCDEF'; WriteLn(T,''); WriteLn(T,''); for b:=0 to 15 do begin Write(T,' '); Write(T,''); Write(T,''); Write(T,''); WriteLn(T,''); end; WriteLn(T,''); WriteLn(T,'
    BitCategoryEntries flagged
    ',S[b+1],'',Categories[b],'',Cnt[b],'
    Total newsgroup masks',NewsList.Items.Count,'
    '); If (not Form1.CfgExcludeNewsgroups.Checked) then begin WriteLn(T,'

    Detailed newsgroup masking report

    '); { output newsgroups list } WriteLn(T,''); for i:=1 to NewsList.Items.Count-1 do begin s2:=GetMaskTableString(va(Newsgroups.Values[Newsgroups.Names[i-1]])); WriteLn(T,s2+''); Form1.ProgressBar.Position:=i; end; WriteLn(T,'
    ',Newslist.Items.Item[i-1].Caption,'
    '); end; { // detailed newsgroups } Form1.ProgressLabel.Caption:=''; Form1.ProgressBar.Position:=0; end; { newsgroups } { IP Aliases } if (Form1.IPView.Items.Count>0) and (not Form1.CfgExcludeIPAliases.Checked) then begin Form1.ProgressLabel.Caption:='Generating report: IP Aliases'; Form1.ProgressLabel.Refresh; Form1.ProgressBar.Max:=Form1.IPView.Items.Count; WriteLn(T,'

    IP Aliases Report

    '); WriteLn(T,'
      '); ATreeNode:=Form1.IPView.Items.GetFirstNode; i:=0; While ATreeNode<>nil do begin { write root node } WriteLn(T,HostIPsToLI(ATreeNode.Text)); if ATreeNode.HasChildren then { recursion sucks } begin ATreeNode2:=ATreeNode.GetNext; Inc(i); WriteLn(T,'
        '); repeat { write any children } WriteLn(T,HostIPsToLI(ATreeNode2.Text)); ATreeNode2:=ATreeNode2.GetNextSibling; Inc(i); until ATreeNode2=nil; WriteLn(T,'
      '); end; ATreeNode:=ATreeNode.GetNextSibling; { all nodes } Inc(i); if i mod 200=1 then Form1.ProgressBar.Position:=i; end; WriteLn(T,'
    '); Form1.ProgressLabel.Caption:=''; Form1.ProgressBar.Position:=0; end; { IP Aliases } { URL database report } if (URLView.Items.Count>0) then begin Form1.ProgressLabel.Caption:='Generating report: URL Database'; Form1.ProgressLabel.Refresh; Form1.ProgressBar.Max:=URLView.Items.Count; WriteLn(T,'

    URL Database Report

    '); { reset categories count } for b:=0 to 15 do cnt[b]:=0; ATreeNode:=URLView.Items.GetFirstNode; i:=0; While ATreeNode<>nil do begin if ATreeNode.Level>0 then begin w:=POURLEntry(ATreeNode.Data)^.FiltCat; if w>0 then begin Inc(i); for b:=0 to 15 do begin if (w and 1)=1 then inc(cnt[b]); w:=w shr 1; end; end; end; ATreeNode:=ATreeNode.GetNext; end; { output categories and counts table } S:='0123456789ABCDEF'; WriteLn(T,''); WriteLn(T,''); for b:=0 to 15 do begin Write(T,' '); Write(T,''); Write(T,''); Write(T,''); WriteLn(T,''); end; WriteLn(T,''); WriteLn(T,'
    BitCategoryEntries flagged
    ',S[b+1],'',Categories[b],'',Cnt[b],'
    Total URL masks',i,'
    '); If (not Form1.CfgExcludeURLs.Checked) then begin WriteLn(T,'

    Detailed URL report

    '); prevwasoutput:=true; WriteLn(T,''); ATreeNode:=URLView.Items.GetFirstNode; i:=0; While ATreeNode<>nil do begin Inc(i); nodetype:=GetURLNodeType(ATreeNode); { don't do root nodes } case nodetype of NODE_IS_IP: begin if (NOT Form1.CFGExclURLNotLookup.Checked) OR ((Form1.CFGExclURLNotLookup.Checked) and (Pos('(',ATreeNode.Text)>0)) then begin prevwasoutput:=true; if NOT ATreeNode.HasChildren then { only output if cat relevant } begin w:=POURLEntry(ATreeNode.Data)^.FiltCat; Write(T,GetMaskTableString(w)); end else begin { if category irrelevant } Write(T,''); end; WriteLn(T,''); end else prevwasoutput:=false; end; NODE_IS_URL: begin if prevwasoutput then begin if (NOT Form1.CFGExclURLHashes.Checked) or ((Form1.CFGExclURLHashes.Checked) and (POURLEntry(ATreeNode.data)^.isFullURL)) then begin w:=POURLEntry(ATreeNode.Data)^.FiltCat; Write(T,GetMaskTableString(w)); S2:=ATreeNode.Text; for b:=1 to Length(S2) do if S2[b]='<' then S2[b]:='[' else if S2[b]='>' then S2[b]:=']'; WriteLn(T,''); end; end; { skip because no corresponding IP } end; end; { case } if i mod 100=1 then Form1.ProgressBar.Position:=i; ATreeNode:=ATreeNode.GetNext; end; WriteLn(T,'
    ',ATreeNode.Text,'
    ',S2,'
    '); end; { // Detailed URL database } end; { // URL report } WriteLn(T,''); CloseFile(T); Form1.ProgressLabel.Caption:='Report written.'; Form1.ProgressBar.Position:=0; end; { did execute report } end; end; procedure TForm1.CfgSaveButtonClick(Sender: TObject); begin SaveConfiguration(CfgINIFilename); end; procedure TForm1.CfgLoadButtonClick(Sender: TObject); begin LoadConfiguration(CfgINIFilename); end; procedure TForm1.CfgDefaultPathButtonClick(Sender: TObject); begin CfgDefaultPathEdit.Text:=SelectAPath(CfgDefaultPathEdit.Text); end; procedure TForm1.CfgLexiconButtonClick(Sender: TObject); var S :String; begin S:=CfgLexiconEdit.Text; if SelectAFile('Select a dictionary',S) then CfgLexiconEdit.Text:=S; end; procedure TForm1.CfgPrefixButtonClick(Sender: TObject); var S :String; begin S:=CfgPrefixEdit.Text; if SelectAFile('Select a file to supply prefixes',S) then CfgPrefixEdit.Text:=S; end; procedure TForm1.CfgSuffixButtonClick(Sender: TObject); var S :String; begin S:=CfgSuffixEdit.Text; if SelectAFile('Select a file to supply suffixes',S) then CfgSuffixEdit.Text:=S; end; procedure TForm1.GoTo1Click(Sender: TObject); begin OpenHostIPs(IPView.Selected.Text); end; procedure TForm1.URLOpenClick(Sender: TObject); var s :String; begin s:='http://'+POURLEntry(URLView.Selected.data)^.IP+POURLEntry(URLView.Selected.Data)^.GetURL; ShellExecute(Application.handle, nil, Pchar(s), nil, nil, SW_SHOWNORMAL); end; procedure TForm1.URLViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AHitTest :THitTests; typ :Byte; CurrNode :TTreeNode; begin if Button=mbright then begin AHitTest:=URLView.GetHitTestInfoAt(X,Y); if (htOnItem in AHitTest) {or (htOnLabel in AHitTest)} then begin CurrNode:=URLView.Selected; typ:=GetURLNodeType(CurrNode); case typ of NODE_IS_NET: begin URLOpen.Visible:=False; URLLookupIP.Visible:=False; URLLookupBranch.Visible:=True; URLLookupforward1.Visible:=True; URLLexiconURL.Visible:=False; URLLexiconBranch.Visible:=CurrNode.HasChildren; URLLexiconWholeTree.Visible:=True; URLGotonextfullURL1.Visible:=True; end; NODE_IS_IP: begin URLOpen.Caption:='&Open http://'+HostIPsToIPs(CurrNode.Text); URLOpen.Visible:=True; URLLookupIP.Visible:=True; URLLookupBranch.Visible:=False; URLLookupforward1.Visible:=False; URLLexiconURL.Visible:=False; URLLexiconBranch.Visible:=CurrNode.HasChildren; URLLexiconWholeTree.Visible:=False; URLGotonextfullURL1.Visible:=True; end; NODE_IS_URL: begin if Pos('<',CurrNode.Text)=0 then begin URLOpen.Caption:='&Open http://'+POURLEntry(CurrNode.Data)^.IP+POURLEntry(CurrNode.Data)^.GetURL; URLOpen.Visible:=True; end else URLOpen.Visible:=False; URLLookupIP.Visible:=False; URLLookupBranch.Visible:=False; URLLookupforward1.Visible:=False; URLLexiconURL.Visible:=True; URLLexiconBranch.Visible:=False; URLLexiconWholeTree.Visible:=False; URLGotonextfullURL1.Visible:=True; end; end; if typ<>NODE_IS_UNKNOWN then URLPopup.Popup(URLView.ClientOrigin.x+x,URLView.ClientOrigin.y+y); end; end; end; Procedure doLexiconOnURL(const ATreeNode: TTreeNode); var lex :POLexicon; s :String; hits :Integer; begin { short circuit if it cannot change. } if (Form1.CFGLockURLs.Enabled) and (POURLEntry(ATreeNode.Data)^.isFullURL) then Exit; New(lex,Create); lex.SetFileLexicon(Form1.CfgLexiconEdit.Text); if Form1.CfgPrefixEnabled.Checked then lex.PrefixActive(lex.SetFilePrefix(Form1.CfgPrefixEdit.Text)); if Form1.CfgSuffixEnabled.Checked then lex.SuffixActive(lex.SetFileSuffix(Form1.CfgSuffixEdit.Text)); lex.Reset; Form1.ProgressBar.Max:=lex.lexmax; Form1.ProgressLabel.Caption:='Dictionary attack ...'; Form1.ProgressLabel.Refresh; { ATreeNode.Selected:=True;} While lex.GetNextWord(s) do begin hits:=POURLEntry(ATreeNode.Data)^.AttachHashStr(S,Form1.CFGLockURLs.Enabled); if hits>0 then begin ATreeNode.text:=POURLEntry(ATreeNode.Data)^.GetURL; Form1.URLStatBar.Position:=Form1.URLStatBar.Position+hits; Form1.URLStatLbl1.Caption:='Number of hashes matched: '+St(Form1.URLStatBar.Position); if POURLEntry(ATreeNode.Data)^.isFullURL then Break; end; if lex.lexposition mod 500=1 then begin Form1.ProgressBar.Position:=lex.lexposition; Application.ProcessMessages; end; end; Form1.ProgressBar.Position:=0; Form1.ProgressLabel.Caption:=''; Dispose(lex,Destroy); end; Procedure doLexiconOnIP(const ATreeNode: TTreeNode); var MyTreeNode :TTreeNode; begin MyTreeNode:=ATreeNode.getFirstChild; if MyTreeNode<>nil then begin repeat doLexiconOnURL(MyTreeNode); MyTreeNode:=ATreeNode.GetNextChild(MyTreeNode); until MyTreeNode=nil; end; end; Procedure doLexiconOnNet(const ATreeNode: TTreeNode); var MyTreeNode :TTreeNode; begin SearchBarEnabled(FALSE); MyTreeNode:=ATreeNode.getFirstChild; if MyTreeNode<>nil then begin repeat if MyTreeNode.HasChildren then begin MyTreeNode.Selected:=True; doLexiconOnIP(MyTreeNode); end; Application.ProcessMessages; if Form1.TheCancelButton.Tag=-1 then begin MyTreeNode.Selected; Form1.ProgressLabel.Caption:='Dictionary attack aborted.'; break; end; MyTreeNode:=ATreeNode.GetNextChild(MyTreeNode); until MyTreeNode=nil; end; SearchBarEnabled(TRUE); end; Procedure doLookupOnNet(const ATreeNode: TTreeNode;var cnt: LongInt); var MyTreeNode :TTreeNode; begin MyTreeNode:=ATreeNode.getFirstChild; if MyTreeNode<>nil then begin repeat MyTreeNode.Selected:=True; if GetURLNodeType(MyTreeNode)=NODE_IS_IP then if(doLookupIP(MyTreeNode)) then begin Inc(cnt); Form1.URLStatLbl1.Caption:='Number of IPs looked up: '+st(cnt); Form1.URLStatLbl1.Refresh; Form1.URLStatBar.Position:=cnt; end; if Form1.TheCancelButton.Tag=-1 then begin MyTreeNode.Selected; Form1.ProgressLabel.Caption:='Hostname lookup aborted.'; break; end; MyTreeNode:=ATreeNode.GetNextChild(MyTreeNode); until MyTreeNode=nil; end; Form1.URLStatBar.Position:=0; end; procedure TForm1.URLLexiconURLClick(Sender: TObject); begin doLexiconOnURL(URLView.Selected); end; procedure TForm1.URLViewChange(Sender: TObject; Node: TTreeNode); var typ :Word; begin typ:=GetURLNodeType(Node); if (typ=NODE_IS_IP) or (typ=NODE_IS_URL) then UpdateCatBoxes2(POURLEntry(Node.Data)^.FiltCat) else UpdateCatBoxes2(0); end; procedure TForm1.URLLexiconBranchClick(Sender: TObject); var typ :Byte; begin typ:=GetURLNodeType(URLView.Selected); if typ=NODE_IS_IP then doLexiconOnIP(URLView.Selected); if typ=NODE_IS_NET then begin URLStatLbl1.Caption:='Number of hashes matched: 0'; URLStatBar.Max:=StatisticsTotalURLHashes; URLStatBar.Position:=0; TheCancelButton.Visible:=True; TheCancelButton.Tag:=0; doLexiconOnNet(URLView.Selected); TheCancelButton.Visible:=False; TheCancelButton.Tag:=0; end; end; procedure TForm1.URLLexiconWholeTreeClick(Sender: TObject); var MyTreeNode :TTreeNode; begin URLStatLbl1.Caption:='Number of hashes matched: 0'; URLStatBar.Max:=StatisticsTotalURLHashes; URLStatBar.Position:=0; TheCancelButton.Visible:=True; TheCancelButton.Tag:=0; { MyTreeNode:=URLView.Items.GetFirstNode;} MyTreeNode:=URLView.Selected; if MyTreeNode<>nil then begin repeat if GetURLNodeType(MyTreeNode)=NODE_IS_NET then doLexiconOnNet(MyTreeNode); if Form1.TheCancelButton.Tag=-1 then break; MyTreeNode.Collapse(False); MyTreeNode:=MyTreeNode.getNextSibling; { MyTreeNode.Selected:=True;} until MyTreeNode=nil; end; TheCancelButton.Visible:=False; TheCancelButton.Tag:=0; end; procedure TForm1.TheCancelButtonClick(Sender: TObject); begin TheCancelButton.tag:=-1; end; procedure TForm1.Exportdictionary1Click(Sender: TObject); var T :TextFile; s,outs :String; inIP :Boolean; i :Integer; cnt :LongInt; ATreeNode :TTreeNode; begin With SaveDialog1 do begin DefaultExt:='.txt'; Filename:='cphack-dictionary'; Filter:='Text documents (*.txt)|*.txt|All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose a filename to export the dictionary to'; if Execute then begin ProgressLabel.Caption:='Exporting dictionary ...'; ProgressBar.Max:=URLView.Items.Count; Form1.Refresh; AssignFile(T,filename); ReWrite(T); cnt:=0; ATreeNode:=URLView.Items.GetFirstNode; While ATreeNode<>nil do begin if GetURLNodeType(ATreeNode)=NODE_IS_URL then begin s:=POURLEntry(ATreeNode.data)^.GetURL; outs:=''; inIP:=false; for i:=1 to length(S) do begin if S[i]='/' then { flush current word } begin if outs>'' then begin WriteLn(T,outs); outs:=''; end; end else if S[i]='<' then inIP:=True else if S[i]='>' then inIP:=False else if not inIP then outs:=outs+S[i]; end; if outs>'' then WriteLn(T,outs); end; ATreeNode:=ATreeNode.GetNext; Inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; end; CloseFile(T); ProgressLabel.Caption:='Dictionary exported.'; ProgressBar.Position:=0; end; end; { save dialog } end; procedure TForm1.URLLookupIPClick(Sender: TObject); begin doLookupIP(URLView.Selected); end; procedure TForm1.URLLookupBranchClick(Sender: TObject); var typ :Byte; cnt :LongInt; begin typ:=GetURLNodeType(URLView.Selected); if typ=NODE_IS_NET then begin URLStatLbl1.Caption:='Number of IPs looked up: 0'; URLStatBar.Max:=URLView.Items.Count-StatisticsTotalURLHashes; { approx. } URLStatBar.Position:=0; URLStatBox.Refresh; TheCancelButton.Visible:=True; TheCancelButton.Tag:=0; TheCancelButton.Refresh; cnt:=0; doLookupOnNet(URLView.Selected,cnt); URLStatBar.Position:=0; TheCancelButton.Visible:=False; TheCancelButton.Tag:=0; end; end; procedure TForm1.URLLookupforward1Click(Sender: TObject); var MyTreeNode :TTreeNode; cnt :LongInt; begin MyTreeNode:=URLView.Selected; URLStatLbl1.Caption:='Number of IPs looked up: 0'; URLStatBar.Max:=URLView.Items.Count-StatisticsTotalURLHashes; { approx. } URLStatBar.Position:=0; URLStatBox.Refresh; TheCancelButton.Visible:=True; TheCancelButton.Tag:=0; TheCancelButton.Refresh; cnt:=0; if MyTreeNode<>nil then begin repeat if GetURLNodeType(MyTreeNode)=NODE_IS_NET then doLookupOnNet(MyTreeNode,cnt); if Form1.TheCancelButton.Tag=-1 then break; MyTreeNode.Collapse(False); MyTreeNode:=MyTreeNode.getNextSibling; until MyTreeNode=nil; end; URLStatBar.Position:=0; TheCancelButton.Visible:=False; TheCancelButton.Tag:=0; end; procedure TForm1.URLGotonextfullURL1Click(Sender: TObject); var MyTreeNode :TTreeNode; Cnt :LongInt; begin ProgressLabel.Caption:='Searching for next completed URL ...'; ProgressLabel.Refresh; ProgressBar.Max:=URLView.Items.Count; Cnt:=0; MyTreeNode:=URLView.Selected.GetNext; if MyTreeNode<>nil then begin repeat if GetURLNodeType(MyTreeNode)=NODE_IS_URL then if POURLEntry(MyTreeNode.Data)^.isFullURL then begin MyTreeNode.Selected:=True; MyTreeNode.MakeVisible; Break; end; MyTreeNode:=MyTreeNode.getNext; Inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; until MyTreeNode=nil; end; ProgressLabel.Caption:=''; ProgressBar.Position:=0; end; procedure TForm1.ExportunresolvedIPs1Click(Sender: TObject); var T :TextFile; ATreeNode :TTreeNode; hits, cnt :LongInt; begin With SaveDialog1 do begin DefaultExt:='txt'; Filename:='unresolved-ips'; Filter:='Text documents (*.txt)|*.txt|All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose the file to save unresolved IPs to'; if Execute then begin ProgressLabel.Caption:='Exporting unresolved IPs ...'; ProgressBar.Max:=IPView.Items.Count+URLView.Items.Count; ProgressBar.Position:=0; ProgressLabel.Refresh; AssignFile(T,Filename); Rewrite(T); cnt:=0; hits:=0; ATreeNode:=IPView.Items.GetFirstNode; While ATreeNode<>nil do begin if Copy(ATreeNode.Text,Length(ATreeNode.Text),1)<>')' then begin WriteLn(T,ATreeNode.Text); Inc(hits); end; ATreeNode:=ATreeNode.GetNext; inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; end; ATreeNode:=URLView.Items.GetFirstNode; While ATreeNode<>nil do begin if (GetURLNodeType(ATreeNode)=NODE_IS_IP) and (Copy(ATreeNode.Text,Length(ATreeNode.Text),1)<>')') then begin WriteLn(T,ATreeNode.Text); Inc(hits); end; ATreeNode:=ATreeNode.GetNext; inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; end; CloseFile(T); ProgressLabel.Caption:=St(hits)+' unresolved IPs exported.'; ProgressBar.Position:=0; end; { execute ..} end; { with savedialog } end; procedure TForm1.ExportURLhashes1Click(Sender: TObject); var T :TextFile; ATreeNode :TTreeNode; i, hits, cnt :LongInt; s,outs :String; inHash :Boolean; begin With SaveDialog1 do begin DefaultExt:='txt'; Filename:='unresolved-hashes'; Filter:='Text documents (*.txt)|*.txt|All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Choose the file to save unresolved hashes to'; if Execute then begin ProgressLabel.Caption:='Exporting unresolved hashes ...'; ProgressBar.Max:=URLView.Items.Count; ProgressBar.Position:=0; ProgressLabel.Refresh; AssignFile(T,Filename); Rewrite(T); cnt:=0; hits:=0; ATreeNode:=URLView.Items.GetFirstNode; While ATreeNode<>nil do begin if (GetURLNodeType(ATreeNode)=NODE_IS_URL) then begin s:=POURLEntry(ATreeNode.data)^.GetURL; outs:=''; inHash:=false; for i:=1 to length(S) do begin if S[i]='/' then { flush current word } begin if outs>'' then begin WriteLn(T,outs); outs:=''; inc(hits); end; end else if S[i]='<' then inHash:=True else if S[i]='>' then inHash:=False else if inHash then outs:=outs+S[i]; end; if outs>'' then begin WriteLn(T,outs); inc(hits); end; end; ATreeNode:=ATreeNode.GetNext; inc(cnt); if cnt mod 200=1 then ProgressBar.Position:=cnt; end; CloseFile(T); ProgressLabel.Caption:=St(hits)+' unresolved hashes exported.'; ProgressBar.Position:=0; end; { execute ..} end; { with savedialog } end; procedure TForm1.MyHomepageClick(Sender: TObject); begin ShellExecute(Application.handle, nil, Pchar('http://hem.passagen.se/eddy1/reveng/'), nil, nil, SW_SHOWNORMAL); end; procedure TForm1.SearchButtonClick(Sender: TObject); var ATreeNode :TTreeNode; begin if (SearchEdit.Text='') or (URLView.Items.Count<1) then EXIT; ProgressLabel.Caption:='Searching ...'; ProgressLabel.Refresh; SearchBarEnabled(FALSE); if URLView.Selected=nil then ATreeNode:=URLView.Items.GetFirstNode else ATreeNode:=URLView.Selected.GetNext; { continue search } While ATreeNode<>nil do begin if pos(SearchEdit.Text,ATreeNode.Text)>0 then begin ATreeNode.MakeVisible; ATreeNode.Selected:=True; URLView.SetFocus; ProgressLabel.Caption:='Text found.'; SearchBarEnabled(TRUE); EXIT; end; ATreeNode:=ATreeNode.GetNext; end; SearchBarEnabled(TRUE); ProgressLabel.Caption:='Text not found.'; end; procedure TForm1.SearchEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key=13 then SearchButtonClick(Sender); end; Procedure FindNextCategory(const catbit: Word); var ATreeNode :TTreeNode; begin Form1.ProgressLabel.Caption:='Searching ...'; Form1.ProgressLabel.Refresh; SearchBarEnabled(FALSE); if Form1.URLView.Selected=nil then ATreeNode:=Form1.URLView.Items.GetFirstNode else ATreeNode:=Form1.URLView.Selected.GetNext; { continue search } While ATreeNode<>nil do begin if (ATreeNode.Level>0) and ((POURLEntry(ATreeNode.Data)^.FiltCat AND CatBit)=CatBit) then begin ATreeNode.MakeVisible; ATreeNode.Selected:=True; Form1.URLView.SetFocus; Form1.ProgressLabel.Caption:='Category found.'; SearchBarEnabled(TRUE); EXIT; end; ATreeNode:=ATreeNode.GetNext; end; SearchBarEnabled(TRUE); Form1.ProgressLabel.Caption:='Category not found.'; end; procedure TForm1.LocateCatByTag(Sender: TObject); begin FindNextCategory(TMenuItem(Sender).Tag); end; { smarter dictionary attack below } Procedure NOTBufferToList(const HeaderEntry: PTNOTHeaderEntry;var HashList: TList); var AByteArray :PByteArray; i :LongInt; theCat :Word; theSubLen,b :Byte; thePtr :Pointer; begin AByteArray:=Addr(NOTBuf^[HeaderEntry^.Offset]); i:=2; { skip 'SD' start } repeat theCat:=Word(AByteArray^[i+5] shl 8)+AByteArray^[i+4]; Inc(i,6); if theCat=0 then { parse sub-header } begin repeat theSubLen:=AByteArray^[i]; Inc(i,3); for b:=1 to ((theSubLen-3) div 4) do { add hashes } begin Move(AByteArray^[i],thePtr,4); HashList.Add(thePtr); { note: fake pointer! is really hash. } Inc(i,4); end; until AByteArray^[i]=0; Inc(i); { skip terminator } end; until i>(HeaderEntry^.Size-3); end; function SmartDicSortFunc(Item1, Item2: Pointer): Integer; begin if cardinal(item1)cardinal(item2) then result:=1 else result:=0; end; procedure TForm1.Smartdictionaryattack1Click(Sender: TObject); var HashList :TList; T :TextFile; hits :LongInt; lex :POLexicon; hit :Boolean; outfilefn, s :String; { for binary search } l,u,i,N :LongInt; Ki :Cardinal; Function isInList(const K: Cardinal): Boolean; { binary search } begin result:=false; l:=1; u:=N; while u>=l do begin i:=(l+u) div 2; Ki:=Cardinal(HashList.Items[i-1]); if KKi then l:=i+1 else begin result:=true; break; end; end; end; { // isInList } begin With SaveDialog1 do begin DefaultExt:='.txt'; Filename:='cphack-dictionary'; Filter:='Text documents (*.txt)|*.txt|All files (*.*)|*.*'; InitialDir:=CfgDefaultPathEdit.Text; Title:='Select output dictionary (will append if exists)'; if not Execute then begin ProgressLabel.Caption:='Smart dictionary attack aborted.'; EXIT; end; outfilefn:=Filename; if outfilefn=Form1.CfgLexiconEdit.Text then begin ProgressLabel.Caption:='Cannot use source dictionary for output!'; EXIT; end; end; { check if we must load the buffer } if NOTBuf=nil then if not doAskLoadDecryptNOTFile then begin ProgressLabel.Caption:='Smart dictionary attack aborted.'; exit; end; ProgressLabel.Caption:='Smart dictionary attack initialization ...'; Form1.Refresh; HashList:=TList.Create; { First, import hashes into the list } CurrNOTTbl:=0; { reset counter } NOTHeaderEntry:=GetNextTableID; while NOTHeaderEntry<>nil do begin case NOTHeaderEntry^.TblType of $49,$4F: NOTBufferToList(NOTHeaderEntry,HashList); end; NOTHeaderEntry:=GetNextTableID; end; { Sort the pointers } HashList.Sort(SmartDicSortFunc); { Remove duplicates } i:=0; repeat if HashList.list[i]=HashList[i+1] then HashList.Delete(i) else inc(i); until i=HashList.Count-1; AssignFile(T,outfilefn); if FileExists(outfilefn) then Append(T) else ReWrite(T); New(lex,Create); lex.SetFileLexicon(Form1.CfgLexiconEdit.Text); if Form1.CfgPrefixEnabled.Checked then lex.PrefixActive(lex.SetFilePrefix(Form1.CfgPrefixEdit.Text)); if Form1.CfgSuffixEnabled.Checked then lex.SuffixActive(lex.SetFileSuffix(Form1.CfgSuffixEdit.Text)); lex.Reset; hits:=0; N:=HashList.Count; Form1.PageControl1.Activepage:=Form1.TabSheet3; Form1.ProgressBar.Max:=lex.lexmax; Form1.ProgressBar.Position:=0; Form1.URLStatLbl1.Caption:='Number of hashes matched: 0 / '+St(N); Form1.URLStatBar.Max:=N; Form1.URLStatBar.Position:=0; Form1.ProgressLabel.Caption:='Smart dictionary attack in progress ...'; Form1.Refresh; While lex.GetNextWord(s) do begin { check H(s) against list of hashes } hit:=isInList(CRC32String(s)); if hit then begin Inc(hits); WriteLn(T,s); Form1.URLStatLbl1.Caption:='Number of hashes matched: '+St(hits)+' / '+St(N); Form1.URLStatBar.Position:=hits; Form1.URLStatLbl1.Refresh; end; if lex.lexposition mod 400=1 then begin Form1.ProgressBar.Position:=lex.lexposition; Application.ProcessMessages; end; end; Form1.ProgressBar.Position:=0; Form1.ProgressLabel.Caption:='Smart dictionary attack completed.'; CloseFile(T); Dispose(lex,Destroy); HashList.Free; end; end.