program scan;
{$APPTYPE CONSOLE}
uses
Windows,
Winsock2;
type
TBufferArray = array[0..65535] of byte;
iph = record
ip_verlen: byte;
ip_tos: byte;
ip_len: word;
ip_id: word;
ip_offset: word;
ip_ttl: byte;
ip_protocol: byte;
ip_checksum: word;
ip_saddr: longword;
ip_daddr: longword;
end;
tcph = record
th_sport: word;
th_dport: word;
th_seq: longword;
th_ack: longword;
th_len: byte;
th_flags: byte;
th_win: word;
th_checksum: word;
th_upr: word;
end;
var
hSocket, bSocket: integer;
hFile: dword;
TID: dword;
Sequence: dword;
Source: TInAddr;
BatchFile: string;
Ports: array [0..255] of word;
PortCount: integer = 0;
Target: dword = 0;
Port: word;
Delay: dword = 50;
UseBatch: boolean = False;
UseOutput: boolean = False;
MaxScan: dword = 0;
ScanCount: dword = 0;
Verbose: dword = 0;
Random: dword = 0;
function IntToStr(I: integer): string;
begin
Str(I, Result);
end;
function StrToInt(S: string): integer;
begin
Val(S, Result, Result);
end;
function Split(Input: string; Deliminator: string; Index: integer): string;
var
StringLoop, StringCount: integer;
Buffer: string;
begin
StringCount := 0;
for StringLoop := 1 to Length(Input) do
begin
if (Copy(Input, StringLoop, 1) = Deliminator) then
begin
Inc(StringCount);
if StringCount = Index then
begin
Result := Buffer;
Exit;
end
else
begin
Buffer := '';
end;
end
else
begin
Buffer := Buffer + Copy(Input, StringLoop, 1);
end;
end;
Result := Buffer;
end;
function RandomAddress(Address: dword; AddressClass: byte): dword;
var
AddressMask: dword;
Range: dword;
begin
Result := ntohl(Address);
case AddressClass of
3:
begin
AddressMask := 4294967040;
Range := 16777214;
end;
2:
begin
AddressMask := 4294901760;
Range := 65534;
end;
1:
begin
AddressMask := 4278190080;
Range := 254;
end;
else
Exit;
end;
AddressMask := ntohl(AddressMask);
Result := (Result and AddressMask) xor Result + dword(System.Random(Range)) + 1;
Result := htonl(Result);
end;
function CheckSum(var Buffer; Size: integer): word;
type
TWordArray = Array[0..1] of word;
var
lSumm: LongWord;
iLoop: integer;
begin
lSumm := 0;
iLoop := 0;
while Size > 1 do
begin
lSumm := lSumm + TWordArray(Buffer)[iLoop];
inc(iLoop);
Size := Size - SizeOf(word);
end;
if Size = 1 then lSumm := lSumm + Byte(TWordArray(Buffer)[iLoop]);
lSumm := (lSumm shr 16) + (lSumm and $FFFF);
lSumm := lSumm + (lSumm shr 16);
Result := word(not lSumm);
end;
procedure Header(FromIP: dword; FromPort: word; ToIP: dword; ToPort: word; Seq: longint; var Buffer: TBufferArray; var Socket: TSockAddr; var Size: word);
var
ipHdr: iph;
tcpHdr: tcph;
TcpHeaderLen: word;
ChecksumSize: word;
DataPointer: ^byte;
procedure IncPtr(Value: integer);
begin
DataPointer := pointer(integer(DataPointer) + Value);
end;
begin
Size := sizeof(ipHdr) + sizeof(tcpHdr);
ipHdr.ip_verlen := ((4 shl 4) or sizeof(ipHdr) div sizeof(longword));
ipHdr.ip_tos := 0;
ipHdr.ip_len := htons(Size);
ipHdr.ip_id := 0;
ipHdr.ip_offset := 0;
ipHdr.ip_ttl := 128;
ipHdr.ip_protocol := 6;
ipHdr.ip_checksum := 0;
ipHdr.ip_saddr := FromIP;
ipHdr.ip_daddr := ToIP;
ChecksumSize := 0;
tcpHdr.th_sport := htons(FromPort);
tcpHdr.th_dport := htons(ToPort);
tcpHdr.th_seq := htons(Seq);
tcpHdr.th_ack := 0;
tcpHdr.th_len := 80;
tcpHdr.th_flags := 2;
tcpHdr.th_win := htons(65535);
tcpHdr.th_checksum := 0;
tcpHdr.th_upr := 0;
DataPointer := @Buffer[0];
FillChar(Buffer, SizeOf(Buffer), 0);
Move(ipHdr.ip_saddr, DataPointer^, SizeOf(ipHdr.ip_saddr));
IncPtr(SizeOf(ipHdr.ip_saddr));
ChecksumSize := ChecksumSize + sizeof(ipHdr.ip_saddr);
Move(ipHdr.ip_daddr, DataPointer^, sizeof(ipHdr.ip_daddr));
IncPtr(SizeOf(ipHdr.ip_daddr));
ChecksumSize := ChecksumSize + sizeof(ipHdr.ip_daddr);
IncPtr(1);
Inc(ChecksumSize);
Move(ipHdr.ip_protocol, DataPointer^, sizeof(ipHdr.ip_protocol));
IncPtr(sizeof(ipHdr.ip_protocol));
ChecksumSize := ChecksumSize + sizeof(ipHdr.ip_protocol);
TcpHeaderLen := htons(sizeof(tcpHdr));
Move(TcpHeaderLen, DataPointer^, sizeof(TcpHeaderLen));
IncPtr(sizeof(TcpHeaderLen));
ChecksumSize := ChecksumSize + sizeof(TcpHeaderLen);
Move(tcpHdr, DataPointer^, sizeof(tcpHdr));
IncPtr(sizeof(tcpHdr));
ChecksumSize := ChecksumSize + sizeof(tcpHdr);
tcpHdr.th_checksum := CheckSum(Buffer, ChecksumSize);
FillChar(Buffer, sizeof(Buffer), 0);
DataPointer := @Buffer[0];
Move(ipHdr, DataPointer^, sizeof(ipHdr));
IncPtr(sizeof(ipHdr));
Move(tcpHdr, DataPointer^, sizeof(tcpHdr));
Socket.sin_family := 2;
Socket.sin_port := htons(0);
Socket.sin_addr.S_addr := ToIP;
end;
procedure Send(TargetIP: dword; TargetPort: integer; SourceIP: dword; SourcePort: integer; Sequence: longint);
var
Buffer: TBufferArray;
Sck: TSockAddr;
Size: Word;
begin
Header(SourceIP, SourcePort, TargetIP, TargetPort, Sequence, Buffer, Sck, Size);
while SendTo(hSocket, Buffer, Size, 0, Sck, sizeof(Sck)) = -1 do Sleep(1);
end;
function GetInAddr: TInAddr;
var
Host: array[0..128] of char;
HostEnt: PHostEnt;
begin
GetHostName(@Host, 128);
HostEnt := GetHostByName(@Host);
Result := PInAddr(HostEnt^.h_addr_list^)^
end;
procedure Init;
var
WSAdata: TWSAdata;
SockAddrIn: TSockAddrIn;
Option: integer;
Control, BytesReceived: longint;
begin
WSAStartup($0002, WSAdata);
hSocket := Socket(2, 3, 0);
Option := 1;
SetSockOpt(hSocket, 0, 2, @Option, SizeOf(Option));
bSocket := Socket(2, 3, 0);
SockAddrIn.sin_family := 2;
SockAddrIn.sin_addr := GetInAddr;
SockAddrIn.sin_port := htons(0);
bind(bSocket, @SockAddrIn, SizeOf(SockAddrIn));
WSAIoctl(bSocket, IOC_IN or $18000000 or 1, @Control, SizeOf(Control), nil, 0, @BytesReceived, nil, nil);
end;
procedure ReceiveResults;
var
Data: array [0..39] of char;
BytesReceived: longint;
IPHeader: iph;
TCPHeader: tcph;
Result: string;
BytesWritten: Cardinal;
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
begin
while True do
begin
BytesReceived := recv(bSocket, Data, 40, 0);
if BytesReceived = 40 then
begin
IPHeader := iph(pointer(@Data)^);
TCPHeader := tcph(pointer(longint(@Data) + 20)^);
if TCPHeader.th_flags = 16 then
begin
if ntohs(TCPHeader.th_dport) = Port then
begin
if Verbose <> 0 then
begin
Result := string(inet_ntoa(TInAddr(IPHeader.ip_saddr))) + ':' + IntToStr(ntohs(TCPHeader.th_sport)) + #13#10;
Write('[CONNECTION] ' + Result);
end;
if UseOutput then
begin
Result := string(inet_ntoa(TInAddr(IPHeader.ip_saddr))) + ':' + IntToStr(ntohs(TCPHeader.th_sport)) + #13#10;
WriteFile(hFile, pointer(Result)^, Length(Result) + 1, BytesWritten, nil);
end;
if UseBatch then
begin
Result := BatchFile + ' ' + string(inet_ntoa(TInAddr(IPHeader.ip_saddr))) + ' ' + IntToStr(ntohs(TCPHeader.th_sport));
ZeroMemory(@StartInfo, SizeOf(TStartupInfo));
StartInfo.cb := SizeOf(TStartupInfo);
StartInfo.dwFlags := STARTF_USESHOWWINDOW;
StartInfo.wShowWindow := SW_HIDE;
CreateProcess(nil, pchar(Result), nil, nil, False, 0, nil, nil, StartInfo, ProcInfo);
end;
end;
end;
end;
end;
end;
procedure ScanAddresses;
var
PortLoop: integer;
begin
while ((ScanCount <= MaxScan) or (MaxScan = 0)) do
begin
if Verbose = 2 then
begin
if ntohl(Target) mod 256 = 0 then
begin
Target := htonl(ntohl(Target) + 1);
end;
if ScanCount mod 255 = 0 then
begin
WriteLn('[STATUS] ' + string(inet_ntoa(TInAddr(Target))));
end;
end;
for PortLoop := 0 to PortCount - 1 do
begin
Send(Target, Ports[PortLoop], dword(Source), Port, Sequence);
Send(Target, Ports[PortLoop], dword(Source), Port, Sequence);
Sleep(Delay);
Inc(ScanCount);
end;
if Random > 0 then
begin
Target := RandomAddress(Target, Random)
end
else
Target := htonl(ntohl(Target) + 1);
end;
Halt(0);
end;
procedure Usage;
begin
WriteLn('AFX Syn Scanner 0.2 for 2000/XP/2003');
WriteLn('http://www.iamaphex.cjb.net');
WriteLn('aphex@iamaphex.net');
WriteLn;
WriteLn('Usage: scan -h:host -p:port -i:scancount -d:delay -b:batch -o:output -v:verboselevel -r:randomlevel');
end;
procedure ParseOption(Cmd, Arg: string);
begin
if lstrcmp('-h:', pchar(Cmd)) = 0 then
begin
Target := inet_addr(pchar(Arg));
end
else if lstrcmp('-p:', pchar(Cmd)) = 0 then
begin
Ports[PortCount] := StrToInt(Arg);
Inc(PortCount);
end
else if lstrcmp('-d:', pchar(Cmd)) = 0 then
begin
Delay := StrToInt(Arg);
end
else if lstrcmp('-i:', pchar(Cmd)) = 0 then
begin
MaxScan := StrToInt(Arg);
end
else if lstrcmp('-b:', pchar(Cmd)) = 0 then
begin
BatchFile := Copy(Arg, 1, Length(Arg));
UseBatch := True;
end
else if lstrcmp('-o:', pchar(Cmd)) = 0 then
begin
hFile := CreateFile(pchar(Arg), GENERIC_WRITE, FILE_SHARE_WRITE, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
SetFilePointer(hFile, 0, nil, FILE_END);
UseOutput := True;
end
else if lstrcmp('-v:', pchar(Cmd)) = 0 then
begin
Verbose := StrToInt(Arg);
end
else if lstrcmp('-r:', pchar(Cmd)) = 0 then
begin
Random := StrToInt(Arg);
end
else
begin
Usage;
Halt(0);
end;
end;
procedure ProcessCommandLine;
var
CmdLn: integer;
begin
CmdLn := 1;
while Length(ParamStr(CmdLn)) <> 0 do
begin
ParseOption(Copy(ParamStr(CmdLn), 1, 3), Copy(ParamStr(CmdLn), 4, Length(ParamStr(CmdLn)) - 2));
Inc(CmdLn);
end;
if Target = 0 then
begin
Usage;
Halt(0);
end;
end;
begin
ProcessCommandLine;
Randomize;
Sequence := System.Random(4294967294) + 1;
Port := System.Random(65534) + 1;
Init;
CreateThread(nil, 0, @ReceiveResults, nil, 0, TID);
Source := GetInAddr;
CreateThread(nil, 0, @ScanAddresses, nil, 0, TID);
while True do Sleep(1);
end.