{
[email protected]
}
program DGG;
{$APPTYPE CONSOLE}
uses
SysUtils,
Windows,
Sockets;
function gg_login_hash(password: PAnsiChar; seed: Cardinal) : Integer;
var
x, y, z: Integer;
begin
y := seed;
x := 0;
while (password^ <> AnsiChar(nil)) do begin
x := (x and $ffffff00) or Ord(password^);
y := y xor x;
y := y + x;
x := x shl 8;
y := y xor x;
x := x shl 8;
y := y - x;
x := x shl 8;
y := y xor x;
z := y and $1f;
y := (y shl z) or (y shr (32 - z));
password := password + 1;
end;
result := y;
end;
procedure connect(gg_id: Integer; gg_pass: PAnsiChar);
type
gg_header = record
t: Integer;
l: Integer;
end;
s_gg_login80 = packed record
uin: Integer;
language: array[1..2] of AnsiChar;
hash_type: Byte;
hash: array [1..64] of AnsiChar;
status: Integer;
flags: Integer;
features: Integer;
local_ip: Integer;
local_port: SmallInt;
external_ip: Integer;
external_port: SmallInt;
image_size: Byte;
unknown2: Byte;
version_len: Integer;
version: array[1..$21] of AnsiChar;
description_size: Integer;
end;
var
socket: TTcpClient;
i_tmp: Integer;
garbage: Pointer; // Tutaj beda tymczasowo odbierane wszystkie smieci
header : gg_header;
out_login: s_gg_login80;
seed: Cardinal;
const GG_WELCOME = $0001;
const GG_LOGIN80 = $0031;
const GG_LOGIN_HASH_GG32 = $01;
const GG_LOGIN_HASH_SHA1 = $02;
const GG_LOGIN80_OK = $0035;
const GG_STATUS_AVAIL = $0002;
const GG_LOGIN_FAILED = $0009;
const GG_DISCONNECTING = $000b;
begin
socket := TTcpClient.Create(nil);
socket.RemoteHost := '91.197.13.35';
socket.RemotePort := '443';
if not socket.Connect then begin
socket.Destroy;
WriteLn('Unable to connect');
exit()
end;
while socket.ReceiveBuf(header, SizeOf(gg_header)) > 0 do begin
if (header.t = GG_WELCOME) then begin
WriteLn('GG Welcome');
socket.ReceiveBuf(i_tmp, SizeOf(i_tmp));
seed := i_tmp;
ZeroMemory(@out_login, SizeOf(out_login));
header.t := GG_LOGIN80;
header.l := SizeOf(out_login);
out_login.uin := gg_id;
out_login.hash_type := GG_LOGIN_HASH_GG32;
out_login.status := GG_STATUS_AVAIL;
out_login.features := $00000007; // Bo tak ma byc
out_login.unknown2 := $64; // Bo tak ma byc
out_login.version_len := SizeOf(out_login.version);
out_login.description_size := 0; // I tak jest wyzerowane, ale to tak dla pamieci, ze nie mamy opisu
CopyMemory(@out_login.language, PAnsiChar('pl'), 2); { Dlaczego tak? A no bo po to, zeby miec pewnosc, z
ze Delphi nie dolozy magicznie na koniec NULLa. }
CopyMemory(@out_login.version, PAnsiChar('Gadu-Gadu Client build 8.0.0.7669'), SizeOf(out_login.version));
i_tmp := gg_login_hash(gg_pass, seed); // Obliczamy hasha
CopyMemory(@out_login.hash, @i_tmp, SizeOf(i_tmp));
socket.SendBuf(header, SizeOf(header));
socket.SendBuf(out_login, SizeOf(out_login));
WriteLn('Sent login data');
end else if (header.t = GG_LOGIN80_OK) then begin
WriteLn('Logged in');
if (header.l > 0) then begin
GetMem(garbage, header.l);
socket.ReceiveBuf(garbage, header.l, 1);
FreeMem(garbage);
end;
end else if (header.t = GG_LOGIN_FAILED) then begin
WriteLn('Wrong password');
socket.Disconnect;
end else if (header.t = GG_DISCONNECTING) then begin
WriteLn('Received GG_DISCONNECTING');
socket.Disconnect;
end else begin
WriteLn('Unknown header');
// Odbieramy smieci
if (header.l > 0) then begin
GetMem(garbage, header.l);
socket.ReceiveBuf(garbage, header.l);
FreeMem(garbage);
end;
end;
end;
WriteLn('Disconnected.');
socket.Destroy;
ReadLn;
end;
var
buff_in: AnsiString;
gg_id: Integer;
begin
try
Write('Numerek: ');
ReadLn(buff_in);
if StrToIntDef(String(buff_in), 0) = 0 then begin
WriteLn('Bledny numer');
exit();
end;
gg_id := StrToIntDef(String(buff_in), 0);
Write('Haslo: ');
ReadLn(buff_in);
WriteLn('gg_id=' + IntToStr(gg_id) + ' gg_pass=' + String(buff_in));
WriteLn('[@] Start');
connect(gg_id, PAnsiChar(buff_in));
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.