巧妙编程实现QQ安全登录 |
花的神明 |
《软件报》2008年第11期 邮发代号:61-74 QQ是我们很常用的聊天软件,当登录QQ时,一般都是在其登录窗口中输入QQ号码和密码,之后才可以进入聊天窗口。但是,现在很多木马程序往往通过各种手段来截取您的QQ密码,例如设置键盘钩子,伪造QQ登录界面等。虽然QQ提供了nProtect键盘加密保护技术,不过最新的QQ木马完全可以直接破解该保护技术,在QQ用户毫无察觉的情况下直接截取QQ密码信息。如何才能打破常规,实现QQ安全快速登录呢? 实际上,除了使用正常的QQ登录对话框实现登录操作外,还可以使用QQ命令行实现登录操作。QQ命令行的格式为“QQ.exe /START QQUIN:QQ号码 PWDHASH:加密后的QQ密码 /STAT:登录状态”,其中的“QQ.exe”表示QQ的完整程序路径,例如“C:\Program Files\Tencent\QQ.exe”,“QQUIN”参数后面跟随QQ号码,“PWDHASH”参数后面跟随加密后的QQ密码。在执行登录操作时,QQ根据取得您输入的QQ密码后,使用MD5散列算法对其进行加密处理,得到16个字节的MD5散列值,然后使用BASE64编码对该散列值进行后编码处理,之后得到的值才可以用于登录操作。“STAT”参数后跟登录状态值,其中“40”表示隐身登录,“41”表示正常登录。QQ主程序利用取得的QQ号码,加密后的密码以及登录状态参数。因此,只要取得了您的QQ密码的编码信息,就可以在CMD窗口中使用命令行安全登录QQ了。因为没有使用QQ的登录对话框,再狡猾的病毒也无法探知您的QQ密码信息。根据以上原理,这里就使用Delphi 设计一个实用的QQ命令行生成程序。 在Delphi 中创建一个新的项目,在表单中放置一个名称为“num”的编辑框,用于输入QQ号码,放置一个名称为“pass”的编辑框,用于输入QQ密码,放置一个标题为“隐身登录”的CheckBox控件,用于判断是否使用隐身登录,放置一个名称为“edit1”的编辑框,用于显示完整的QQ登录命令语句,放置一个名称为“button1”的按钮,用于产生QQ命令行。注意在程序开头的“Uses”栏中应该包含“IdHashMessageDigest”单元,它实际上包含在Delphi 7内置的Indy控件包中,这里要使用其中包含的HashValue函数计算QQ密码的16字节的MD5 散列值,然后再用BASE64编码对该散列值进行编码得到的所需的密码数据。该函数完整的格式为“function HashValue(AStream: TStream): T4x4LongWordRecord; override;”,其中的参数类型是一个流或者字符串对象,经过计算可以返回T4x4LongWordRecord类型的值。在窗体的创建事件中,取得QQ的安装路径。,相关的程序片段为: … with reg do //reg为Tregistry对象 begin rootkey:=HKEY_LOCAL_MACHINE; if openkey(’SOFTWARE\TENCENT\PLATFORM_TYPE_LIST\1’,true) then //使用openkey函数打开QQ在注册表中的相关主键 begin qqpath:= ReadString(’TypePath’);//使用readstring函数读取QQ安装路径 end; CloseKey; Destroy; end; end; … 程序中主要的部分是计算QQ密码的加密后的散列值,其具体程序为: … function GetCommandLine(QQNum, QQPw: string; QQState: integer): string; type TempChar = array[0..15] of char;//定义16个字节的数组,用于保存MD5散列值 var md5: TIdHashMessageDigest5;//定义一个Hash散列对象,其中的TIdHashMessageDigest5 类是在 IdHashMessageDigest 单元中声明的 begin md5 := TIdHashMessageDigest5.Create;//创建一个Hash散列对象 result := ’ /START QQUIN:’ + QQNum + ’ PWDHASH:’ + Base64(TempChar(md5.HashValue(QQPw))) + ’ /STAT:’ + IntToStr(QQState); //使用MD5加密算法计算QQ密码的散列值,之后使用自定义的Base64()函数对其进行编码,之后将使用预设格式组合QQ号码,加密后的密码以及隐身登录标记,之后将将HashValue函数的值转换成字符集 md5.Free; //释放MD5散列对象 end; … 当点击“button1”按钮时,产生完整的QQ登录命令行,如果勾选“隐身登录”项,表示使用隐身登录模式,否则的话,表示使用正常登录模式。在“edit1”中即可显示不同模式下的完整命令行。例如“"C:\PROGRA~1\Tencent\QQ\QQ.exe" /START QQUIN:2899802 PWDHASH:SAPAtFJ97zat6d6vB9Sw/A== /STAT:41”,可以看到QQ密码已经被加密处理过了,这里使用的是正常的登录模式。当然,这里的QQ号码和加密登录密码是假设的。此外,当点击了“button1”按钮后,同时还会在该程序的运行路径中创建一个名为“secureQQ.bat”的批处理文件,其中包含完整的QQ登录命令行,之后双击该批处理文件,即可快速登录到QQ上了。别人即使得到该文件,也无法得到真实的QQ密码。只要您的QQ密码设置的复杂,利用MD5算法加密过的密码几乎无法破解的。相关的命令行为: … procedure TForm1.Button1Click(Sender: TObject); var F: TextFile; fn: string; begin if num.Text=’’ then begin Messagebox(handle,’请输入您的QQ号码!’,’提示’,mb_OK); exit; end; if pass.Text=’’ then begin Messagebox(handle,’请输入您的QQ密码!’,’提示’,mb_OK); exit; end; if checkbox1.Checked then begin edit1.Enabled:=true; edit1.Text:=qqpath+’ ’+GetCommandLine(num.Text ,pass.Text ,40);//将QQ主文件路径和参数信息组合在一起,使用GetCommandLine函数计算QQ密码的散列值,如果Checkbox1处于选择状态,表示使用隐身登录 end else //否则表示正常登录 begin edit1.Enabled:=true; edit1.Text:=’"’+qqpath+’"’+’ ’+GetCommandLine(num.Text ,pass.Text ,41); end; fn:=ExtractFilePath(paramstr(0))+’\’+’secureQQ.bat’;//创建批处理文件,将完整的QQ命令行写入该文件中 if fileexists(fn) then DeleteFile(fn); AssignFile(F, fn); Rewrite(F); writeln(F, ’@Echo off’); writeln(F, edit1.text); CloseFile(F); end; 完整的源代码为:(该程序在Delphi7中调试通过) unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,IdHashMessageDigest, StdCtrls,Registry, ExtCtrls; type TForm1 = class(TForm) num: TEdit; Label2: TLabel; Label3: TLabel; Button1: TButton; pass: TEdit; Edit1: TEdit; Label1: TLabel; CheckBox1: TCheckBox; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure numKeyPress(Sender: TObject; var Key: Char); procedure passKeyPress(Sender: TObject; var Key: Char); private { Private declarations } public { Public declarations } end; const fSeedA = 831022 ; fSeedB = 8310 ; fKey=1983 ; var Form1: TForm1; qqpath:string; implementation {$R *.dfm} function Base64(Src: string): string;//Base64编码生成函数 const DataSet = ’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/’; var i, ModLen: integer; Current: string; Buf: array[1..3] of Byte; NewBuf: array[1..4] of Byte; begin result := ’’; if Src = ’’ then exit; ModLen := Length(Src) mod 3; while Length(Src) > 0 do begin FillChar(Buf, 3, #0); Current := Copy(Src, 1, 3); Src := Copy(Src, 4, Length(Src) - 3); for i := 1 to 3 do Buf[i] := Ord(Current[i]); NewBuf[1] := Buf[1] shr 2; NewBuf[2] := (Buf[1] shl 6 shr 2 or Buf[2] shr 4) and $3F; NewBuf[3] := (Buf[2] shl 4 shr 2 or Buf[3] shr 6) and $3F; NewBuf[4] := Buf[3] and $3F; for i := 1 to 4 do result := result + DataSet[NewBuf[i] + 1]; end; if ModLen >= 1 then result[Length(result)] := ’=’; if ModLen = 1 then result[Length(result) - 1] := ’=’; end; function GetCommandLine(QQNum, QQPw: string; QQState: integer): string; type TempChar = array[0..15] of char; var md5: TIdHashMessageDigest5; begin md5 := TIdHashMessageDigest5.Create; result := ’ /START QQUIN:’ + QQNum + ’ PWDHASH:’ + Base64(TempChar(md5.HashValue(QQPw))) + ’ /STAT:’ + IntToStr(QQState); md5.Free; end; procedure TForm1.Button1Click(Sender: TObject); var F: TextFile; fn: string; begin if num.Text=’’ then begin Messagebox(handle,’请输入您的QQ号码!’,’提示’,mb_OK);//如果QQ号码为空,弹出提示信息 exit; end; if pass.Text=’’ then begin Messagebox(handle,’请输入您的QQ密码!’,’提示’,mb_OK); //如果QQ密码为空,弹出提示信息 exit; end; if checkbox1.Checked then begin edit1.Enabled:=true; edit1.Text:=qqpath+’ ’+GetCommandLine(num.Text ,pass.Text ,40); end else begin edit1.Enabled:=true; edit1.Text:=’"’+qqpath+’"’+’ ’+GetCommandLine(num.Text ,pass.Text ,41); end; fn:=ExtractFilePath(paramstr(0))+’\’+’secureQQ.bat’; if fileexists(fn) then DeleteFile(fn); AssignFile(F, fn); Rewrite(F); writeln(F, ’@Echo off’); writeln(F, edit1.text); CloseFile(F); end; procedure TForm1.FormCreate(Sender: TObject); var reg:TRegistry; begin reg:=TRegistry.Create; with reg do begin rootkey:=HKEY_LOCAL_MACHINE; if openkey(’SOFTWARE\TENCENT\PLATFORM_TYPE_LIST\1’,true) then begin qqpath:= ReadString(’TypePath’); end; CloseKey; Destroy; end; end; procedure TForm1.numKeyPress(Sender: TObject; var Key: Char); begin if not (Key in [’0’..’9’,#8,#13]) then Key:=#0;// 判断QQ号码是否为数字 if key=#13 then pass.SetFocus;// 当点击回车键时,转移输入焦点 end; procedure TForm1.passKeyPress(Sender: TObject; var Key: Char); begin if key=#13 then Button1.Click(); end; end. |
转载自: http://
联系客服