使用WinIo32绕过密码控件实现自动登录
阅读原文时间:2024年07月31日阅读:1

通过winIO32绕过密码控件,实现自动登录

环境:

vmware上安装windows 32位系统:windows xp / windows 7

selenium版本: 3.11.0

IEDriverServer版本: win32_3.9.0, 放在C:\Program Files\Internet Explorer目录下

python版本: 2.7.14

实现思路:
1.由于密码控件无法用html元素定位,所以首先计算出密码控件的坐标位置;
2.模拟鼠标点击获取密码输入框焦点,再使用winIO32实现模拟键盘输入密码;
3.登录名使用selenium填写
4.图片验证码获取到位置后截图,调用打码服务,然后使用selenium填写识别后的验证码;
5.通过selenium获取到登录按钮,点击登录,最后返回登录成功的cookie。
python实现代码:
使用pip安装以下模块:
flask
flask-script
pillow
pyautogui
requests
selenium

启动服务,地址:127.0.0.1:80

开发环境启动方式:
python login_service.py runserver -h 127.0.0.1 -p 80

生产环境启动方式:
uwsgi --socket 0.0.0.0:80 --protocol=http --wsgi-file myflaskapp.py --callable app --processes 4 --threads 2 --stats 0.0.0.0:9191


# -*- coding: UTF-8 -*-
# login_service.py 登录请求入口
from flask import Flask
from flask.ext.script import Manager
import selenium_service

app = Flask(__name__)
manager = Manager(app)

@app.route('/login/<username>/<password>')
def login(username, password):
    print('request is coming, params:%s, %s' % (username, password))
    ret = {}

    #这边参数要转字符串格式,否则驱动在模拟键盘输入密码时会有问题
    ret = selenium_service.login(str(username), str(password))
    return ret

@app.route('/')
def hello():
    return 'hello world'

if __name__ == '__main__':
    manager.run()


# -*- coding: UTF-8 -*-
# selenium_service.py 调用selenium登录
import os
import time
import json
from selenium.common.exceptions import UnexpectedAlertPresentException
import parse_img
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from PIL import Image
import pyautogui
import ctypes_util
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

timestamp = str(int(round(time.time() * 1000)))
iedriver1 = 'C:/Program Files/Internet Explorer/IEDriverServer.exe'
os.environ['webdriver.ie.driver'] = iedriver1
img_name = timestamp + '.png'
new_img_name = 'new_' + img_name
browser = None    

def home():
    lct = None
    try:
        global browser
        browser = webdriver.Ie(iedriver1)
        browser.get('https://www.xxxx.com/login/loginreg.jsp')
    except UnexpectedAlertPresentException as e:
        print('unexpected alert present when visit the website.')

def refresh():
    #点击刷新图片验证码
    browser.find_element_by_class_name('yzm_a').click()

def switchToCurrentWindow():
    h = browser.current_window_handle
    browser.switch_to.window(h)

def getImg():
    element = browser.find_element_by_class_name('yzm_img')
    #switchToCurrentWindow()
    browser.get_screenshot_as_file(img_name)
    im = Image.open(img_name)
    left = element.location['x']
    top = element.location['y']
    right = element.location['x'] + element.size['width']
    bottom = element.location['y'] + element.size['height']
    region = im.crop((left, top, right, bottom))
    # 保存图片验证码
    region.save(new_img_name)
    # 调用打码服务识别图片验证码
    code = parse_img.parseImage(new_img_name)
    removeImg(img_name)
    removeImg(new_img_name)
    print('parse img return code:' + code)
    return code

def input(username, password, code):
    browser.maximize_window()
    x1 = 210
    y1 = 350
    # 点击获取密码输入框焦点
    pyautogui.click(x1,y1)
    # 调用winIo驱动输入密码
    try:
        ctypes_util.typestr(password)
    except Exception as e:
        print(e)
    # 输入用户名和图片验证码
    browser.find_element_by_id('_@IMGRC@_').send_keys(code)
    browser.find_element_by_id('loginname').send_keys(username)
    #点击登录按钮
    browser.find_element_by_class_name('btn2').click()

def login(username, password):
    try:
        home()
        code = getImg()
        if len(code.strip()) != 6 or code == 'ERROR':
            refresh()
            code = getImg()
        input(username, password, code)
        browser.implicitly_wait(0.5)
    except Exception as e:
        print(e)
    #登录结果检查
    #status: -1表示验证码错误,0表示登录名或密码错误,1表示登录成功,-2表示未知错误
    status = 0
    result = ''
    errMsg = ''
    _msg_ = ''
    lgnInfo = ''
    pwdInfo = ''

    try:
        lgnInfo = browser.find_element_by_id('loginNameInfo').text
        pwdInfo = browser.find_element_by_id('passwordInfo').text
        print('loginNameInfo:%s, passwordInfo:%s' %(lgnInfo, pwdInfo))
    except:
        print('loginNameInfo or passwordInfo not exist!')

    try:
        errMsg = browser.find_element_by_id('_error_field_').text
    except:
        print('errMsg not exist!')

    try:
        _msg_ = browser.find_element_by_id('_@MSG@_').text
    except:
        print('_msg_ not exist!')

    print('errorMsg:' + errMsg)
    print('_msg_:' + _msg_)

    msg = errMsg if errMsg != '' else _msg_
    inputInfo = lgnInfo if lgnInfo != '' else pwdInfo
    print('msg=' + msg)
    if len(msg.strip()) > 0:
        if '验证码输入错误' in msg:
            status = -1
        elif '登录名或密码错误' in msg:
            status = 0
        else:
            status = -2
    elif len(inputInfo.strip()) > 0:
        status = -3
        msg = '登录名或密码输入错误,请重试!'
    else:
        status = 1
        msg = '登录成功'
        result = ';'.join([item['name'] + '=' + item['value'] for item in browser.get_cookies()])
    #关闭browser
    browser.quit()
    #组装返回报文
    ret = {}
    ret['result'] = result
    ret['status'] = status
    ret['message'] = msg
    return json.dumps(ret, ensure_ascii=False)

def removeImg(path):
    if os.path.exists(path):
        os.remove(path)

if __name__ == '__main__':
    result = login('sel2364', 'sel2364')
    print(result)


# -*- coding: UTF-8 -*-
# ctypes_util.py 调用dll中的函数,模拟键盘输入
from ctypes import *
import platform

def typestr(s):
    if platform.system() == 'Windows':
        libc = cdll.LoadLibrary('testdll_driver.dll')
        libc.output(s)

if __name__ == '__main__':
    typestr('aaabbb')


# -*- coding: UTF-8 -*-
# parse_img.py 调用打码服务
import requests
import json

url = "http://xxx.xxxx.com/captcha/parse"
# fo = open("code.jpg", "rb")

headers={
    "appkey":"******",
    "source":"******"
}

def parseImage(file):
    fo = open(file, "rb")
    body = fo.read()
    resp = requests.post(url, body, headers=headers)
    #print(resp.content)
    jsonobj = json.loads(resp.content)
    return jsonobj['code']

if __name__ == '__main__':
    code = parseImage("code.jpg")
    print("code=" + code);