1. 首页 > 电脑教程 > 采用多线程技术实现快速批量申请QQ号码代码

采用多线程技术实现快速批量申请QQ号码代码

腾讯在其QQ免费注册页面http://reg.qq.com/中,为了限制用户注册,设置了多种限制手段,尤其是在其JS页面中设置了多种算法,防止用户批量注册。本文主要分析QQ是如何在WEB前台实现防止用户批量的注册,并且提供了相应的技术解决方案,程序早都做好了,没有外放,看到博客园上有其他人对外写了这样的文章,但是比较简陋,因此这里将我的设计方案跟各位分析一下首先看我的最终实现效果图,比较简陋一些,多线程实现的,如果有什么疑问,可以跟我联系,本人联系QQ:8112857.

在开始注册前边的框框里边输入想要一次性批量申请QQ号码的数量,然后点击开始注册,系统自动的生成相应的线程,然后开始进行排队打码,在每个输入框输入相应的注册码以后,点击回车,系统会自动的进行注册,并跳转到另外一个框框里边,并将正确的QQ号码自动保存到TXT文本里边。系统我在实现的时候,没有考虑最后的临界区的问题,因此如果在没有输入验证码,并且关闭的时候,系统会假死,当然了,这个问题不影响使用,下面我说明下我的设计方案。1.分析QQ注册提交实际上QQ注册页面利用JAVASCRIPT操纵和很多COOKIES信息,而且利用COOKIES信息也进行了一系列的操作,而实际上我们完全可以给屏蔽掉,将关于操纵COOKIE的所有信息都给屏蔽掉,因此就是解析来的步骤第一步,获取验证码,并且显示出来,这里我使用的是我们公司自己的控件,PNHTTP,你们也可以使用相应的组件,譬如说MSXML之类的只要能够实现GET或者POST方式的TRegThread(aThread).Bmp:= Http.HttpBmp('http://captcha.qq.com/getimage?aid=1007901&0.9408595752591837'); //远程获取验证码,并保存到TBITMAP里边第二步,用户输入验证码,及其其他的内容信息以后,还不能直接的提交,腾讯在这里对数据进行了一个加操作,首先像checkconn页面发出一个GET申请,这个操作主要就是获取一串JSON代码,里边包含了需要提交的各变量的名称,也就是FORM里边的INPUT变量的名称,这个变量的名称腾讯做的比较变态,还进行了一些算法,经过分析,我给还原过来如下获取表单变量 1 FormParams:= Http.HttpGet('http://reg.qq.com/cgi-bin/checkconn?seed0.8865932116432269'); ///获取checkconn页面内容2 StrCookie:= Http.CookieMgr.CookieCollection.Cookie['PCCOOKIE','qq.com'].Value; ///获取'PCCOOKIE'这个COOKIE里边保存的COOKIE信息3 StrCookie:= copy(StrCookie,length(StrCookie)-1,2); ///获取COOKIE的倒数两位4 LBase:= HexToInt(StrCookie); ///将COOKIE倒数两位进行十六进制转换5 6 ParamArray[0]:= 'QQ'; ///申请类型17 ParamArray[1]:= 'EMAIL'; ///申请类型28 ParamArray[2]:= 'zeze'; ///QQ昵称9 ParamArray[3]:= '0'; ///QQ性别10 ParamArray[4]:= '1985'; ///出生年11 ParamArray[5]:= '1'; ///出生月12 ParamArray[6]:= '2'; ///出生日13 ParamArray[7]:= '1'; ///忘记了14 ParamArray[8]:= '2'; ///忘记了15 ParamArray[9]:= 'abc111111'; ///密码16 ParamArray[10]:= 'abc111111'; ///重复密码17 ParamArray[11]:= '1'; ///国家代码18 ParamArray[12]:= '11'; ///省份代码19 ParamArray[13]:= '1'; ///区域代码20 ParamArray[14]:= RndStr; ///验证码21 22 try23 SListA:= FPNSplit(Copy(FormParams,33,402),',');24 SListB:= FPNSplit(Copy(FormParams,447,64),',');25 ///上边的是处理CHECKCONN页面的内容,实际上是JSON格式的,可以直接采用JSON解析,但是我这里嫌麻烦,所以自己用的分割函数直接处理26 FormParams:= ''; ///需要提交的变量名27 ///下边的是对CHECKCONN返回内容的解密算法28 for i := 0 to 12 do begin29 IdxA:= StrToInt(SListB[i]) xor LBase;30 IdxB:= 12-i;31 IdxA:= IdxA xor 6818;32 IdxA:= IdxA xor 8315;33 IdxA:= IdxA xor 5123;34 IdxA:= IdxA xor 2252;35 for j := 0 to 5 do36 IdxA:= IdxA xor 0;37 IdxA:= IdxA mod 15;38 39 FormParams:= FormParams+ Copy(SListA[IdxB],2,28)+ '='+ ParamArray[IdxA]+ '&'; ///这里是构造提交数据信息40 end;41 42 finally43 SListA.Free;44 SListB.Free;45 end;46 47 48 上边通过FormParams变量,将所需要提交的信息保存了下来,接下来我们开始像服务器提交提交注册,并检测结果 1 StrResult:= Http.HttpPost('http://reg.qq.com/cgi-bin/getnum',FormParams,True);2 Reg:= TPerlRegEx.Create(nil);3 try4 Reg.Subject:= StrResult;5 Reg.RegEx:= '您获得的号码为:\([\s\S]*?)\<';6 if Reg.MatchAgain then begin7 StrQQ:= Reg.SubExpressions[1];8 FPNWriteLnText('注册成功的QQ.txt',StrQQ,False);9 end else begin10 FPNWriteLnText('注册失败线程.txt',TRegData(aDataObj).FId,False);11 end;12 finally13 Reg.Free;14 end;15 以上的过程就完成了腾讯的注册流程,但是仅仅这样是不够的,因为我们所需要的最终目的是多线程,多线程怎么实现呢?我这里采用DELPHI线程池的方式代码 1 TCoding= record ///这里是记录打码区的状态2 Status: integer; //忙碌1,空闲0,等待用户输入数据2,用户已经输入,等待处理33 ShowBegin: integer; //开始显示验证码的时间4 end;5 6 ///线程池中的线程处理类,可以派生,也可以不用派生7 TRegThread = class(TPNPoolThread)8 private9 MyCodeIdx: integer;10 bmp: TBitmap;11 procedure ShowImg1;12 procedure ShowImg;13 public14 destructor Destroy;15 end;16 17 TRegData= class(TPNTaskObject)18 private19 FId: String; //编号20 public21 constructor Create(const AId: string);22 function Duplicate(DataObj: TPNTaskObject;23 const Processing: Boolean): Boolean; ///判断两个任务是否重复,此函数必须在派生类写明24 function Info: string; override; ///输出信息,覆盖25 end;26 相关打码区函数 1 var2 MainForm: TMainForm;3 Codings: array[1..9] of TCoding;4 CodingCs: TPNCriticalSection; ///申请打码资源的CS5 6 RegId: integer;7 8 StrLog: string; ///日志数据9 PoolReg: TPNThreadPool; ///线程池10 csLog: TPNCriticalSection; ///保存日志的临界区11 12 function CodingApply: integer; //申请打码显示资源,如果申请成功,返回显示的标号,否则返回-113 function CodingRelease(CodeIdx: Integer): string; //释放显示资源,返回的是打码的信息14 function CodingWait(CodeIdx: Integer): Boolean; //将状态更改为等待15 function CodingOK(CodeIdx: Integer): Boolean; //将状态更改为处理完毕16 function CodingStatus(CodeIdx: Integer): integer; //获取当前状态17 具体的线程池设置代码,对于申请打码区资源,及其释放打码区资源,都写得有具体的方案代码 1 2 function CodingApply: integer;3 var4 i: integer;5 begin6 CodingCs.Enter;7 Result:= -1;8 try9 for i := 1 to 9 do begin10 if Codings[i].Status=0 then begin11 Result:= i;12 Codings[i].Status:= 1;13 Break;14 end;15 end;16 finally17 CodingCs.Leave;18 Sleep(0);19 end;20 end;21 22 function CodingRelease(CodeIdx: Integer): string;23 begin24 if (CodeIdx<0) or (CodeIdx>9) then Exit;25 CodingCs.Enter;26 try27 try28 Result:= TEdit(MainForm.FindComponent('Input'+ IntToStr(CodeIdx))).Text;29 except30 Result:= '';31 end;32 Codings[CodeIdx].Status:= 0;33 finally34 CodingCs.Leave;35 Sleep(0);36 end;37 end;38 39 function CodingWait(CodeIdx: Integer): Boolean;40 begin41 if (CodeIdx<0) or (CodeIdx>9) then Exit;42 Result:= True;43 CodingCs.Enter;44 try45 try46 Codings[CodeIdx].Status:= 2;47 except48 Result:= False;49 end;50 finally51 CodingCs.Leave;52 Sleep(0);53 end;54 end;55 56 function CodingOK(CodeIdx: Integer): Boolean;57 begin58 if (CodeIdx<0) or (CodeIdx>9) then Exit;59 Result:= True;60 CodingCs.Enter;61 try62 try63 Codings[CodeIdx].Status:= 3;64 except65 Result:= False;66 end;67 finally68 CodingCs.Leave;69 Sleep(0);70 end;71 end;72 function CodingStatus(CodeIdx: Integer): integer;73 begin74 if (CodeIdx<0) or (CodeIdx>9) then Exit;75 CodingCs.Enter;76 try77 Result:= Codings[CodeIdx].Status;78 finally79 CodingCs.Leave;80 Sleep(0);81 end;82 end;83 84 constructor TRegData.Create(const AId: string);85 begin86 FId:= AId;87 end;88 89 function TRegData.Duplicate(DataObj: TPNTaskObject;90 const Processing: Boolean): Boolean;91 begin92 Result := (not Processing) and93 (FId = TRegData(DataObj).FId);94 end;95 96 function TRegData.Info: string;97 begin98 Result:= 'FId='+ FId+ ';';99 end;100 101 102 procedure TRegThread.ShowImg1;103 begin104 try105 TImage(MainForm.FindComponent('Img'+ IntToStr(MyCodeIdx))).Picture.Assign(bmp);106 TEdit(MainForm.FindComponent('Input'+ IntToStr(MyCodeIdx))).Text:= '';107 except108 end;109 CodingWait(MyCodeIdx);110 end;111 procedure TRegThread.ShowImg;112 begin113 Synchronize(ShowImg1);114 end;115 destructor TRegThread.Destroy;116 begin117 try118 if bmp<>nil then bmp.Free;119 except120 end;121 inherited Destroy;122 end;123 124 function HexToInt(const S: String): DWORD;125 asm126 PUSH EBX127 PUSH ESI128 129 MOV ESI, EAX //字符串地址130 MOV EDX, [EAX-4] //读取字符串长度131 132 XOR EAX, EAX //初始化返回值133 XOR ECX, ECX //临时变量134 135 TEST ESI, ESI //判断是否为空指针136 JZ @@2137 TEST EDX, EDX //判断字符串是否为空138 JLE @@2139 MOV BL, $20140 @@0:141 MOV CL, [ESI]142 INC ESI143 144 OR CL, BL //如果有字母则被转换为小写字母145 SUB CL, '0'146 JB @@2 // < '0' 的字符147 CMP CL, $09148 JBE @@1 // '0'..'9' 的字符149 SUB CL, 'a'-'0'-10150 CMP CL, $0A151 JB @@2 // < 'a' 的字符152 CMP CL, $0F153 JA @@2 // > 'f' 的字符154 @@1: // '0'..'9', 'A'..'F', 'a'..'f'155 SHL EAX, 4156 OR EAX, ECX157 DEC EDX158 JNZ @@0159 JMP @@3160 @@2:161 XOR EAX, EAX // 非法16进制字符串162 @@3:163 POP ESI164 POP EBX165 RET166 end;167 168 procedure TMainForm.DownProcessRequest(Sender: TPNThreadPool;169 aDataObj: TPNTaskObject; aThread: TPNPoolThread);170 var171 Http: TPNHttp;172 i,j,LBase,IdxA,IdxB: integer;173 RndStr,FormParams,StrResult,StrQQ,StrCookie,StrIP: string;174 SListA,SListB: TStringList;175 Reg: TPerlRegEx;176 ParamArray: array[0..14] of string;177 begin178 // FPNWriteLnText('日志.txt',TRegData(aDataObj).FId+'开始注册',False);179 Http:= TPNHttp.Create(nil,True,True);180 Randomize;181 StrIP:= '1.193.86.'+ IntToStr(Random(255)+ 1);182 // StrIP:= IntToStr(Random(255)+ 1)+'.'+ IntToStr(Random(255)+ 1)+'.'+ IntToStr(Random(255)+ 1)+'.'+ IntToStr(Random(255)+ 1);183 Http.Request.CustomHeaders.Add('X-Forwarded-For:'+ StrIP);184 try185 try186 Http.HttpGet('http://reg.qq.com/');187 // FPNWriteLnText(TRegData(aDataObj).FId+'HEADER信息.txt','首页:'+ Http.HttpHeader,False);188 TRegThread(aThread).MyCodeIdx:= CodingApply;189 ///等待获取打码资源190 while TRegThread(aThread).MyCodeIdx=-1 do begin191 sleep(500);192 TRegThread(aThread).MyCodeIdx:= CodingApply;193 end;194 try195 TRegThread(aThread).Bmp:= Http.HttpBmp('http://captcha.qq.com/getimage?aid=1007901&0.9408595752591837');196 // FPNWriteLnText(TRegData(aDataObj).FId+'HEADER信息.txt','验证码:'+ Http.HttpHeader,False);197 TRegThread(aThread).ShowImg;198 finally199 if TRegThread(aThread).Bmp<>nil then200 TRegThread(aThread).Bmp.Free;201 end;202 while CodingStatus(TRegThread(aThread).MyCodeIdx)=2 do begin203 Sleep(200);204 end;205 RndStr:= CodingRelease(TRegThread(aThread).MyCodeIdx);206 // FPNWriteLnText('日志.txt',TRegData(aDataObj).FId+':RndStr='+ RndStr,False);207 FormParams:= Http.HttpGet('http://reg.qq.com/cgi-bin/checkconn?seed0.8865932116432269');208 // FPNWriteLnText(TRegData(aDataObj).FId+'HEADER信息.txt','CheckConn:'+ Http.HttpHeader,False);209 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt','返回的参数集:'+ FormParams,False);210 // FormParams:= Copy(FormParams,33,402);211 StrCookie:= Http.CookieMgr.CookieCollection.Cookie['PCCOOKIE','qq.com'].Value;212 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt','PCCOOKIE值为:'+ StrCookie,False);213 StrCookie:= copy(StrCookie,length(StrCookie)-1,2);214 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt','LBASE值为:'+ StrCookie,False);215 LBase:= HexToInt(StrCookie);216 217 ParamArray[0]:= 'QQ';218 ParamArray[1]:= 'EMAIL';219 ParamArray[2]:= 'zeze';220 ParamArray[3]:= '0';221 ParamArray[4]:= '1985';222 ParamArray[5]:= '1';223 ParamArray[6]:= '2';224 ParamArray[7]:= '1';225 ParamArray[8]:= '2';226 ParamArray[9]:= 'abc111111';227 ParamArray[10]:= 'abc111111';228 ParamArray[11]:= '1';229 ParamArray[12]:= '11';230 ParamArray[13]:= '1';231 ParamArray[14]:= RndStr;232 try233 SListA:= FPNSplit(Copy(FormParams,33,402),',');234 SListB:= FPNSplit(Copy(FormParams,447,64),',');235 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt',Copy(FormParams,447,64),False);236 FormParams:= '';237 for i := 0 to 12 do begin238 IdxA:= StrToInt(SListB[i]) xor LBase;239 IdxB:= 12-i;240 IdxA:= IdxA xor 6818;241 IdxA:= IdxA xor 8315;242 IdxA:= IdxA xor 5123;243 IdxA:= IdxA xor 2252;244 for j := 0 to 5 do245 IdxA:= IdxA xor 0;246 IdxA:= IdxA mod 15;247 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt','IdxA:'+ IntToStr(IdxA),False);248 249 FormParams:= FormParams+ Copy(SListA[IdxB],2,28)+ '='+ ParamArray[IdxA]+ '&'250 end;251 252 // FormParams:= Copy(SList[0],2,28)+ '=1&'+ Copy(SList[1],2,28)+ '=1&'+ Copy(SList[2],2,28)+ '=pop67579818&'253 // + Copy(SList[3],2,28)+ '=1983&'+ Copy(SList[4],2,28)+ '='+ RndStr+'&' + Copy(SList[5],2,28)+ '=1&'254 // + Copy(SList[6],2,28)+ '=lovezeze&'+ Copy(SList[7],2,28)+ '=pop67579818&'+ Copy(SList[8],2,28)+ '=0&'255 // + Copy(SList[9],2,28)+ '=1&'+ Copy(SList[10],2,28)+ '=2&'+ Copy(SList[11],2,28)+ '=11&'256 // + Copy(SList[12],2,28)+ '=1';257 finally258 SListA.Free;259 SListB.Free;260 end;261 for i := 0 to Http.CookieMgr.CookieCollection.Count - 1 do262 StrCookie:= StrCookie+ Http.CookieMgr.CookieCollection.Items[i].CookieName+ ':'263 + Http.CookieMgr.CookieCollection.Items[i].CookieText;264 StrResult:= Http.HttpPost('http://reg.qq.com/cgi-bin/getnum',FormParams,True);265 // FPNWriteLnText(TRegData(aDataObj).FId+'HEADER信息.txt','POST时候:'+ Http.HttpHeader,False);266 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt','提交COOKIE为:'+ StrCookie,False);267 // FPNWriteLnText(TRegData(aDataObj).FId+'数据日志.txt','提交参数为:'+ FormParams,False);268 // FPNWriteLnText(TRegData(aDataObj).FId+'返回数据.txt',StrResult,False);269 Reg:= TPerlRegEx.Create(nil);270 try271 Reg.Subject:= StrResult;272 Reg.RegEx:= '您获得的号码为:\([\s\S]*?)\<';273 if Reg.MatchAgain then begin274 StrQQ:= Reg.SubExpressions[1];275 FPNWriteLnText('注册成功的QQ.txt',StrQQ,False);276 end else begin277 FPNWriteLnText('注册失败线程.txt',TRegData(aDataObj).FId,False);278 end;279 // FPNWriteLnText(TRegData(aDataObj).FId+'匹配结果.txt',StrResult,False);280 finally281 Reg.Free;282 end;283 except284 285 end;286 finally287 Http.Free;288 end;289 end;290 291 procedure TMainForm.btn1Click(Sender: TObject);292 var293 i: integer;294 begin295 for i := 1 to StrToInt(RegNum.Text) do begin296 RegId:= RegId+ 1;297 PoolReg.AddRequest(TRegData.Create(IntToStr(RegId)));298 end;299 end;300 301 procedure TMainForm.FormCreate(Sender: TObject);302 begin303 RegId:= 0;304 CodingCs:= TPNCriticalSection.Create;305 PoolReg := TPNThreadPool.Create(nil);306 with PoolReg do begin307 OnProcessRequest := DownProcessRequest; ///线程处理函数308 AdjustInterval := 5 * 1000; ///减少线程间隔时间,5秒309 MinAtLeast := False; ///是否设置最小线程数310 ThreadDeadTimeout := 10 * 1000; ///线程死亡超时时间311 ThreadsMinCount := 10; ///最小线程数312 ThreadsMaxCount := 50; ///最大线程数313 uTerminateWaitTime := 2 * 1000; ///挂起等待时间314 end;315 316 end;317 318 procedure TMainForm.FormDestroy(Sender: TObject);319 begin320 PoolReg.Free;321 CodingCs.Free;322 end;323 324 procedure TMainForm.Input1KeyPress(Sender: TObject; var Key: Char);325 var326 CodeIdx: integer;327 ObjName: string;328 begin329 if Key= Char(13) then begin330 ObjName:= (Sender as TRzEdit).Name;331 CodeIdx:= StrToInt(Copy(ObjName,6,1));332 CodingOK(CodeIdx);333 if CodeIdx=9 then334 CodeIdx:= 1335 else336 CodeIdx:= CodeIdx+ 1;337 TRzEdit(FindComponent('Input'+ IntToStr(CodeIdx))).SetFocus;338 end;339 end;340 本文只是对QQ注册页面进行一些分析,供大家参考,其实大家在做WEB设计的时候,如何防止批量注册这块,也可以参考下QQ,比较变态一些,但是感觉腾讯做的还不完善。

声明:希维路由器教程网提供的内容,仅供网友学习交流,如有侵权请与我们联系删除,谢谢。ihuangque@qq.com
本文地址:https://www.ctrlcv.com.cn/diannao/169323125010628.html