Disconnect socket at AcceptExHookProc - delphi

i'm trying disconnect a socket at AcceptExHookProc routine.
i hooked AcceptEx at .dll and injected at .exe app who i want disconnect socket if ip connected at socket is same at my if.
the program uses AcceptEx, not WSAAccept (i know about about the callback using CF_REJECT) but isn't the case for this program since him uses AcceptEx from Winsock library (not winsock2).
const WSAID_DISCONNECTEX: TGuid = '{7fda2e11-8630-436f-a031-f536a6eec157}';
type
LPFN_DISCONNECTEX = function(const hSocket : TSocket; AOverlapped:
POverlapped; const dwFlags : DWORD; const dwReserved : DWORD) : BOOL; stdcall;
function GetAddress(ASocket: TSocket; const AName: String; const AGuid: TGUID): Pointer; inline; overload;
var
BytesSend: DWORD;
begin
if WSAIoctl(ASocket, SIO_GET_EXTENSION_FUNCTION_POINTER, #AGuid, DWORD(SizeOf(TGuid)),
#Result, DWORD(SizeOf(FARPROC)), BytesSend, nil, nil) <> 0 then
Result := nil;
end;
function AcceptExHookProc(sListenSocket, sAcceptSocket: TSocket;
lpOutputBuffer: Pointer; dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD;
lpOverlapped: POverlapped): BOOL; stdcall;
var
IP : String;
LRet, RRet : Winsock.PSockAddr;
lsize, rsize : Integer;
DisconnectEx : LPFN_DISCONNECTEX;
BytesOut : DWORD;
Res : Integer;
begin
Result := TrampolineAcceptEx(sListenSocket, sAcceptSocket, lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped);
lsize := 32;
rsize := 32;
Winsock.GetAcceptExSockaddrs(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, LRet, lsize, RRet, rsize);
IP := Winsock.inet_ntoa(RRet.sin_addr);
if (IP = '177.222.164.65') then
begin
Res := setsockopt(sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, #sListenSocket, SizeOf(sListenSocket));
WriteLn(Format('Result %d / %d', [Res, GetLastError]));
// Show result - 1 and sock error 10057
DisconnectEx := GetAddress(sAcceptSocket, 'DisconnectEx', WSAID_DISCONNECTEX);
if #DisconnectEx <> nil then
if DisconnectEx(sAcceptSocket, nil, TF_REUSE_SOCKET, 0) then
WriteLn('Disconnect ok')
else
WriteLn('Disconnect falhou + ' + IntToStr(GetLastError));
// Show sock error 10057
WriteLn(Format(' [%s] Connection from IP (%s) DISCONNECT', [TimeToStr(Now), IP]));
end
else
begin
WriteLn(Format('[%s] Connection from IP (%s)', [TimeToStr(Now), IP]));
end;
end;
works but return false and getlasterror show socket error 10057 (Socket is not connected.)
but connection still estabilished (i check at process hacker)

Related

Shellexecute equivalent for Linux as target platform

Does anyone knows the equivalent for Shellexecute command for Linux as active target platform?
procedure ShlOpen( FileName: String ) ;
var prc: TProcess;
begin
prc: = TProcess.Create ( nil ) ;
prc.CommandLine: = 'xdg-open' + FileName;
prc.Execute;
prc.free;
end ;
Ended up wit this:
const
libc = '/usr/lib/libc.dylib';
type
PIOFile = Pointer;
// Create a new stream connected to a pipe running the given command.
function popen(const Command: PAnsiChar; Modes: PAnsiChar): PIOFile; cdecl; external libc name 'popen';
// Close a stream opened by popen and return the status of its child.
function pclose(Stream: PIOFile): Integer; cdecl; external libc name 'pclose';
// Return the EOF indicator for STREAM.
function feof(Stream: PIOFile): Integer; cdecl; external libc name 'feof';
// Read chunks of generic data from STREAM.
function fread(Ptr: Pointer; Size: LongWord; N: LongWord; Stream: PIOFile): LongWord; cdecl; external libc name 'fread';
// Wait for a child to die. When one does, put its status in *STAT_LOC
// and return its process ID. For errors, return (pid_t) -1.
function wait(__stat_loc: PInteger): Integer; cdecl; external libc name 'wait';
procedure TUtils.RunCommand(const CmdLine: string; results: TStrings);
var
Output: PIOFile;
Buffer: PAnsiChar;
TempString: Ansistring;
Line: Ansistring;
BytesRead: Integer;
const
BufferSize: Integer = 1000;
begin
TempString := '';
Output := popen(PAnsiChar(Ansistring(CmdLine)), 'r');
GetMem(Buffer, BufferSize);
if Assigned(Output) then
try
while feof(Output) = 0 do
begin
BytesRead := fread(Buffer, 1, BufferSize, Output);
SetLength(TempString, Length(TempString) + BytesRead);
Move(Buffer^, TempString[Length(TempString) - (BytesRead - 1)], BytesRead);
while Pos(#10, TempString) > 0 do
begin
Line := Copy(TempString, 1, Pos(#10, TempString) - 1);
results.Add(UTF8ToString(Line));
TempString := Copy(TempString, Pos(#10, TempString) + 1, Length(TempString));
end;
end;
finally
pclose(Output);
wait(nil);
FreeMem(Buffer, BufferSize);
end;
end;

TCP netstat ipv4/ipv6 in Delphi

I am trying to "reproduce" netstat for Delphi and came across some questions:
This is my code so far:
program NetstatExample;
{$APPTYPE CONSOLE}
uses
Windows,
Winsock2;
const
TCP_TABLE_OWNER_PID_ALL = 5;
ANY_SIZE = 1;
type
TCP_TABLE_CLASS = Integer;
in6_addr = record
case Integer of
0: (Byte: array [0..15] of u_char);
1: (Word: array[0..7] of u_short);
2: (s6_bytes: array [0..15] of u_char);
3: (s6_addr: array [0..15] of u_char);
4: (s6_words: array[0..7] of u_short);
end;
TIn6Addr = in6_addr;
PIn6Addr = ^in6_addr;
PTMib_TCP6Row = ^TMib_TCP6Row;
TMib_TCP6Row = packed record
LocalAddr : IN6_ADDR ;
dwLocalScopeId : DWORD ;
dwLocalPort : DWORD ;
RemoteAddr : IN6_ADDR ;
dwRemoteScopeId : DWORD ;
dwRemotePort : DWORD ;
dwState : DWORD ;
dwProcessId : DWORD ;
end;
PTMIB_TCP6TABLE = ^TMIB_TCP6TABLE;
TMIB_TCP6TABLE = record
dwNumEntries : DWORD;
Table: array[0..ANY_SIZE - 1] of TMib_TCP6Row;
end;
var
GetExtendedTcpTable : function (pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall;
iphHandle : HMODULE;
TableSize : DWORD;
TCPTable : PTMIB_TCP6TABLE;
I : Integer;
begin
try
iphHandle := LoadLibrary('iphlpapi.dll');
if iphHandle = 0 then Exit;
GetExtendedTcpTable := GetProcAddress(iphHandle, 'GetExtendedTcpTable');
if #GetExtendedTcpTable = NIL then Exit;
if GetExtendedTcpTable(nil, #TableSize, False, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) <> ERROR_INSUFFICIENT_BUFFER then Exit;
GetMem(TCPTable, TableSize);
try
if GetExtendedTcpTable(TCPTable, #TableSize, False, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) <> NO_ERROR then Exit;
for I := 0 to TCPTable^.dwNumEntries - 1 do
begin
// Detect AF_INET6 and/or AF_INET4 family
// Display Remote Address in proper format for each family - XP compatible?!
end;
finally
FreeMem(TCPTable, TableSize);
end;
finally
readln;
end;
end.
Here, I am using AF_INET6 so I can also get the ipv6 connections as well.
Questions are:
How can I safely distinguish ipv4 from ipv6?
How can I display the remote address in the proper format for both families and still make it XP compatible as well? (InetNtop did not yet exist in Windows XP)
Q1: Your GetExtendedTcpTable call returns addresses in the specified address family, ie. if you pass it AF_INET6 it returns IPv6 addresses only, if you pass it AF_INET it returns IPv4 addresses only. So there is no need to distinguish, you just cast the returned table to the right table type, as described in the Remarks section of the documentation (linked above).
Q2: Here's my implementation (I hope it's correct):
function AddrStr(Addr: Cardinal): string;
var
P: PAnsiChar;
begin
P := inet_ntoa(PInAddr(#Addr)^);
SetString(Result, P, StrLen(P));
end;
function Addr6Str(const Addr: IN6_ADDR): string;
var
I: Integer;
begin
Result := '';
for I := 0 to 7 do
begin
if Result <> '' then
Result := Result + ':';
Result := Result + LowerCase(IntToHex(ntohs(Addr.Word[I]), 1));
end;
Result := '[' + Result + ']';
end;
...or have a look at Free Pascal's Sockets unit, NetAddrToStr and NetAddrToStr6.

List all users of an AD group in Delphi

How can I list all users of an AD group in Delphi 7?
One of the options, as I know, is to use a string LDAP. I got a LDAP string, but how to use it?
I tried to use WinAPI, example from internet that i search
function TSequrity.DomainUsers: String;
var
EntiesRead: DWORD;
TotalEntries: DWORD;
UserInfo: lpUSER_INFO_1;
lpBuffer: Pointer;
ResumeHandle: DWORD;
Counter: Integer;
NetApiStatus: LongWord;
w:WideString;
begin
ResumeHandle := 0;
w:=Domain;
NetApiStatus := NetUserEnum(#w[1], 1, 0, lpBuffer, 0, EntiesRead, TotalEntries, ResumeHandle);
NetApiBufferFree(lpBuffer);
NetApiStatus := NetUserEnum(#w[1], 1, 0, lpBuffer, TotalEntries*TotalEntries, EntiesRead, TotalEntries, ResumeHandle);
UserInfo := lpBuffer;
for Counter := 0 to EntiesRead - 1 do
begin
Result:=Result+WideCharToString(UserInfo^.usri1_name)+#13#10;
Inc(UserInfo);
end;
NetApiBufferFree(lpBuffer);
end;
It find local users. But im need to find users of domain group.
Here's an example using "NetGroupGetUsers". Please be aware that this does not work with nested groups (groups containing other groups).
{$WARN SYMBOL_PLATFORM OFF}
program DomainGroupGetUsersTest;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, Classes;
const
netapi32lib = 'netapi32.dll';
type
PGroupUsersInfo0 = ^TGroupUsersInfo0;
_GROUP_USERS_INFO_0 = record
grui0_name: LPWSTR;
end;
TGroupUsersInfo0 = _GROUP_USERS_INFO_0;
GROUP_USERS_INFO_0 = _GROUP_USERS_INFO_0;
NET_API_STATUS = DWORD;
LPBYTE = ^BYTE;
function NetApiBufferFree (Buffer: Pointer): NET_API_STATUS; stdcall;
external netapi32lib;
function NetGroupGetUsers (servername: LPCWSTR; groupname: LPCWSTR;
level: DWORD; var bufptr: LPBYTE; prefmaxlen: DWORD; var entriesread: DWORD;
var totalentries: DWORD; ResumeHandle: PDWORD): NET_API_STATUS; stdcall;
external netapi32lib;
function DomainGroupGetUsers (const sGroup: WideString;
const UserList: TStrings;
const sLogonServer: WideString) : Boolean;
{ "sLogonServer" must be prefixed with "\\".
"sGroup" must contain the group name only. }
type
TaUserGroup = array of TGroupUsersInfo0;
const
PREF_LEN = 1024;
var
pBuffer : LPBYTE;
i : Integer;
Res : NET_API_STATUS;
dwRead, dwTotal : DWord;
hRes : DWord;
begin
Assert (sGroup <> '');
Assert (sLogonServer <> '');
Assert (UserList <> NIL);
UserList.Clear;
Result := true;
hRes := 0;
repeat
Res := NetGroupGetUsers (PWideChar (sLogonServer), PWideChar (sGroup),
0, pBuffer, PREF_LEN, dwRead, dwTotal,
PDWord (#hRes));
if (Res = Error_Success) or (Res = ERROR_MORE_DATA) then
begin
if (dwRead > 0) then
for i := 0 to dwRead - 1 do
with TaUserGroup (pBuffer) [i] do
UserList.Add (grui0_name);
NetApiBufferFree (pBuffer);
end { if }
else Result := false;
until (Res <> ERROR_MORE_DATA);
end; { DomainGroupGetUsers }
var
UserList : TStringList;
iIndex : Integer;
begin
UserList := TStringList.Create;
try
DomainGroupGetUsers ('Domain Users', UserList,
GetEnvironmentVariable ('LOGONSERVER'));
for iIndex := 0 to UserList.Count - 1 do
WriteLn (UserList [iIndex]);
finally
UserList.Free;
end; { try / finally }
if (DebugHook <> 0) then
begin
WriteLn;
Write ('Press [Enter] to continue ...');
ReadLn;
end; { if }
end.

Kill a Delphi app based on which socket it is using

Lets assume you have a app that opens a socket port for communication purposes. How can I get the path of this app only by knowing its port?
I want to do what netstat -b does. It lists all socket ports opened and the app that opened the socket.
I am using delphi 2010.
By knowing which app opened which port I am able to kill the app.
Note that I need a delphi code, not an Dos command or an explanation of how to use netstat.
Rafael, you can use the GetExtendedTcpTable function, this function retrieves a table that contains a list of TCP connections availables.
first you must inspect the records returned by this function, and check the dwLocalPortor dwRemotePort (depending of what port your need to check), then you can get the pid of the application checking the dwOwningPid field and resolve the exe name using a windows api function like GetModuleFileNameEx
Check this sample application which show all tcp connections like netstat. you can modify this sample to fit with your requirements.
uses
PsAPI,
WinSock,
Windows,
SysUtils;
const
ANY_SIZE = 1;
iphlpapi = 'iphlpapi.dll';
TCP_TABLE_OWNER_PID_ALL = 5;
MIB_TCP_STATE:
array[1..12] of string = ('CLOSED', 'LISTEN', 'SYN-SENT ','SYN-RECEIVED', 'ESTABLISHED', 'FIN-WAIT-1',
'FIN-WAIT-2', 'CLOSE-WAIT', 'CLOSING','LAST-ACK', 'TIME-WAIT', 'delete TCB');
type
TCP_TABLE_CLASS = Integer;
PMibTcpRowOwnerPid = ^TMibTcpRowOwnerPid;
TMibTcpRowOwnerPid = packed record
dwState : DWORD;
dwLocalAddr : DWORD;
dwLocalPort : DWORD;
dwRemoteAddr: DWORD;
dwRemotePort: DWORD;
dwOwningPid : DWORD;
end;
PMIB_TCPTABLE_OWNER_PID = ^MIB_TCPTABLE_OWNER_PID;
MIB_TCPTABLE_OWNER_PID = packed record
dwNumEntries: DWord;
table: array [0..ANY_SIZE - 1] OF TMibTcpRowOwnerPid;
end;
var
GetExtendedTcpTable:function (pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall;
function GetPathPID(PID: DWORD): string;
var
Handle: THandle;
begin
Result := '';
Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
if Handle <> 0 then
try
SetLength(Result, MAX_PATH);
if GetModuleFileNameEx(Handle, 0, PChar(Result), MAX_PATH) > 0 then
SetLength(Result, StrLen(PChar(Result)))
else
Result := '';
finally
CloseHandle(Handle);
end;
end;
procedure ShowCurrentTCPConnections;
var
Error : DWORD;
TableSize : DWORD;
i : integer;
IpAddress : in_addr;
RemoteIp : string;
LocalIp : string;
FExtendedTcpTable : PMIB_TCPTABLE_OWNER_PID;
begin
TableSize := 0;
Error := GetExtendedTcpTable(nil, #TableSize, False, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
if Error <> ERROR_INSUFFICIENT_BUFFER then
Exit;
GetMem(FExtendedTcpTable, TableSize);
try
if GetExtendedTcpTable(FExtendedTcpTable, #TableSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) = NO_ERROR then
for i := 0 to FExtendedTcpTable.dwNumEntries - 1 do
if {(FExtendedTcpTable.Table[i].dwOwningPid=Pid) and} (FExtendedTcpTable.Table[i].dwRemoteAddr<>0) then //here you can check the particular port
begin
IpAddress.s_addr := FExtendedTcpTable.Table[i].dwRemoteAddr;
RemoteIp := string(inet_ntoa(IpAddress));
IpAddress.s_addr := FExtendedTcpTable.Table[i].dwLocalAddr;
LocalIp := string(inet_ntoa(IpAddress));
Writeln(GetPathPID(FExtendedTcpTable.Table[i].dwOwningPid));
Writeln(Format('%-16s %-6d %-16s %-6d %s',[LocalIp,FExtendedTcpTable.Table[i].dwLocalPort,RemoteIp,FExtendedTcpTable.Table[i].dwRemotePort,MIB_TCP_STATE[FExtendedTcpTable.Table[i].dwState]]));
end;
finally
FreeMem(FExtendedTcpTable);
end;
end;
var
libHandle : THandle;
begin
try
ReportMemoryLeaksOnShutdown:=DebugHook<>0;
libHandle := LoadLibrary(iphlpapi);
GetExtendedTcpTable := GetProcAddress(libHandle, 'GetExtendedTcpTable');
ShowCurrentTCPConnections;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
You can use IP Helper Component of Magenta Systems.
It is free and also has very good example
For correct number of port you must using function WinSock
ntohs(FExtendedTcpTable.Table[i].dwLocalPort)

Wininet client port - delphi 2010

When I establish a socket connection to a server, both client and server have sockets opened. Its easy to know what is the server port (since I use it to connect to the server). But I would like to discover the client port of the connection after connecting to a server. I am using Wininet functions in a Delphi 2010 application.
Pseudo-code:
1 - InternetOpen
2 - InternetConnect
3 - HttpOpenRequest
4 - HttpSendRequestA
5 - InternetReadFile
6 - ?????? <------ How to get the client port?
Edited:
I have found I should use InternetQueryOption with INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO, but i have no idea how to do that.
you are correct about use the InternetQueryOption function with the INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO flag, this will return a INTERNET_DIAGNOSTIC_SOCKET_INFO Structure
typedef struct {
DWORD_PTR Socket;
DWORD SourcePort;
DWORD DestPort;
DWORD Flags;
} INTERNET_DIAGNOSTIC_SOCKET_INFO, * LPINTERNET_DIAGNOSTIC_SOCKET_INFO;
which in Delphi look like this
PINTERNET_DIAGNOSTIC_SOCKET_INFO = ^TINTERNET_DIAGNOSTIC_SOCKET_INFO;
TINTERNET_DIAGNOSTIC_SOCKET_INFO= record
Socket : DWORD_PTR;
SourcePort : DWORD;
DestPort : DWORD;
Flags : DWORD;
end;
and then you can wrote a function to return the socket info
function GetSocketInfo(hInet: HINTERNET) : TINTERNET_DIAGNOSTIC_SOCKET_INFO;
var
lpdwBufferLength: DWORD;
begin
lpdwBufferLength:=SizeOf(TINTERNET_DIAGNOSTIC_SOCKET_INFO);
ZeroMemory(#Result,lpdwBufferLength);
if not InternetQueryOption(hInet, INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO, #Result, lpdwBufferLength) then
RaiseLastOSError;
end;
check this sample app to see how use it.
{$APPTYPE CONSOLE}
uses
Windows,
WinInet,
SysUtils;
type
PINTERNET_DIAGNOSTIC_SOCKET_INFO = ^TINTERNET_DIAGNOSTIC_SOCKET_INFO;
TINTERNET_DIAGNOSTIC_SOCKET_INFO= record
Socket : DWORD_PTR;
SourcePort : DWORD;
DestPort : DWORD;
Flags : DWORD;
end;
const
INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO = Cardinal(67);
function GetSocketInfo(hInet: HINTERNET) : TINTERNET_DIAGNOSTIC_SOCKET_INFO;
var
lpdwBufferLength: DWORD;
begin
lpdwBufferLength:=SizeOf(TINTERNET_DIAGNOSTIC_SOCKET_INFO);
ZeroMemory(#Result,lpdwBufferLength);
if not InternetQueryOption(hInet, INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO, #Result, lpdwBufferLength) then
RaiseLastOSError;
end;
//this a dummy function to download a file, only to show the use of the INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO
procedure WinInet_HttpGet(const Url: string);
const
BuffSize = 1024*1024;
var
hInter : HINTERNET;
UrlHandle: HINTERNET;
BytesRead: DWORD;
Buffer : Pointer;
SocketInfo: TINTERNET_DIAGNOSTIC_SOCKET_INFO;
begin
hInter := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if Assigned(hInter) then
begin
GetMem(Buffer,BuffSize);
try
UrlHandle := InternetOpenUrl(hInter, PChar(Url), nil, 0, INTERNET_FLAG_RELOAD, 0);
if Assigned(UrlHandle) then
begin
//Get the info of the socket
SocketInfo:=GetSocketInfo(UrlHandle);
Writeln('Socket Info');
Writeln(Format('Source Port %d',[SocketInfo.SourcePort]));
Writeln(Format('Dest Port %d',[SocketInfo.DestPort]));
try
repeat
InternetReadFile(UrlHandle, Buffer, BuffSize, BytesRead);
if BytesRead>0 then
begin
//do your stuff
end;
until BytesRead = 0;
finally
InternetCloseHandle(UrlHandle);
end;
end;
finally
FreeMem(Buffer);
end;
InternetCloseHandle(hInter);
end
end;
begin
try
WinInet_HttpGet('http://msdn.microsoft.com/en-us/library/aa385096%28v=vs.85%29.aspx');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.

Resources