• 命令行方式实现QQ自动登录


          上一次写过一篇VB制作QQ自动登录器的日志,介绍用得是模拟键盘输入的方式实现QQ的自动登录。这种方式有一种缺陷,就是必须保持输入焦点的正确,否则很容易就打乱了程序的执行过程,造成无法登录。特别是一开机就运行该程序,然后该程序去调用QQ的时候,Win API Winexec执行特慢,导致程序跟不上QQ,输入焦点也错了。后来在网上又发现了一种用QQ命令行的方式来实现自动登录的,这种方式明显更好用。该命令行的格式为“QQ应用程序路径 /START QQUIN:QQ号码 PWDHASH:Base64(MD5(QQ密码)) /STAT:登录模式”。
          QQ应用程序的路径我们可以在注册表下面找到,而需要注意的是QQ密码必须是经过MD5加密过的,再用Base64编码一次。登录模式则有40和41两种,40表示隐身登录,41表示正常登录。了解了命令行的格式后我们就直接调用Win API Winexec就可以实现QQ的自动登录了。下面给出实现代码:

    m_QQ_AutoLogin模块:

    Option Explicit
    Public Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey As LongByVal lpSubKey As StringByVal ulOptions As LongByVal samDesired As Long, phkResult As LongAs Long
    Public Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey As LongByVal lpValueName As StringByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As LongAs Long         ' Note that if you declare the lpData parameter as String, you must pass it By Value.
    Public Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As LongAs Long
    Public Declare Function PathFileExists Lib "shlwapi.dll" Alias "PathFileExistsA" (ByVal szPath As StringAs Long
    Private Declare Function WinExec Lib "kernel32" (ByVal lpCmdLine As StringByVal nCmdShow As LongAs Long

    Public Const HKEY_LOCAL_MACHINE = &H80000002
    Public Const KEY_ALL_ACCESS = &H3F
    Public Const ERROR_SUCCESS = 0&

    Public conn As ADODB.Connection   'conn为连接
    Public rs As ADODB.Recordset    'rs为记录集

    '连接数据库
    Function QQ_DB_Connect() As Boolean
        
    Dim strQQDBPath As String
        
        QQ_DB_Connect 
    = False
        
        
    If Right(App.Path, 1= "" Then  '获取数据库的路径
            strQQDBPath = App.Path & "QQData.mdb"
        
    Else
            strQQDBPath 
    = App.Path & "QQData.mdb"
        
    End If
        
        
    If PathFileExists(strQQDBPath) = 0 Then
            
    MsgBox "在当前应用程序目录下找不到数据库文件!", vbInformation Or vbOKOnly, "QQ自动登录器"
            
    Exit Function
        
    End If
        
        
    'MsgBox QQDBPath
        Set conn = New ADODB.Connection
        
    If conn.State = adStateOpen And Not IsEmpty(adStateOpen) Then conn.Close
        conn.ConnectionString 
    = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strQQDBPath & ";Jet OLEDB:Database Password=QQDATA"
        conn.CursorLocation 
    = adUseClient
        conn.Open
        QQ_DB_Connect 
    = True
    End Function

    '断开与数据库的连接
    Function QQ_DB_Deconnetion()
        
    If conn.State = adStateOpen Then conn.Close
        
    Set conn = Nothing
    End Function

    '添加QQ号码信息函数
    Function QQ_DB_Add(strNum As String, strPwd As StringAs Boolean
        
    Dim strSql As String
        
        
    If QQ_DB_Find(strNum) Then
            QQ_DB_Add 
    = False
        
    Else
            strSql 
    = "insert into QQDataTable(QQ_NUM,QQ_PWD) values('" & strNum & "','" & strPwd & "')"
            conn.Execute strSql
            QQ_DB_Add 
    = True
        
    End If
    End Function

    '修改QQ号码信息函数
    Function QQ_DB_Edit(strNum As String, strPwd As StringAs Boolean
        
    Dim nID As Long, strSql As String
        
        nID 
    = QQ_DB_Find(strNum)
        
    If nID Then
            strSql 
    = "Update QQDataTable set QQ_NUM='" & strNum & "',QQ_PWD='" & strPwd & "' where ID=" & nID
            conn.Execute strSql
            QQ_DB_Edit 
    = True
        
    Else
            QQ_DB_Edit 
    = False
        
    End If
    End Function

    '获取指定的QQ号码记录的ID
    Function QQ_DB_Find(strNum As StringAs Long
        
    Dim strSql As String
        
        strSql 
    = "select * from QQDataTable where QQ_NUM='" & strNum & "'"
        
    Set rs = New ADODB.Recordset
        rs.Open strSql, conn
        
    If rs.RecordCount > 0 Then
            QQ_DB_Find 
    = rs.Fields("ID")
        
    Else
            QQ_DB_Find 
    = 0
        
    End If
        rs.Close
        
    Set rs = Nothing
    End Function

    '获取指定ID记录的信息
    Function QQ_DB_Get(nID As Long, strNum As String, strPwd As StringAs Boolean
        
    Dim strSql As String
        
        strSql 
    = "select * from QQDataTable where ID=" & nID
        
    Set rs = New ADODB.Recordset
        rs.Open strSql, conn
        
    If rs.RecordCount > 0 Then
            strNum 
    = rs.Fields("QQ_NUM")
            strPwd 
    = rs.Fields("QQ_PWD")
            QQ_DB_Get 
    = True
        
    Else
            QQ_DB_Get 
    = False
        
    End If
        rs.Close
        
    Set rs = Nothing
    End Function

    '更新QQ号码列表函数
    Function QQ_DB_UpdataUserList(lvListView As ListView)
        
    Dim strSql As String
        
    Dim strNum As String
        
        lvListView.ListItems.Clear
        strSql 
    = "select * from QQDataTable"
        
    Set rs = New ADODB.Recordset
        rs.Open strSql, conn
        
    Do While Not rs.EOF
            strNum 
    = rs.Fields("QQ_NUM")
            
    Call lvListView.ListItems.Add(, , strNum, 01)
            rs.MoveNext
        
    Loop
        rs.Close
        
    Set rs = Nothing
    End Function

    '删除QQ信息函数
    Function QQ_DB_Del(strNum As StringAs Boolean
        
    Dim strSql As String
        
        
    If QQ_DB_Find(strNum) Then
            strSql 
    = "delete * from QQDataTable where QQ_NUM = '" & strNum & "'"
            conn.Execute strSql
            QQ_DB_Del 
    = True
        
    Else
            QQ_DB_Del 
    = False
        
    End If
    End Function

    '获取QQ应用程序安装路径
    Function QQ_DB_GetQQAppPath() As String
        
    Dim hKey As Long, strQQAppPath As String, lngQQAppPathLen As Long
        
        QQ_DB_GetQQAppPath 
    = ""  '初始化函数返回值
        
        
    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARETencentQQ"0, KEY_ALL_ACCESS, hKey) <> ERROR_SUCCESS Then  '到注册表去获取QQ安装目录
            Exit Function  '失败返回
        End If
        
        strQQAppPath 
    = String(2560)
        lngQQAppPathLen 
    = Len(strQQAppPath)
        
    If RegQueryValueEx(hKey, "Install"00ByVal strQQAppPath, lngQQAppPathLen) <> ERROR_SUCCESS Then
            
    Call RegCloseKey(hKey)
            
    Exit Function  '失败返回
        End If

        
    Call RegCloseKey(hKey)
        
        strQQAppPath 
    = Left(strQQAppPath, InStr(strQQAppPath, Chr(0)) - 1)
        
    If Right(strQQAppPath, 1= "" Then
            strQQAppPath 
    = strQQAppPath & "QQ.exe"
        
    Else
            strQQAppPath 
    = strQQAppPath & "QQ.exe"
        
    End If
        QQ_DB_GetQQAppPath 
    = strQQAppPath
    End Function

    'QQ命令行密码加密函数
    Function QQ_DB_Pwdhash(strPwd As StringAs String
        
    Dim bytMD5Bytes() As Byte, bytBase64Bytes() As Byte
        
        bytMD5Bytes() 
    = MyMD5(strPwd)
        bytBase64Bytes() 
    = Base64_Encode(bytMD5Bytes())
        QQ_DB_Pwdhash 
    = StrConv(bytBase64Bytes(), vbUnicode)
    End Function

    'QQ命令行自动登录函数
    Function QQ_AutoLogin(strNum As String, intLoginMode As IntegerAs Boolean
        
    Dim strPwd As String, lngID As Long
        
    Dim strQQAppPath As String, strQQAppCmd As String
        
        lngID 
    = QQ_DB_Find(strNum)
        
    If lngID Then
            
    If QQ_DB_Get(lngID, strNum, strPwd) Then
                strPwd 
    = QQ_DB_Pwdhash(strPwd)  '经命令行密码加密函数加密
                strQQAppPath = QQ_DB_GetQQAppPath()      '获取QQ应用程序安装路径
                strQQAppCmd = strQQAppPath & " /START QQUIN:" & strNum & " PWDHASH:" & strPwd & " /STAT:" & intLoginMode  '40隐身登录,41正常登录
                Call WinExec(strQQAppCmd, 1)  '运行QQ应用程序
            End If
        
    Else
            
    MsgBox "该QQ号码未设置密码信息,请先设置!", vbInformation + vbOKOnly, "QQ自动登录器"
        
    End If
    End Function
    m_QQ_MD5模块:
    Option Explicit

    Private m_lOnBits(30)
    Private m_l2Power(30)
    Private Const BITS_TO_A_BYTE = 8
    Private Const BYTES_TO_A_WORD = 4
    Private Const BITS_TO_A_WORD = 32

    'MD5加密函数,返回MD5加密串(返回Byte数组,16字节)
    Public Function MyMD5(strMessage As StringAs Byte()
        
    Dim strMD5Hash As String, i As Long
        
    Dim btyMD5Bytes(0 To 15As Byte
        
        strMD5Hash 
    = MD5(strMessage, 32)
        
    For i = 0 To 31 Step 2
            btyMD5Bytes(i 
    / 2= HexToDec(Mid(strMD5Hash, i + 12))
        
    Next
        
        
    'Open "C:MD5.txt" For Binary As #1
        'Put #1, , btyMD5Bytes()
        'Close #1
        
        MyMD5 
    = btyMD5Bytes()
    End Function

    '16进制字符串转换10进制数字函数
    Public Function HexToDec(ByVal strHex As StringAs Long
        HexToDec 
    = "&h" & strHex
    End Function

    '下面是别人写的函数
    Private Function md5_F(X, Y, z)
    md5_F 
    = (X And Y) Or ((Not X) And z)
    End Function

    Private Function md5_G(X, Y, z)
    md5_G 
    = (X And z) Or (Y And (Not z))
    End Function

    Private Function md5_H(X, Y, z)
    md5_H 
    = (X Xor Y Xor z)
    End Function

    Private Function md5_I(X, Y, z)
    md5_I 
    = (Y Xor (X Or (Not z)))
    End Function

    Private Sub md5_FF(a, b, c, d, X, s, ac)
    = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_F(b, c, d), X), ac))
    = RotateLeft(a, s)
    = AddUnsigned(a, b)
    End Sub

    Private Sub md5_GG(a, b, c, d, X, s, ac)
    = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_G(b, c, d), X), ac))
    = RotateLeft(a, s)
    = AddUnsigned(a, b)
    End Sub

    Private Sub md5_HH(a, b, c, d, X, s, ac)
    = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_H(b, c, d), X), ac))
    = RotateLeft(a, s)
    = AddUnsigned(a, b)
    End Sub

    Private Sub md5_II(a, b, c, d, X, s, ac)
    = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_I(b, c, d), X), ac))
    = RotateLeft(a, s)
    = AddUnsigned(a, b)
    End Sub

    Private Function ConvertToWordArray(sMessage)
    Dim lMessageLength
    Dim lNumberOfWords
    Dim lWordArray()
    Dim lBytePosition
    Dim lByteCount
    Dim lWordCount

    Const MODULUS_BITS = 512
    Const CONGRUENT_BITS = 448

    lMessageLength 
    = Len(sMessage)

    lNumberOfWords 
    = (((lMessageLength + ((MODULUS_BITS - CONGRUENT_BITS)  BITS_TO_A_BYTE))  (MODULUS_BITS  BITS_TO_A_BYTE)) + 1* (MODULUS_BITS  BITS_TO_A_WORD)
    ReDim lWordArray(lNumberOfWords - 1)

    lBytePosition 
    = 0
    lByteCount 
    = 0
    Do Until lByteCount >= lMessageLength
    lWordCount 
    = lByteCount  BYTES_TO_A_WORD
    lBytePosition 
    = (lByteCount Mod BYTES_TO_A_WORD) * BITS_TO_A_BYTE
    lWordArray(lWordCount) 
    = lWordArray(lWordCount) Or LShift(Asc(Mid(sMessage, lByteCount + 11)), lBytePosition)
    lByteCount 
    = lByteCount + 1
    Loop

    lWordCount 
    = lByteCount  BYTES_TO_A_WORD
    lBytePosition 
    = (lByteCount Mod BYTES_TO_A_WORD) * BITS_TO_A_BYTE

    lWordArray(lWordCount) 
    = lWordArray(lWordCount) Or LShift(&H80, lBytePosition)

    lWordArray(lNumberOfWords 
    - 2= LShift(lMessageLength, 3)
    lWordArray(lNumberOfWords 
    - 1= RShift(lMessageLength, 29)

    ConvertToWordArray 
    = lWordArray
    End Function

    Private Function WordToHex(lValue)
    Dim lByte
    Dim lCount

    For lCount = 0 To 3
    lByte 
    = RShift(lValue, lCount * BITS_TO_A_BYTE) And m_lOnBits(BITS_TO_A_BYTE - 1)
    WordToHex 
    = WordToHex & Right("0" & Hex(lByte), 2)
    Next
    End Function

    Public Function MD5(sMessage, stype)
    m_lOnBits(
    0= CLng(1)
    m_lOnBits(
    1= CLng(3)
    m_lOnBits(
    2= CLng(7)
    m_lOnBits(
    3= CLng(15)
    m_lOnBits(
    4= CLng(31)
    m_lOnBits(
    5= CLng(63)
    m_lOnBits(
    6= CLng(127)
    m_lOnBits(
    7= CLng(255)
    m_lOnBits(
    8= CLng(511)
    m_lOnBits(
    9= CLng(1023)
    m_lOnBits(
    10= CLng(2047)
    m_lOnBits(
    11= CLng(4095)
    m_lOnBits(
    12= CLng(8191)
    m_lOnBits(
    13= CLng(16383)
    m_lOnBits(
    14= CLng(32767)
    m_lOnBits(
    15= CLng(65535)
    m_lOnBits(
    16= CLng(131071)
    m_lOnBits(
    17= CLng(262143)
    m_lOnBits(
    18= CLng(524287)
    m_lOnBits(
    19= CLng(1048575)
    m_lOnBits(
    20= CLng(2097151)
    m_lOnBits(
    21= CLng(4194303)
    m_lOnBits(
    22= CLng(8388607)
    m_lOnBits(
    23= CLng(16777215)
    m_lOnBits(
    24= CLng(33554431)
    m_lOnBits(
    25= CLng(67108863)
    m_lOnBits(
    26= CLng(134217727)
    m_lOnBits(
    27= CLng(268435455)
    m_lOnBits(
    28= CLng(536870911)
    m_lOnBits(
    29= CLng(1073741823)
    m_lOnBits(
    30= CLng(2147483647)

    m_l2Power(
    0= CLng(1)
    m_l2Power(
    1= CLng(2)
    m_l2Power(
    2= CLng(4)
    m_l2Power(
    3= CLng(8)
    m_l2Power(
    4= CLng(16)
    m_l2Power(
    5= CLng(32)
    m_l2Power(
    6= CLng(64)
    m_l2Power(
    7= CLng(128)
    m_l2Power(
    8= CLng(256)
    m_l2Power(
    9= CLng(512)
    m_l2Power(
    10= CLng(1024)
    m_l2Power(
    11= CLng(2048)
    m_l2Power(
    12= CLng(4096)
    m_l2Power(
    13= CLng(8192)
    m_l2Power(
    14= CLng(16384)
    m_l2Power(
    15= CLng(32768)
    m_l2Power(
    16= CLng(65536)
    m_l2Power(
    17= CLng(131072)
    m_l2Power(
    18= CLng(262144)
    m_l2Power(
    19= CLng(524288)
    m_l2Power(
    20= CLng(1048576)
    m_l2Power(
    21= CLng(2097152)
    m_l2Power(
    22= CLng(4194304)
    m_l2Power(
    23= CLng(8388608)
    m_l2Power(
    24= CLng(16777216)
    m_l2Power(
    25= CLng(33554432)
    m_l2Power(
    26= CLng(67108864)
    m_l2Power(
    27= CLng(134217728)
    m_l2Power(
    28= CLng(268435456)
    m_l2Power(
    29= CLng(536870912)
    m_l2Power(
    30= CLng(1073741824)

    Dim X
    Dim k
    Dim AA
    Dim BB
    Dim CC
    Dim DD
    Dim a
    Dim b
    Dim c
    Dim d

    Const S11 = 7
    Const S12 = 12
    Const S13 = 17
    Const S14 = 22
    Const S21 = 5
    Const S22 = 9
    Const S23 = 14
    Const S24 = 20
    Const S31 = 4
    Const S32 = 11
    Const S33 = 16
    Const S34 = 23
    Const S41 = 6
    Const S42 = 10
    Const S43 = 15
    Const S44 = 21

    = ConvertToWordArray(sMessage)

    = &H67452301
    = &HEFCDAB89
    = &H98BADCFE
    = &H10325476

    For k = 0 To UBound(X) Step 16
    AA 
    = a
    BB 
    = b
    CC 
    = c
    DD 
    = d

    md5_FF a, b, c, d, X(k 
    + 0), S11, &HD76AA478
    md5_FF d, a, b, c, X(k 
    + 1), S12, &HE8C7B756
    md5_FF c, d, a, b, X(k 
    + 2), S13, &H242070DB
    md5_FF b, c, d, a, X(k 
    + 3), S14, &HC1BDCEEE
    md5_FF a, b, c, d, X(k 
    + 4), S11, &HF57C0FAF
    md5_FF d, a, b, c, X(k 
    + 5), S12, &H4787C62A
    md5_FF c, d, a, b, X(k 
    + 6), S13, &HA8304613
    md5_FF b, c, d, a, X(k 
    + 7), S14, &HFD469501
    md5_FF a, b, c, d, X(k 
    + 8), S11, &H698098D8
    md5_FF d, a, b, c, X(k 
    + 9), S12, &H8B44F7AF
    md5_FF c, d, a, b, X(k 
    + 10), S13, &HFFFF5BB1
    md5_FF b, c, d, a, X(k 
    + 11), S14, &H895CD7BE
    md5_FF a, b, c, d, X(k 
    + 12), S11, &H6B901122
    md5_FF d, a, b, c, X(k 
    + 13), S12, &HFD987193
    md5_FF c, d, a, b, X(k 
    + 14), S13, &HA679438E
    md5_FF b, c, d, a, X(k 
    + 15), S14, &H49B40821

    md5_GG a, b, c, d, X(k 
    + 1), S21, &HF61E2562
    md5_GG d, a, b, c, X(k 
    + 6), S22, &HC040B340
    md5_GG c, d, a, b, X(k 
    + 11), S23, &H265E5A51
    md5_GG b, c, d, a, X(k 
    + 0), S24, &HE9B6C7AA
    md5_GG a, b, c, d, X(k 
    + 5), S21, &HD62F105D
    md5_GG d, a, b, c, X(k 
    + 10), S22, &H2441453
    md5_GG c, d, a, b, X(k 
    + 15), S23, &HD8A1E681
    md5_GG b, c, d, a, X(k 
    + 4), S24, &HE7D3FBC8
    md5_GG a, b, c, d, X(k 
    + 9), S21, &H21E1CDE6
    md5_GG d, a, b, c, X(k 
    + 14), S22, &HC33707D6
    md5_GG c, d, a, b, X(k 
    + 3), S23, &HF4D50D87
    md5_GG b, c, d, a, X(k 
    + 8), S24, &H455A14ED
    md5_GG a, b, c, d, X(k 
    + 13), S21, &HA9E3E905
    md5_GG d, a, b, c, X(k 
    + 2), S22, &HFCEFA3F8
    md5_GG c, d, a, b, X(k 
    + 7), S23, &H676F02D9
    md5_GG b, c, d, a, X(k 
    + 12), S24, &H8D2A4C8A

    md5_HH a, b, c, d, X(k 
    + 5), S31, &HFFFA3942
    md5_HH d, a, b, c, X(k 
    + 8), S32, &H8771F681
    md5_HH c, d, a, b, X(k 
    + 11), S33, &H6D9D6122
    md5_HH b, c, d, a, X(k 
    + 14), S34, &HFDE5380C
    md5_HH a, b, c, d, X(k 
    + 1), S31, &HA4BEEA44
    md5_HH d, a, b, c, X(k 
    + 4), S32, &H4BDECFA9
    md5_HH c, d, a, b, X(k 
    + 7), S33, &HF6BB4B60
    md5_HH b, c, d, a, X(k 
    + 10), S34, &HBEBFBC70
    md5_HH a, b, c, d, X(k 
    + 13), S31, &H289B7EC6
    md5_HH d, a, b, c, X(k 
    + 0), S32, &HEAA127FA
    md5_HH c, d, a, b, X(k 
    + 3), S33, &HD4EF3085
    md5_HH b, c, d, a, X(k 
    + 6), S34, &H4881D05
    md5_HH a, b, c, d, X(k 
    + 9), S31, &HD9D4D039
    md5_HH d, a, b, c, X(k 
    + 12), S32, &HE6DB99E5
    md5_HH c, d, a, b, X(k 
    + 15), S33, &H1FA27CF8
    md5_HH b, c, d, a, X(k 
    + 2), S34, &HC4AC5665

    md5_II a, b, c, d, X(k 
    + 0), S41, &HF4292244
    md5_II d, a, b, c, X(k 
    + 7), S42, &H432AFF97
    md5_II c, d, a, b, X(k 
    + 14), S43, &HAB9423A7
    md5_II b, c, d, a, X(k 
    + 5), S44, &HFC93A039
    md5_II a, b, c, d, X(k 
    + 12), S41, &H655B59C3
    md5_II d, a, b, c, X(k 
    + 3), S42, &H8F0CCC92
    md5_II c, d, a, b, X(k 
    + 10), S43, &HFFEFF47D
    md5_II b, c, d, a, X(k 
    + 1), S44, &H85845DD1
    md5_II a, b, c, d, X(k 
    + 8), S41, &H6FA87E4F
    md5_II d, a, b, c, X(k 
    + 15), S42, &HFE2CE6E0
    md5_II c, d, a, b, X(k 
    + 6), S43, &HA3014314
    md5_II b, c, d, a, X(k 
    + 13), S44, &H4E0811A1
    md5_II a, b, c, d, X(k 
    + 4), S41, &HF7537E82
    md5_II d, a, b, c, X(k 
    + 11), S42, &HBD3AF235
    md5_II c, d, a, b, X(k 
    + 2), S43, &H2AD7D2BB
    md5_II b, c, d, a, X(k 
    + 9), S44, &HEB86D391

    = AddUnsigned(a, AA)
    = AddUnsigned(b, BB)
    = AddUnsigned(c, CC)
    = AddUnsigned(d, DD)
    Next

    If stype = 32 Then
        MD5 
    = LCase(WordToHex(a) & WordToHex(b) & WordToHex(c) & WordToHex(d))
    Else
        MD5 
    = LCase(WordToHex(b) & WordToHex(c))
    End If

    End Function

    Private Function AddUnsigned(lX, lY)
    Dim lX4
    Dim lY4
    Dim lX8
    Dim lY8
    Dim lResult

    lX8 
    = lX And &H80000000
    lY8 
    = lY And &H80000000
    lX4 
    = lX And &H40000000
    lY4 
    = lY And &H40000000

    lResult 
    = (lX And &H3FFFFFFF) + (lY And &H3FFFFFFF)

    If lX4 And lY4 Then
    lResult 
    = lResult Xor &H80000000 Xor lX8 Xor lY8
    ElseIf lX4 Or lY4 Then
    If lResult And &H40000000 Then
    lResult 
    = lResult Xor &HC0000000 Xor lX8 Xor lY8
    Else
    lResult 
    = lResult Xor &H40000000 Xor lX8 Xor lY8
    End If
    Else
    lResult 
    = lResult Xor lX8 Xor lY8
    End If

    AddUnsigned 
    = lResult
    End Function

    Private Function LShift(lValue, iShiftBits)
    If iShiftBits = 0 Then
    LShift 
    = lValue
    Exit Function
    ElseIf iShiftBits = 31 Then
    If lValue And 1 Then
    LShift 
    = &H80000000
    Else
    LShift 
    = 0
    End If
    Exit Function
    ElseIf iShiftBits < 0 Or iShiftBits > 31 Then
    Err.Raise 
    6
    End If

    If (lValue And m_l2Power(31 - iShiftBits)) Then
    LShift 
    = ((lValue And m_lOnBits(31 - (iShiftBits + 1))) * m_l2Power(iShiftBits)) Or &H80000000
    Else
    LShift 
    = ((lValue And m_lOnBits(31 - iShiftBits)) * m_l2Power(iShiftBits))
    End If
    End Function

    Private Function RShift(lValue, iShiftBits)
    If iShiftBits = 0 Then
    RShift 
    = lValue
    Exit Function
    ElseIf iShiftBits = 31 Then
    If lValue And &H80000000 Then
    RShift 
    = 1
    Else
    RShift 
    = 0
    End If
    Exit Function
    ElseIf iShiftBits < 0 Or iShiftBits > 31 Then
    Err.Raise 
    6
    End If

    RShift 
    = (lValue And &H7FFFFFFE)  m_l2Power(iShiftBits)

    If (lValue And &H80000000) Then
    RShift 
    = (RShift Or (&H40000000  m_l2Power(iShiftBits - 1)))
    End If
    End Function

    Private Function RotateLeft(lValue, iShiftBits)
    RotateLeft 
    = LShift(lValue, iShiftBits) Or RShift(lValue, (32 - iShiftBits))
    End Function
    m_Base64模块:
    Option Explicit
    '除以2的一次方是右移一位
    '
    乘以2的一次方是左移一位
    '
    (bytInText(i) And &HFC)  (2 ^ 2)
    '
    第一个字节的内容And运算0xFC(11111100)(取左边6位),再除以2的二次方(右移2位)
    '
    (bytInText(i) And &H3) * (2 ^ 4) Or (bytInText(i + 1) And &HF0)  (2 ^ 4)
    '
    第一个字节的内容And运算0x03(00000011)(取右边2位),再乘以2的四次方(左移4位)
    '
    第二个字节的内容And运算0xF0(11110000)(取左边4位),再除以2的四次方(右移4位)
    '
    两个结果再Or运算
    '
    (bytInText(i + 1) And &HF) * (2 ^ 2) + (bytInText(i + 2) And &HC0)  (2 ^ 6)
    '
    第二个字节的内容And运算0x0F(00001111)(取右边4位),再乘以2的二次方(左移2位)
    '
    第三个字节的内容And运算0xC0(11000000)(取左边2位),再除以2的六次方(右移6位)
    '
    两个结果再Or运算
    '
    bytInText(i + 2) And &H3F
    '
    第三个字节的内容And运算0x3F(00111111)(取右边6位)
            
    'Base64编码函数
    Public Function Base64_Encode(bytInText() As ByteAs Byte()
        
    Dim Base64EncodeTable() As Byte
        
    Dim lngInTextLen As Long, lngMod As Long, i As Long
        
    Dim bytEncode() As Byte, lngEncodeLen As Long
        
        Base64_Encode 
    = Chr(0)  '初始化函数返回值
        
        Base64EncodeTable() 
    = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" '初始化Base64编码表
        Base64EncodeTable() = StrConv(Base64EncodeTable(), vbFromUnicode)  '转换为ANSI编码
        
        
    If LBound(bytInText) <> 0 Then Exit Function  'bytInText数组下标不从零开始则出错返回
        
        lngInTextLen 
    = UBound(bytInText) - LBound(bytInText) + 1  '计算bytInText数组长度
        
        lngMod 
    = lngInTextLen Mod 3 '取模3后的余数(结果只有0、1、2三种情况)
        If lngMod = 0 Then
            lngEncodeLen 
    = lngInTextLen / 3 * 4  '求编码后的长度
            lngInTextLen = lngInTextLen / 3 * 3  '取3的整数倍
        ElseIf lngMod = 1 Then
            lngEncodeLen 
    = (lngInTextLen + 2/ 3 * 4  '求编码后的长度
            lngInTextLen = ((lngInTextLen + 2/ 3 - 1* 3 '取3的整数倍
        ElseIf lngMod = 2 Then
            lngEncodeLen 
    = (lngInTextLen + 1/ 3 * 4  '求编码后的长度
            lngInTextLen = ((lngInTextLen + 1/ 3 - 1* 3 '取3的整数倍
        End If
        
        
    'MsgBox "编码后的长度为" & lngEncodeLen & "字节!"
        'MsgBox "3的整数倍为" & lngInTextLen
        
        
    ReDim bytEncode(0 To lngEncodeLen - 1'重新定义编码缓冲区
        lngEncodeLen = 0  '初始化编码长度计数
        
        
    For i = 0 To lngInTextLen - 1 Step 3
            bytEncode(lngEncodeLen) 
    = Base64EncodeTable((bytInText(i) And &HFC)  (2 ^ 2))
            bytEncode(lngEncodeLen 
    + 1= Base64EncodeTable((bytInText(i) And &H3) * (2 ^ 4Or (bytInText(i + 1And &HF0)  (2 ^ 4))
            bytEncode(lngEncodeLen 
    + 2= Base64EncodeTable((bytInText(i + 1And &HF) * (2 ^ 2Or (bytInText(i + 2And &HC0)  (2 ^ 6))
            bytEncode(lngEncodeLen 
    + 3= Base64EncodeTable(bytInText(i + 2And &H3F)
            lngEncodeLen 
    = lngEncodeLen + 4
        
    Next
        
        i 
    = lngInTextLen - 1 + 1
        
    If lngMod = 1 Then  '对剩余字节进行填充
            bytEncode(lngEncodeLen) = Base64EncodeTable((bytInText(i) And &HFC)  (2 ^ 2))
            bytEncode(lngEncodeLen 
    + 1= Base64EncodeTable((bytInText(i) And &H3) * (2 ^ 4))
            bytEncode(lngEncodeLen 
    + 2= Base64EncodeTable(64)  '填充=
            bytEncode(lngEncodeLen + 3= Base64EncodeTable(64)  '填充=
            lngEncodeLen = lngEncodeLen + 4
        
    ElseIf lngMod = 2 Then
            bytEncode(lngEncodeLen) 
    = Base64EncodeTable((bytInText(i) And &HFC)  (2 ^ 2))
            bytEncode(lngEncodeLen 
    + 1= Base64EncodeTable((bytInText(i) And &H3) * (2 ^ 4Or (bytInText(i + 1And &HF0)  (2 ^ 4))
            bytEncode(lngEncodeLen 
    + 2= Base64EncodeTable((bytInText(i + 1And &HF) * (2 ^ 2))
            bytEncode(lngEncodeLen 
    + 3= Base64EncodeTable(64)  '填充=
            lngEncodeLen = lngEncodeLen + 4
        
    End If

        Base64_Encode 
    = bytEncode()
    End Function

    'Base64解码函数
    Public Function Base64_Decode(bytInText() As ByteAs Byte()
        
    Dim Base64DecodeTable(1 To 122As Byte
        
    Dim lngInTextLen As Long, i As Long
        
    Dim bytDecode() As Byte, lngDecodeLen As Long
        
        Base64_Decode 
    = Chr(0)  '初始化函数返回值
        
        
    If LBound(bytInText) <> 0 Then Exit Function  'bytInText数组下标不从零开始则出错返回
        
        lngInTextLen 
    = UBound(bytInText) - LBound(bytInText) + 1  '计算bytInText数组长度
        If lngInTextLen Mod 4 <> 0 Then Exit Function  '输入编码不是4的倍数则出错返回
        
        
    For i = 1 To 122  '初始化Base64解码表
            Select Case i
            
    Case 43  '+
                Base64DecodeTable(i) = 62
            
    Case 47  '/
                Base64DecodeTable(i) = 63
            
    Case 48 To 57  '0 - 9
                Base64DecodeTable(i) = 52 + (i - 48)
            
    Case 65 To 90  'A - Z
                Base64DecodeTable(i) = 0 + (i - 65)
            
    Case 97 To 122  'a - z
                Base64DecodeTable(i) = 26 + (i - 97)
            
    Case Else
                Base64DecodeTable(i) 
    = 255
            
    End Select
        
    Next
        lngDecodeLen 
    = lngInTextLen / 4 * 3  '求解码后的最大长度
        ReDim bytDecode(0 To lngDecodeLen - 1)  '重新定义解码缓冲区
        'MsgBox "解码后的最大长度为:" & lngDecodeLen
        
        lngDecodeLen 
    = 0  '初始化解码长度
        
        
    For i = 0 To lngInTextLen - 1 Step 4
            bytDecode(lngDecodeLen) 
    = (Base64DecodeTable(bytInText(i)) * (2 ^ 2)) Or ((Base64DecodeTable(bytInText(i + 1)) And &H30)  (2 ^ 4))
            bytDecode(lngDecodeLen 
    + 1= ((Base64DecodeTable(bytInText(i + 1)) And &HF) * (2 ^ 4)) Or ((Base64DecodeTable(bytInText(i + 2)) And &H3C)  (2 ^ 2))
            bytDecode(lngDecodeLen 
    + 2= ((Base64DecodeTable(bytInText(i + 2)) And &H3) * (2 ^ 6)) Or Base64DecodeTable(bytInText(i + 3))
            lngDecodeLen 
    = lngDecodeLen + 3
        
    Next
        
        
    If bytInText(lngInTextLen - 1= &H3D Then  '判断最后两个字节的情况,求解码后的实际长度
            If bytInText(lngInTextLen - 2= &H3D Then
                lngDecodeLen 
    = lngDecodeLen - 2  '最后两个字节为"="
            Else
                lngDecodeLen 
    = lngDecodeLen - 1  '最后一个字节为"="
            End If
            bytDecode(lngDecodeLen) 
    = 0  '在实际长度的后一个字节放个结束符
        End If
        
    'MsgBox "解码后的实际长度为:" & lngDecodeLen
        
        Base64_Decode 
    = bytDecode()
    End Function
    frmLogin.frm窗体:
    Option Explicit

    Private Sub cmdAdd_Click()  '添加按钮
        frmSet.Show 1  '模态显示设置对话框
        Call QQ_DB_UpdataUserList(lvListView)
    End Sub

    Private Sub cmdDel_Click()  '删除按钮
        Dim i As Integer, blnSelect As Boolean
        
        
    For i = 1 To lvListView.ListItems.Count
            
    If lvListView.ListItems(i).Checked = True Then
                blnSelect 
    = True
                
    If MsgBox("你确定要删除QQ号码为:" & lvListView.ListItems(i).Text & "的记录吗?", vbInformation + vbOKCancel, "QQ自动登录器"= vbOK Then
                    
    Call QQ_DB_Del(lvListView.ListItems(i).Text)
                
    End If
            
    End If
        
    Next
        
        
    Call QQ_DB_UpdataUserList(lvListView)
        
    If blnSelect = False Then
            
    MsgBox "请先选择一个QQ号码!", vbInformation + vbOKOnly, "QQ自动登录器"
        
    End If
    End Sub

    Private Sub cmdExit_Click()  '退出按钮
        End
    End Sub

    Private Sub cmdLogin_Click()  '登录按钮
        Dim i As Integer, strNum As String, intLoginMode As Integer, blnSelect As Boolean
        
        
    If chkLoginMode.Value = 1 Then  '选中隐身登录复选框
            intLoginMode = 40
        
    Else
            intLoginMode 
    = 41
        
    End If
        
        
    For i = 1 To lvListView.ListItems.Count
            
    If lvListView.ListItems(i).Checked = True Then
                blnSelect 
    = True
                
                strNum 
    = lvListView.ListItems(i).Text
                
    Call QQ_AutoLogin(strNum, intLoginMode) '自动登录QQ
            End If
        
    Next
        
        
    If blnSelect = False Then
            
    MsgBox "请先选择一个QQ号码!", vbInformation + vbOKOnly, "QQ自动登录器"
        
    End If
    End Sub

    Private Sub cmdModify_Click()  '修改按钮
        Dim i As Integer, blnSelect As Boolean
        
        
    For i = 1 To lvListView.ListItems.Count
            
    If lvListView.ListItems(i).Checked = True Then
                blnSelect 
    = True
                frmSet.g_strNum 
    = lvListView.ListItems(i).Text
                frmSet.Show 
    1
            
    End If
        
    Next
        
        
    If blnSelect = False Then
            
    MsgBox "请先选择一个QQ号码!", vbInformation + vbOKOnly, "QQ自动登录器"
        
    End If
    End Sub

    Private Sub Form_Load()
        
    If QQ_DB_Connect = False Then '连接数据库
            End
        
    End If
        lvListView.SmallIcons 
    = ilImageList
        
    Call QQ_DB_UpdataUserList(lvListView)
    End Sub

    Private Sub lvListView_ItemClick(ByVal Item As MSComctlLib.ListItem)
        lvListView.SelectedItem.Checked 
    = Not lvListView.SelectedItem.Checked
    End Sub

    Private Sub Form_Unload(Cancel As Integer)
        
    Call QQ_DB_Deconnetion  '断开与数据库的连接
    End Sub
    frmSet.frm窗体:
    Option Explicit
    Public g_strNum As String  '保存主窗口传递过来的QQ号码变量

    Private Sub cmdCancel_Click()  '取消按钮
        Unload frmSet
    End Sub

    Private Sub cmdOK_Click()  '确定按钮
        Dim strNum As String, strPwd As String, lngRet As Long
        
        
    If Trim(txtNumber.Text) = "" Or Trim(txtPassword.Text) = "" Or Trim(txtPassword2.Text) = "" Then
            
    MsgBox "请输入完整的信息!", vbInformation Or vbOKOnly, "QQ自动登录器"
            txtNumber.SetFocus
            
    Exit Sub
        
    End If
        
        
    If Trim(txtPassword.Text) <> Trim(txtPassword2.Text) Then
            
    MsgBox "两次输入的密码不一致,请重新输入!", vbInformation Or vbOKOnly, "QQ自动登录器"
            txtPassword.Text 
    = ""
            txtPassword2.Text 
    = ""
            txtPassword.SetFocus
            
    Exit Sub
        
    End If
        
        strNum 
    = Trim(txtNumber.Text)
        strPwd 
    = Trim(txtPassword.Text)
        
        
    If g_strNum <> "" Then  '修改密码信息
            Call QQ_DB_Edit(strNum, strPwd)
            
    MsgBox "修改成功!", vbInformation Or vbOKOnly, "QQ自动登录器"
            Unload frmSet
        
    Else '添加密码信息
            If QQ_DB_Find(strNum) Then
                
    If MsgBox("您所输入的QQ号码信息已存在数据库中,是否改变密码信息?", vbInformation Or vbYesNo, "QQ自动登录器"= vbYes Then
                    
    Call QQ_DB_Edit(strNum, strPwd)
                    
    MsgBox "修改成功!", vbInformation Or vbOKOnly, "QQ自动登录器"
                    Unload frmSet
                
    Else
                    
    Exit Sub
                
    End If
            
    Else
                
    Call QQ_DB_Add(strNum, strPwd)
                
    MsgBox "记录成功!", vbInformation Or vbOKOnly, "QQ自动登录器"
                Unload frmSet
            
    End If
        
    End If
    End Sub

    Private Sub Form_Load()
        
    If g_strNum <> "" Then
            txtNumber.Text 
    = g_strNum
            txtNumber.Enabled 
    = False
        
    End If
    End Sub

    Private Sub Form_Unload(Cancel As Integer)
        g_strNum 
    = ""
    End Sub

    Private Sub txtNumber_KeyPress(KeyAscii As Integer)
        
    If KeyAscii >= Asc(0And KeyAscii <= Asc(9Or KeyAscii = 8 Or KeyAscii = 13 Then
            
        
    Else
            KeyAscii 
    = 0
        
    End If
    End Sub
         该程序用ACCESS保存QQ的密码信息,可以实现批量登录。当你有多个QQ号码需要登录的时候就不用一个个去按QQ输密码了。程序还有一个需要改进的地方,就是保存密码的时候保存的是明文,虽然数据库加了密码,但现在ACCESS数据库好像不是很安全,网上经常看到有破解ACCESS数据库密码之类的文章。所以建议大家在保存密码的时候最好再加个自己的加密的方法。(直接保存密码的MD5也是不安全的喔,别人知道了MD5一样是可以登录你QQ的)
  • 相关阅读:
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Listener介绍
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Filter介绍
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP2的自定义标签
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Servlet介绍
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP脚本的9个内置对象(2)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP脚本的9个内置对象(1)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP的3个编译指令
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP4种基本语法
    HDU6118:度度熊的交易计划(入门级最小费用可行流)
    BZOJ-4819: 新生舞会(01分数规划+费用流)
  • 原文地址:https://www.cnblogs.com/ZYM/p/1151954.html
Copyright © 2020-2023  润新知