📄 class_qqonline.~pas
字号:
//挂QQ服务端,如需WEB版挂QQ的,自己来改造,本人现在没有精力改造了
//QQ:709582502 Email:Touchboy@126.com 不需要的东西都已经取消了
//提供该程序只是用来学习目的,千万不要用于非法用途,后果自负
//用到RX控件,和JCL库,请大家自行下载
//如果不能挂QQ的话,那就请看LumqQQ中的相关协议,改成新协议即可
//如有更新希望发一份给我
unit Class_QQONLine;
interface
uses
Windows,Messages, SysUtils, Variants, Classes,ExtCtrls,
MSWinsockLib_TLB,Class_QQTEA,Class_Record,Class_QQOUTPacket,
Class_QQInPacket,Class_QQDB;
Type
TQQOnLine=Class
private
FUDPSock :array [1..MAXUDPOnLineNum] of TWinSock;
FKeepLiveTime:TTimer;
FErrorTime :TTimer;
FLoginTime :TTimer;
FUDPServer:Array [1..7] of String;
//FAutoReplay: String;
procedure OnKeepLiveTime(Sender:TObject);
procedure OnErrorTime(Sender:TObject);
procedure OnLoginTime(Sender:TObject);
procedure OnDataArrival(ASender: TObject; bytesTotal: Integer);
procedure OnError(ASender: TObject; Number: Smallint;
var Description: WideString; Scode: Integer; const Source,
HelpFile: WideString; HelpContext: Integer;
var CancelDisplay: WordBool);
procedure UPDSendData(Index:integer;SendData:TMYByte;nSendLen:Integer);
public
constructor Create(nKeepLiveTime,nError,nLoginTime:Integer;TCPForm:TComponent);
destructor Destroy; override;
procedure ResetServer(Index:integer);
procedure Login(Index,QQNum: Integer; QQPassWord:String;QQHide: Boolean;QQAutoReplay: String;
OneHour,OneMin,TwoHour,TwoMin,UserType:integer);
procedure ReLogin(Index:integer);
procedure Clear(Index:integer);
procedure LogOut(Index:integer);
procedure StopQQ;
Function GetOnLineTime(Index:integer):String;
//property AutoReplay:String Read FAutoReplay Write FAutoReplay;
end;
var
QQOnLine:TQQOnLine;
implementation
Uses NWSystem,JclDateTime,NWDateTime;
{ TQQOnLine }
constructor TQQOnLine.Create(nKeepLiveTime, nError, nLoginTime: Integer;
TCPForm: TComponent);
var
i:integer;
begin
SocketNextSearch :=1;
For i:=1 to MAXUDPOnLineNum do
begin
FUDPSock[i] :=TWinSock.Create(TCPForm);
FUDPSock[i].Tag :=i;
FUDPSock[i].OnError :=OnError;
FUDPSock[i].OnDataArrival :=OnDataArrival;
FUDPSock[i].Protocol :=1;
end;
{FUDPSock :=TWinSock.Create(TCPForm);
FUDPSock.OnError :=OnError;
FUDPSock.OnDataArrival :=OnDataArrival;
}
FKeepLiveTime :=TTimer.Create(Nil);
FKeepLiveTime.Interval:=nKeepLiveTime;
FKeepLiveTime.OnTimer :=OnKeepLiveTime;
FErrorTime :=TTimer.Create(Nil);
FErrorTime.Interval:=nError;
FErrorTime.OnTimer :=OnErrorTime;
FLoginTime :=TTimer.Create(Nil);
FLoginTime.Interval:=nLoginTime;
FLoginTime.OnTimer :=OnLoginTime;
FUDPServer[1]:='sz.tencent.com';
FUDPServer[2]:='sz4.tencent.com';
FUDPServer[3]:='sz3.tencent.com';
FUDPServer[4]:='sz4.tencent.com';
FUDPServer[5]:='sz5.tencent.com';
FUDPServer[6]:='sz6.tencent.com';
FUDPServer[7]:='sz7.tencent.com';
FLoginTime.Enabled :=True;
FErrorTime.Enabled :=True;
FKeepLiveTime.Enabled :=True;
end;
destructor TQQOnLine.Destroy;
var
i:integer;
begin
FKeepLiveTime.Enabled:=False;
FErrorTime.Enabled :=False;
FLoginTime.Enabled :=False;
FreeAndNil(FKeepLiveTime);
FreeAndNil(FErrorTime);
FreeAndNil(FLoginTime);
For i:=1 to MAXUDPOnLineNum do
begin
FUDPSock[i].Close;
FreeAndNil(FUDPSock[i]);
end;
inherited;
end;
procedure TQQOnLine.Login(Index,QQNum: Integer; QQPassWord: String;
QQHide: Boolean; QQAutoReplay: String;OneHour,OneMin,TwoHour,TwoMin,UserType:integer);
var
I:integer;
PasswordKey:TMyByte;
MYOne,MyTwo:MD5Digest;
sSend:String;
Send:Array of Byte;
S:String;
begin
//Randomize;
If (QQNum = 0) Or (QQPassWord ='') Then Exit;
QQInfo[Index].QQNumber :=QQNum;
QQInfo[Index].QQPassword :=QQPassword;
QQInfo[Index].QQAutoReply:=QQAutoReplay;
QQInfo[Index].QQHide :=QQHide;
QQinfo[Index].OneHour :=OneHour;
QQinfo[Index].OneMin :=OneMin;
QQinfo[Index].TwoHour :=TwoHour;
QQinfo[Index].TwoMin :=TwoMin;
QQinfo[Index].UserType :=UserType;
QQinfo[Index].OnLineMin :=HourTwoToMin(OneHour,OneMin,TwoHour,TwoMin);
MYOne :=MD5String(QQInfo[Index].QQPassword);
SetLength(S,16);
CopyMemory(@S[1],@MyOne[0],16);
MyTwo :=MD5String(S);
For I := 0 To 15 do
begin
QQInfo[Index].PasswordKey[i] :=MyTwo[i];
QQInfo[Index].LoginKey[I] :=Trunc(Random * 256);
end;
ReLogin(index);
end;
procedure TQQOnLine.ReLogin(Index: integer);
var
sSend:String;
Send:Array of Byte;
SendData:TMyByte;
begin
if QQInfo[Index].QQNumber=0 then Exit;
{
if (QQInfo[Index].TwoHour>HourOfTime(NOW)) then
begin
QQInfo[Index].State := QsNotTime;
Exit;
end;
if (QQInfo[Index].TwoHour=HourOfTime(NOW)) and (QQInfo[Index].TwoMin> MinuteOfTime(NoW))then
begin
QQInfo[Index].State := QsNotTime;
Exit;
end;
}
QQInfo[Index].TimerCount :=0;
QQInfo[Index].KeepAliveCount :=1;
SendData := QQOutPacket.LoginToken(QQInfo[Index].QQNumber);
SetLength(Send,13);
Move(SendData[0],Send[0],13);
FUDPSock[Index].Close;
FUDPSock[Index].Bind;
FUDPSock[Index].RemoteHost :=QQInfo[Index].Server;
FUDPSock[Index].RemotePort :=8000;
FUDPSock[Index].SendData(Send);
end;
procedure TQQOnLine.OnDataArrival(ASender: TObject; bytesTotal: Integer);
var
Buff:Array of Byte;
SessionKeyTemp:TMYByte;
ThisTime :Integer;
Stra:String;
I:integer;
v,vv,VVV,VVVV: OleVariant;
p: Pointer;
n:Integer;
MY:TMYByte;
nSendLen:integer;
SendData:Array [0..500] of byte;
index:integer;
begin
index :=TWinSock(ASender).Tag;
FUDPSock[index].GetData(v);
SetLength(Buff,bytesTotal);
p := VarArrayLock(V);
try
Move(p^, Buff[0], High(Buff)+1);
finally
VarArrayUnlock(V);
end;
n:= QQInPacket.GetPacketAbout(Buff);
Case n of
1:begin
MY:=QQOutPacket.LoginPacket(QQInfo[Index].QQNumber, QQInfo[Index].QQHide,QQInfo[Index].LoginKey, QQInfo[Index].PasswordKey,
QQInPacket.LoginTokenReply(Buff));
//QQInfo[Index].State :=QsLogin;
UPDSendData(Index,My,460);
end;
2:
begin
Stra := QQInPacket.GetLoginPacketRedirect(Buff, QQInfo[Index].LoginKey);
If Stra <> '' Then
begin
QQinfo[index].Server :=Stra;
ReLogin(Index);
Exit;
end;
Stra := QQInPacket.GetLoginPacketError(Buff, QQInfo[Index].LoginKey);
If Stra <> '' Then
begin
QQInfo[Index].ErrorString := Stra ;
QQInfo[Index].ErrorCount := QQInfo[Index].ErrorCount + 1;
If (Pos('密码',Stra)<> 0) And (Pos('错误',Stra) <> 0) Then
begin
MY:=QQOutPacket.LogoutPacket(QQInfo[Index].QQNumber,QQInfo[Index].SessionKey,QQInfo[Index].PasswordKey,nSendLen);
UPDSendData(Index,My,nSendLen);
QQInfo[Index].State := QsPassWordError;
end
Else begin
QQInfo[Index].State := QsError;
end;
Exit;
end;
QQUserDB.AddQQInfo(QQInfo[Index].QQNumber,QQInfo[Index].QQPassword,QQinfo[index].OneHour,
QQinfo[index].OneHour,QQinfo[index].TwoHour,QQinfo[index].TwoHour,0);
SessionKeyTemp := QQInPacket.GetLoginPacketSessionKey(Buff, QQInfo[Index].PasswordKey);
For I := 0 To 15 do
QQInfo[Index].SessionKey[I] := SessionKeyTemp[I];
MY:=QQOutPacket.KeepAlivePacket(QQInfo[Index].QQNumber,QQInfo[Index].SessionKey,nSendLen);
UPDSendData(Index,My,nSendLen);
QQInfo[Index].ErrorString :='';
QQInfo[Index].ErrorCount := 0;
QQInfo[Index].State := QsLoginSucess;
end;
3:begin
If QQInfo[Index].QQAutoReply <> '' Then
begin
ThisTime := QQInPacket.GetIMPacketTime(Buff, QQInfo[Index].SessionKey);
If ThisTime > QQInfo[Index].NowTime Then
begin
QQInfo[Index].NowTime := ThisTime;
MY:=QQOutPacket.SendIMPacket(QQInfo[Index].QQNumber,
QQInPacket.GetIMPacketFrom(QQInfo[Index].QQNumber, Buff, QQInfo[Index].SessionKey),
QQInfo[Index].SessionKey, ThisTime, QQInfo[Index].QQAutoReply,nSendLen);
UPDSendData(Index,My,nSendLen);
end;
end;
end;
4:begin
QQInfo[Index].KeepAliveCount := QQInfo[Index].KeepAliveCount + 1;
end;
end
end;
procedure TQQOnLine.OnError(ASender: TObject; Number: Smallint;
var Description: WideString; Scode: Integer; const Source,
HelpFile: WideString; HelpContext: Integer; var CancelDisplay: WordBool);
var
index:integer;
begin
index :=TWinSock(ASender).Tag;
FUDPSock[index].Close;
end;
procedure TQQOnLine.OnErrorTime(Sender: TObject);
var
i:integer;
begin
For i:=1 to MAXUDPOnLineNum do
begin
If QQInfo[I].ErrorCount >= 5 Then Logout(i);
If (Minute - QQInfo[I].AddTime) > 2880 Then Logout(i);
end;
end;
procedure TQQOnLine.OnKeepLiveTime(Sender: TObject);
var
i:integer;
nSendLen:integer;
MY:TMyByte;
CurrHour:Integer;
begin
For i:=1 to MAXUDPOnLineNum do
begin
If (QQInfo[I].QQNumber<>0) and (QQInfo[I].QQPassword<>'')
and (QQInfo[i].State=QsLoginSucess) Then
begin
CurrHour :=HourOfTime(NOW);
if CurrHour>QQInfo[i].TwoHour then
begin
//QQInfo[i].State := QsNotTime;
Continue;
end;
if (QQInfo[i].TwoHour=HourOfTime(NOW)) and (QQInfo[i].TwoMin> MinuteOfTime(NoW))then
begin
//QQInfo[Index].State := QsNotTime;
Continue;
end;
MY :=QQOutPacket.KeepAlivePacket(QQInfo[i].QQNumber,QQInfo[i].SessionKey,nSendLen);
UPDSendData(i,My,nSendLen);
end;
end;
end;
procedure TQQOnLine.OnLoginTime(Sender: TObject);
var
i:integer;
nSendLen:integer;
MY:TMyByte;
begin
For i:=1 to MAXUDPOnLineNum do
begin
if QQInfo[I].KeepAliveCount=0 then
begin
ReLogin(i);
QQInfo[I].KeepAliveCount :=0;
end;
If QQInfo[I].TimerCount>=20 Then
begin
QQInfo[I].TimerCount :=0;
ReLogin(i);
end;
end;
end;
procedure TQQOnLine.ResetServer(Index: integer);
begin
QQInfo[Index].Server :='sz.tencent.com';
//QQInfo[Index].Server :=FUDPServer[Rand(7)];
end;
procedure TQQOnLine.Clear(Index: integer);
var
i:integer;
begin
FUDPSock[Index].Close;
QQInfo[Index].State :=QsLogin;
QQInfo[Index].QQNumber :=0;
QQInfo[Index].QQHide :=False;
QQInfo[Index].QQPassword :='';
QQInfo[Index].QQAutoReply :='';
QQInfo[Index].ErrorCount :=0;
QQInfo[Index].ErrorString :='';
QQInfo[Index].AddTime :=0;
QQInfo[Index].NowTime :=0;
For i:=0 to 15 do
begin
QQInfo[Index].PasswordKey[i]:=0;
QQInfo[Index].LoginKey[i] :=0;
QQInfo[Index].SessionKey[i] :=0;
end;
end;
procedure TQQOnLine.LogOut(Index: integer);
var
MY:TMyByte;
nSendLen:integer;
begin
MY:=QQOutPacket.LogoutPacket(QQInfo[Index].QQNumber,QQInfo[Index].SessionKey,QQInfo[Index].PasswordKey,nSendLen);
UPDSendData(Index,My,nSendLen);
FUDPSock[Index].Close;
Clear(Index);
end;
procedure TQQOnLine.UPDSendData(Index:integer;SendData: TMYByte; nSendLen: Integer);
var
p:Pointer;
V:OleVariant;
begin
V:=VarArrayCreate([0,nSendLen-1],varByte);
p := VarArrayLock(V);
try
Move(SendData[0], p^, nSendLen);
finally
VarArrayUnlock(V);
end;
FUDPSock[Index].Close;
FUDPSock[Index].RemotePort :=8000;
FUDPSock[Index].RemoteHost :=QQinfo[index].Server;
FUDPSock[Index].Bind;
FUDPSock[Index].SendData(V);
end;
procedure TQQOnLine.StopQQ;
var
i:integer;
begin
For i:=1 to MAXUDPOnLineNum do
begin
FUDPSock[i].Close;
end;
end;
function TQQOnLine.GetOnLineTime(Index: integer): String;
begin
Result :='在'+IntTostr(QQinfo[index].OneHour)+':'+IntTostr(QQinfo[index].OneMin)+
'至'+IntTostr(QQinfo[index].TwoHour)+':'+IntTostr(QQinfo[index].TwoMin);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -