V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sleshep
V2EX  ›  Python

QQ 连连看外挂 Python 版本.

  •  3
     
  •   sleshep · 2017-01-22 17:37:54 +08:00 · 4474 次点击
    这是一个创建于 2622 天前的主题,其中的信息可能已经有所发展或是发生改变。

    初中时候写过一个 MFC 的,最近翻代码找到了,倍感怀念,于是写了个 Python 版的,大牛别喷

    使用方法:打开 QQ 游戏连连看,找到个房间,比如高手区 然后打开脚本就可挂机了

    代码:

    #!/usr/bin/env python
    # coding:utf-8
    """
    作者:sleshep
    邮箱:[email protected]
    日期:16-9-19
    时间:上午 11:50
    """
    import struct
    import time
    from ctypes import *
    from logging import basicConfig, getLogger, DEBUG
    
    basicConfig()
    log = getLogger(__name__)
    log.setLevel(DEBUG)
    user32 = WinDLL('user32.dll')
    kernel32 = WinDLL('kernel32.dll')
    
    WM_LBUTTONDOWN = 0x201
    WM_LBUTTONUP = 0x202
    
    
    def read_chess_memory():
        hwnd = get_llk_hwnd()
        chess = create_string_buffer(11 * 19)
    
        if hwnd:
            pid = c_int()
            user32.GetWindowThreadProcessId(hwnd, byref(pid))
            h_process = kernel32.OpenProcess(0xf0000 | 0x100000 | 0xfff, 0, pid)
            kernel32.ReadProcessMemory(h_process, 0x129fb4, byref(chess), 11 * 19, byref(pid))
            kernel32.CloseHandle(h_process)
        return chess
    
    
    def get_llk_hwnd():
        hwnd = user32.FindWindowA('#32770'.encode('ascii'), 'QQ 游戏 - 连连看角色版'.encode('gb2312'))
        if not hwnd:
            log.info('找不到游戏了.')
        return hwnd
    
    
    def make_long(x, y):
        return c_long((x << 16) + y)
    
    
    def click_both(x, y, xx, yy):
        # print('a({},{}) b({},{})'.format(x, y, xx, yy))
        hwnd = get_llk_hwnd()
        if hwnd:
            first_x = 28
            first_y = 199
            user32.SendMessageA(hwnd, WM_LBUTTONDOWN, 0, make_long(first_y + y * 35, first_x + x * 31))
            user32.SendMessageA(hwnd, WM_LBUTTONUP, 0, make_long(first_y + y * 35, first_x + x * 31))
            user32.SendMessageA(hwnd, WM_LBUTTONDOWN, 0, make_long(first_y + yy * 35, first_x + xx * 31))
            user32.SendMessageA(hwnd, WM_LBUTTONUP, 0, make_long(first_y + yy * 35, first_x + xx * 31))
    
    
    def clear_all():
        chess = read_chess_memory()
        for x in range(19):
            for y in range(11):
                for xx in range(19):
                    for yy in range(11):
                        if chess.raw[19 * y + x] != 0 and chess.raw[19 * yy + xx] != 0 and (xx != x or yy != y) and \
                                        chess.raw[19 * y + x] == chess.raw[19 * yy + xx]:
                            click_both(x, y, xx, yy)
    
    
    def get_chess_count():
        return len(list(filter(int, read_chess_memory().raw)))
    
    
    def send_redeploy():
        hwnd = get_llk_hwnd()
        if hwnd:
            log.info('检测到无解,重列!')
            y = 197
            x = 652
            user32.SendMessageA(hwnd, WM_LBUTTONDOWN, 0, make_long(y, x))
            user32.SendMessageA(hwnd, WM_LBUTTONUP, 0, make_long(y, x))
            time.sleep(2)
    
    
    def fully_clear():
        while get_chess_count():
            last_count = get_chess_count()
            clear_all()
            if last_count == get_chess_count() and last_count != 0:
                send_redeploy()
    
    
    def start_game():
        hwnd = get_llk_hwnd()
        if hwnd:
            y = 570
            x = 668
            user32.SendMessageA(hwnd, WM_LBUTTONDOWN, 0, make_long(y, x))
            user32.SendMessageA(hwnd, WM_LBUTTONUP, 0, make_long(y, x))
    
    
    def quick_start():
        """
        大厅快速开始没法 SendMessage ,所以只能移动鼠标然后再点
        """
        hwnd = user32.FindWindowA(0, '连连看'.encode('gb2312'))
        if hwnd:
            rect = create_string_buffer(16)
            user32.GetWindowRect(hwnd, byref(rect))
            left_x, left_y, *_ = struct.unpack('<IIII', rect.raw)
            x = 275 + left_x
            y = 150 + left_y
            user32.SetCursorPos(x, y)
            time.sleep(.5)
            user32.mouse_event(0x0002, x, y, 0, 0)
            time.sleep(.5)
            user32.mouse_event(0x0004, x, y, 0, 0)
            time.sleep(3)
    
    
    def main():
        while 1:
            if not get_llk_hwnd():
                log.info('没找到游戏,估计被踢出来了,现在重新进..')
                quick_start()
            start_game()
            time.sleep(1)
            fully_clear()
    
    
    if __name__ == '__main__':
        main()
    
    第 1 条附言  ·  2017-06-27 14:55:07 +08:00
    基址最新是 0x189f78
    15 条回复    2017-01-23 21:00:51 +08:00
    sleshep
        1
    sleshep  
    OP
       2017-01-22 17:39:00 +08:00
    windows xp + python3.4 成功,只能运行于 python3+
    windows7 以上有 ASLR 基地址可能会有问题,没试验
    lucifer4he
        2
    lucifer4he  
       2017-01-22 17:43:01 +08:00
    现在写的不是应该 win10 + python3 么
    sleshep
        3
    sleshep  
    OP
       2017-01-22 17:46:15 +08:00
    @lucifer4he
    虚拟机里只装了 xp
    母鸡 ubuntu
    zhuce1234578888
        4
    zhuce1234578888  
       2017-01-22 18:42:22 +08:00
    能不能写个文章,分析下这个脚本,大神
    YingJie
        5
    YingJie  
       2017-01-23 00:00:37 +08:00 via iPhone
    一些 win api 的调用, py 不适合干这个
    jy02201949
        6
    jy02201949  
       2017-01-23 00:55:33 +08:00 via iPhone
    连连看,当初开外挂撩妹子装高手
    master13
        7
    master13  
       2017-01-23 09:02:40 +08:00
    py3 对中文支持正好
    #coding:utf8
    '#32770'.encode('ascii'), 'QQ 游戏 - 连连看角色版'.encode('gb2312')
    mcds
        8
    mcds  
       2017-01-23 09:33:14 +08:00
    import * 这个习惯不太好~
    0x5010
        9
    0x5010  
       2017-01-23 10:29:20 +08:00
    @mcds ctypes 一般还真都这么用
    sleshep
        10
    sleshep  
    OP
       2017-01-23 11:47:56 +08:00
    @mcds
    一看你就是没咋写过
    whx20202
        11
    whx20202  
       2017-01-23 13:11:44 +08:00
    @mcds 说说为什么不好
    ech0x
        12
    ech0x  
       2017-01-23 15:46:12 +08:00 via iPhone
    @whx20202 命名空间被导入了,有可能出现冲突。
    ech0x
        13
    ech0x  
       2017-01-23 15:47:03 +08:00 via iPhone
    @ech0x 不过有些库无所谓。。。
    mcds
        14
    mcds  
       2017-01-23 18:18:23 +08:00
    @sleshep 哈, ctypes 还真用的少..
    Mavious
        15
    Mavious  
       2017-01-23 21:00:51 +08:00 via iPad
    咦,我一个非程序猿都看懂了不少行,和按键精灵的代码很像。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4509 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 05:34 · PVG 13:34 · LAX 22:34 · JFK 01:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.