Winsock closesocket problem

c++ / delphi package - dll injection and api hooking
Post Reply
Mr. FancyPants
Posts: 17
Joined: Sun May 30, 2004 1:27 pm

Winsock closesocket problem

Post by Mr. FancyPants »

Hi, i'm trying to make a program to boot/ban people from my server. Everything works fine until the socket has to be closed. The closesocket function returns 0, which means that the function was succesful, but the client doesn't get disconnected. Here's the code from the dll:

Code: Select all

library T2Boot;

uses
  madCodeHook,
  Windows,
  WinSock,
  SysUtils;

type TConType = (ctClient, ctServer, ctUnknown);

type TPackage = record
  Msg: array[0..MAX_PATH] of Char;
  ParamStr: array[0..1023] of Char;
  ParamInt: Integer;
end;

var
  ConType: TConType;
  listen_NextHook: function(s: TSocket; backlog: Integer): Integer; stdcall;
  accept_NextHook: function(s: TSocket; addr: PSockAddr; addrlen: PInteger): TSocket; stdcall;

function listen_HookProc(s: TSocket; backlog: Integer): Integer; stdcall;
begin
  ConType := ctServer;
  Result := listen_NextHook(s, backlog);
end;

function accept_HookProc(s: TSocket; addr: PSockAddr; addrlen: PInteger): TSocket; stdcall;
var Package: TPackage;
    Resp: Boolean;
    address: TSockAddr;
    addresslen: Integer;
begin
  Result := accept_NextHook(s, addr, addrlen);
  getpeername(Result, address, addresslen);
  if Result <> SOCKET_ERROR then
  begin
    Package.Msg := 'accept';
    StrPCopy(@Package.ParamStr, inet_ntoa(address.sin_addr));
    Package.ParamInt := Result;
    if SendIpcMessage('TheBootQueue', @Package, SizeOf(Package), @Resp, SizeOf(Resp)) then
      if Resp then
        if closesocket(Result) = 0 then
          Windows.Beep(500,100);
  end;
end;

{$R *.res}

begin
  HookApi('wsock32.dll', 'listen', @listen_HookProc, @listen_NextHook);
  HookApi('wsock32.dll', 'accept', @accept_HookProc, @accept_NextHook);

  ConType := ctUnknown;
end.
I hope you can help me out,

BTW i removed some of the unimportant or unused code.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Perhaps you need to "shutdown" the socket before closing it? No idea, I'm no socket expert.

Perhaps you can call SendIpcMessage before calling the original accept API? Then if you don't like the connection, you don't call the original accept API at all, but refuse the accept?
Mr. FancyPants
Posts: 17
Joined: Sun May 30, 2004 1:27 pm

Post by Mr. FancyPants »

Thx, but the only way to retrieve the real address and socket of the client is to call the real accept function first, otherwise the address will be something like 1.0.0.0 and the socket will be -1 (SOCKET_ERROR). shutdown is only used if you want to close the connection gracefully and is not neccesary. Anyways, I've allready solved the problem :D .

I need to know how to call a function in the injected DLL. Do I need to create a second IPC queue in the DLL, so my program can send info to the DLL. Or can both the DLL and the program read from and write to the same queue. Or maybe I could use RemoteExecute. In other words I need to know if it is possible to communicate in both ways and how to do it without letting the DLL send messages all the time and wait for a response telling the DLL what do to.

Thanks in advance.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Mr. FancyPants wrote:Anyways, I've allready solved the problem
Please tell us how. Might be useful for other people. Thanks!
Mr. FancyPants wrote:I need to know how to call a function in the injected DLL. Do I need to create a second IPC queue in the DLL, so my program can send info to the DLL. Or can both the DLL and the program read from and write to the same queue. Or maybe I could use RemoteExecute. In other words I need to know if it is possible to communicate in both ways and how to do it without letting the DLL send messages all the time and wait for a response telling the DLL what do to.
For what purpose do you need that? Ideally the app should create a global memory mapping (CreateGlobalFileMapping) and the dll should open it and read from there. If you can get along without that the application sends the dll a notification, that would be the best way. The app can always update that memory mapping and the dll will have the up to date information. If the app needs to notify the dll on its own, things get more difficult - especially because when doing system wide API hooking there will be dozens instances of your dll running.
Mr. FancyPants
Posts: 17
Joined: Sun May 30, 2004 1:27 pm

Post by Mr. FancyPants »

madshi wrote:
Mr. FancyPants wrote:Anyways, I've allready solved the problem
Please tell us how. Might be useful for other people. Thanks!
The code at the top of this page DOES work. I edited the post a few minutes after I started this topic and forgot to tell that it was solved, sorry :oops: . I changed closesocket(s) to closesocket(Result).
madshi wrote:For what purpose do you need that?
The closesocket function called from within the accept hook will only work for players that are allready banned. But I need to able to kick/ban players at any time. So I somehow have to call the closesocket function in the target process, i.e. when someone pushes the 'kick' button in my program.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Well, that's not too easy. You can create an IPC queue in each dll. But you have to use a different name for each dll, because each IPC queue name may only be used once, while your dll is loaded multiple times (once for each process).

Alternatively you could create a thread in the target process, either by using CreateRemoteThreadEx or by calling RemoteExecute. RemoteExecute also copies the function which you want to be executed to the target process. When using CreateRemoteThreadEx the code must already be in the target process. You could e.g. jump to a function which your hook dll exports. But your app would have to find out at which address the function can be reached.
Mr. FancyPants
Posts: 17
Joined: Sun May 30, 2004 1:27 pm

Post by Mr. FancyPants »

Thanks, I found the address of the function i needed to call. And I used CreateRemoteThreadEx and it worked fine.

Here is the code:

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
var tid, th: dword;
begin
  if Clients.ItemIndex > 0 then
  begin
    th := CreateRemoteThreadEx(Process('TheGame.exe').Handle.Handle, nil, 0, Ptr($01706730), PInteger(Client[Clients.ItemIndex-1].Socket), 0, tid);
    WaitForSingleObject(th, INFINITE);
    CloseHandle(th);
  end;
end;
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Please note that your dll can only be loaded at the wanted image base address in all the running processes, if the wanted image base address it not in use yet. Otherwise your dll will get relocated. In that case the addresses of the exported functions will change.
Post Reply