python一键登录srun校园网(以深圳技术大学为例)


一、需求分析

指路:https://www.srun.com/cn/list/info?id=44

Srun4K 校园网解决方案,这群人自以为自己的系统搞得很好,可以帮助使用者偷懒的管理网络,但是对于用户端其实每天充斥着断网、卡顿、认证不跳等诸多问题,所以写个客户端便捷的进行断网重连。

二、实现过程

这里本来不想写的,但是某人要求教教他抓包,我就不点名了
由于人在公司,所以截图部分等我想弄的时候再弄吧

2.1 分析api

2.1.1 连接到校园网,自动弹出登录认证界面

http://172.19.0.5/srun_portal_success?ac_id=28&theme=pro&wlanacname=&wlanuserip=10.161.21.150

2.1.2 先输入错误的账号密码,按F12看会获取哪些信息

在这里插入图片描述

2.1.3 api

get_challenge
请求方式为get,地址为
http://172.19.0.5/cgi-bin/get_challenge

请求的数据为

在这里插入图片描述

参数分析
callbackjsonp解决跨域的参数
username校园网账户
ip本机自动获取到的ip
_当前时间戳(32)位

这里是不需要分析的。唯一需要注意的是challenge,因为太过诡异。


srun_portal
请求方式为get,地址为
http://172.19.0.5/cgi-bin/srun_portal
请求数据为
在这里插入图片描述
看到这一大串,可能不太好下手。确实参数有点多。
多观察几次,先找不变的参数,排除掉。

参数分析
callback和第一次的callback意思一样,排除
actionlogin
username账户
ac_id1(意义不详,每次都一样可以排除了)
ip自动获取的ip
n200(和ac_id一样排除)
type1(和ac_id一样排除)
oswindows10
namewindows
double_stack0
_当前时间戳(13位)

一共14个参数,一下子pass11个,还剩下3个参数分别是 password chksum info
接下来开始分析js文件,一共4个
搜索关键字:password
在这里插入图片描述
这个是什么,这个不就是我们请求的参数吗,一下全都出来了,继续搜索对应关键字。
在这里插入图片描述
hmd5就找出来了,是经过md5加密之后的密码,还做过加盐处理
至于token就是之前的challenge

接下来是chksum一样的方法,搜索关键字。
在这里插入图片描述
可以发现是简单的字符串拼接。然后用sha1加密得出chksum。
可是还有个i是什么呢。继续找吧
在这里插入图片描述
都出来了,对象转为字符串之后进行xEncode(天知道是什么加密方式)进行加密,反正也是加盐的加密。也用到了token。之后再进行一次base64加密。i就出来了
i出来了,chksum也出来了。顺序不能错。
处理顺序

参数加密方式
passwordHmac MD5加密
chksumsha1处理
3个参数都需要用到token,至于加密方式更加是坑
只有sha1和md5是可以直接用的。
xencode更加不知道是什么鬼东西,base64是经过改动的。和正常的base64是不一样的。

2.2 分析加密

python版的xencode

import math
def force(msg):
    ret = []
    for w in msg:
        ret.append(ord(w))
    return bytes(ret)
def ordat(msg, idx):
    if len(msg) > idx:
        return ord(msg[idx])
    return 0
def sencode(msg, key):
    l = len(msg)
    pwd = []
    for i in range(0, l, 4):
        pwd.append(
            ordat(msg, i) | ordat(msg, i + 1) << 8 | ordat(msg, i + 2) << 16
            | ordat(msg, i + 3) << 24)
    if key:
        pwd.append(l)
    return pwd
def lencode(msg, key):
    l = len(msg)
    ll = (l - 1) << 2
    if key:
        m = msg[l - 1]
        if m < ll - 3 or m > ll:
            return
        ll = m
    for i in range(0, l):
        msg[i] = chr(msg[i] & 0xff) + chr(msg[i] >> 8 & 0xff) + chr(
            msg[i] >> 16 & 0xff) + chr(msg[i] >> 24 & 0xff)
    if key:
        return "".join(msg)[0:ll]
    return "".join(msg)
def get_xencode(msg, key):
    if msg == "":
        return ""
    pwd = sencode(msg, True)
    pwdk = sencode(key, False)
    if len(pwdk) < 4:
        pwdk = pwdk + [0] * (4 - len(pwdk))
    n = len(pwd) - 1
    z = pwd[n]
    y = pwd[0]
    c = 0x86014019 | 0x183639A0
    m = 0
    e = 0
    p = 0
    q = math.floor(6 + 52 / (n + 1))
    d = 0
    while 0 < q:
        d = d + c & (0x8CE0D9BF | 0x731F2640)
        e = d >> 2 & 3
        p = 0
        while p < n:
            y = pwd[p + 1]
            m = z >> 5 ^ y << 2
            m = m + ((y >> 3 ^ z << 4) ^ (d ^ y))
            m = m + (pwdk[(p & 3) ^ e] ^ z)
            pwd[p] = pwd[p] + m & (0xEFB8D130 | 0x10472ECF)
            z = pwd[p]
            p = p + 1
        y = pwd[0]
        m = z >> 5 ^ y << 2
        m = m + ((y >> 3 ^ z << 4) ^ (d ^ y))
        m = m + (pwdk[(p & 3) ^ e] ^ z)
        pwd[n] = pwd[n] + m & (0xBB390742 | 0x44C6F8BD)
        z = pwd[n]
        q = q - 1
    return lencode(pwd, False)

python版base64

_PADCHAR = "="
_ALPHA = "LVoJPiCN2R8G90yg+hmFHuacZ1OWMnrsSTXkYpUq/3dlbfKwv6xztjI7DeBE45QA"
def _getbyte(s, i):
    x = ord(s[i]);
    if (x > 255):
        print("INVALID_CHARACTER_ERR: DOM Exception 5")
        exit(0)
    return x
def get_base64(s):
    i=0
    b10=0
    x = []
    imax = len(s) - len(s) % 3;
    if len(s) == 0:
        return s
    for i in range(0,imax,3):
        b10 = (_getbyte(s, i) << 16) | (_getbyte(s, i + 1) << 8) | _getbyte(s, i + 2);
        x.append(_ALPHA[(b10 >> 18)]);
        x.append(_ALPHA[((b10 >> 12) & 63)]);
        x.append(_ALPHA[((b10 >> 6) & 63)]);
        x.append(_ALPHA[(b10 & 63)])
    i=imax
    if len(s) - imax ==1:
        b10 = _getbyte(s, i) << 16;
        x.append(_ALPHA[(b10 >> 18)] + _ALPHA[((b10 >> 12) & 63)] + _PADCHAR + _PADCHAR);
    else:
        b10 = (_getbyte(s, i) << 16) | (_getbyte(s, i + 1) << 8);
        x.append(_ALPHA[(b10 >> 18)] + _ALPHA[((b10 >> 12) & 63)] + _ALPHA[((b10 >> 6) & 63)] + _PADCHAR);
    return "".join(x)

md5

import hmac
import hashlib
def get_md5(password,token):
	return hmac.new(token.encode(), password.encode(), hashlib.md5).hexdigest()

sha1

import hmac
import hashlib
def get_md5(password,token):
	return hmac.new(token.encode(), password.encode(), hashlib.md5).hexdigest()

2.3 流程总结

第一次get_challenge是获取token。
中间做了3个信息的处理
最后一步就是登录和认证了

三.模拟登录

完整代码如下:

#coding=utf-8
import ctypes
import hashlib
import json
import math
import random
import socket
import time

import requests


conf = ConfigParser()
conf.read("1.config",encoding='utf-8')
username = conf.get('mysql', 'username')
password = conf.get('mysql', 'password')
init_url="http://172.19.0.5"

def init_getip():
	 """网络获得ip(似乎看起来更靠谱) """
	init_res=requests.get(init_url,headers=header)
	print("初始化获取ip")
	ip=re.search('id="wlanuserip" value="(.*?)"',init_res.text).group(1)
	return ip

def GetLocalIPByPrefix(prefix):
    """ 多网卡情况下,根据前缀获取IP(Windows 下适用) """
    localIP = ''
    for ip in socket.gethostbyname_ex(socket.gethostname())[2]:
        if ip.startswith(prefix):
            localIP = ip
    return localIP
local_ip=GetLocalIPByPrefix('10.')
#local_ip=init_getip()

class MD5(object):

    '''MD5加密//根据js'''
    def a(self, n):
        r = ''
        e = 32 * len(n)
        for i in range(0,e,8):
            r += chr((n[i >> 5] >> i % 32 & 0xffffffff >> i % 32) & 255)
        return r

    def d(self, n):
        r = [0 for _ in range(len(n) >> 2)]
        e = 8 * len(n)
        for i in range(0,e,8):
            if i >> 5 == len(r):
                r.append(0)
            r[i >> 5] |= ctypes.c_int32((255 & ord(n[i // 8])) << i % 32).value
        return r

    def t(self, n, t):
        r = (65535 & n) + (65535 & t)
        a = ctypes.c_int32(n >> 16).value
        b = ctypes.c_int32(t >> 16).value
        c = ctypes.c_int32(r >> 16).value
        d = ctypes.c_int32(a + b + c << 16).value
        return d | 65535 & r

    def r(self, n, t):
        return ctypes.c_int32(n << t).value | (n >> 32 - t & 0xffffffff >> 32 - t)

    def e(self, n, e, o, u, c, f):
        return self.t(self.r(self.t(self.t(e, n), self.t(u, f)), c), o)

    def o(self, n, t, r, o, u, c, f):
        return self.e(t & r | ~t & o, n, t, u, c, f)

    def u(self, n, t, r, o, u, c, f):
        return self.e(t & o | r & ~o, n, t, u, c, f)

    def c(self, n, t, r, o, u, c, f):
        return self.e(t ^ r ^ o, n, t, u, c, f)

    def f(self, n, t, r, o, u, c, f):
        return self.e(r ^ (t | ~o), n, t, u, c, f)

    def i(self, n, r):
        x = 14 + (r + 64 >> 9 << 4) + 1
        n.extend([0 for _ in range(x - len(n))])
        n[-1] = r
        n[r >> 5] |= ctypes.c_int32(128 << r % 32).value
        l = 1732584193
        g = -271733879
        v = -1732584194
        m = 271733878
        for j in range(0,len(n),16):
            if j + 15 >= len(n):
                x = j + 15 - len(n) + 1
                for _ in range(x):
                    n.append(0)
            i = l
            a = g
            d = v
            h = m
            l = self.o(l, g, v, m, n[j], 7, -680876936)
            m = self.o(m, l, g, v, n[j + 1], 12, -389564586)
            v = self.o(v, m, l, g, n[j + 2], 17, 606105819)
            g = self.o(g, v, m, l, n[j + 3], 22, -1044525330)
            l = self.o(l, g, v, m, n[j + 4], 7, -176418897)
            m = self.o(m, l, g, v, n[j + 5], 12, 1200080426)
            v = self.o(v, m, l, g, n[j + 6], 17, -1473231341)
            g = self.o(g, v, m, l, n[j + 7], 22, -45705983)
            l = self.o(l, g, v, m, n[j + 8], 7, 1770035416)
            m = self.o(m, l, g, v, n[j + 9], 12, -1958414417)
            v = self.o(v, m, l, g, n[j + 10], 17, -42063)
            g = self.o(g, v, m, l, n[j + 11], 22, -1990404162)
            l = self.o(l, g, v, m, n[j + 12], 7, 1804603682)
            m = self.o(m, l, g, v, n[j + 13], 12, -40341101)
            v = self.o(v, m, l, g, n[j + 14], 17, -1502002290)
            g = self.o(g, v, m, l, n[j + 15], 22, 1236535329)
            l = self.u(l, g, v, m, n[j + 1], 5, -165796510)
            m = self.u(m, l, g, v, n[j + 6], 9, -1069501632)
            v = self.u(v, m, l, g, n[j + 11], 14, 643717713)
            g = self.u(g, v, m, l, n[j], 20, -373897302)
            l = self.u(l, g, v, m, n[j + 5], 5, -701558691)
            m = self.u(m, l, g, v, n[j + 10], 9, 38016083)
            v = self.u(v, m, l, g, n[j + 15], 14, -660478335)
            g = self.u(g, v, m, l, n[j + 4], 20, -405537848)
            l = self.u(l, g, v, m, n[j + 9], 5, 568446438)
            m = self.u(m, l, g, v, n[j + 14], 9, -1019803690)
            v = self.u(v, m, l, g, n[j + 3], 14, -187363961)
            g = self.u(g, v, m, l, n[j + 8], 20, 1163531501)
            l = self.u(l, g, v, m, n[j + 13], 5, -1444681467)
            m = self.u(m, l, g, v, n[j + 2], 9, -51403784)
            v = self.u(v, m, l, g, n[j + 7], 14, 1735328473)
            g = self.u(g, v, m, l, n[j + 12], 20, -1926607734)
            l = self.c(l, g, v, m, n[j + 5], 4, -378558)
            m = self.c(m, l, g, v, n[j + 8], 11, -2022574463)
            v = self.c(v, m, l, g, n[j + 11], 16, 1839030562)
            g = self.c(g, v, m, l, n[j + 14], 23, -35309556)
            l = self.c(l, g, v, m, n[j + 1], 4, -1530992060)
            m = self.c(m, l, g, v, n[j + 4], 11, 1272893353)
            v = self.c(v, m, l, g, n[j + 7], 16, -155497632)
            g = self.c(g, v, m, l, n[j + 10], 23, -1094730640)
            l = self.c(l, g, v, m, n[j + 13], 4, 681279174)
            m = self.c(m, l, g, v, n[j], 11, -358537222)
            v = self.c(v, m, l, g, n[j + 3], 16, -722521979)
            g = self.c(g, v, m, l, n[j + 6], 23, 76029189)
            l = self.c(l, g, v, m, n[j + 9], 4, -640364487)
            m = self.c(m, l, g, v, n[j + 12], 11, -421815835)
            v = self.c(v, m, l, g, n[j + 15], 16, 530742520)
            g = self.c(g, v, m, l, n[j + 2], 23, -995338651)
            l = self.f(l, g, v, m, n[j], 6, -198630844)
            m = self.f(m, l, g, v, n[j + 7], 10, 1126891415)
            v = self.f(v, m, l, g, n[j + 14], 15, -1416354905)
            g = self.f(g, v, m, l, n[j + 5], 21, -57434055)
            l = self.f(l, g, v, m, n[j + 12], 6, 1700485571)
            m = self.f(m, l, g, v, n[j + 3], 10, -1894986606)
            v = self.f(v, m, l, g, n[j + 10], 15, -1051523)
            g = self.f(g, v, m, l, n[j + 1], 21, -2054922799)
            l = self.f(l, g, v, m, n[j + 8], 6, 1873313359)
            m = self.f(m, l, g, v, n[j + 15], 10, -30611744)
            v = self.f(v, m, l, g, n[j + 6], 15, -1560198380)
            g = self.f(g, v, m, l, n[j + 13], 21, 1309151649)
            l = self.f(l, g, v, m, n[j + 4], 6, -145523070)
            m = self.f(m, l, g, v, n[j + 11], 10, -1120210379)
            v = self.f(v, m, l, g, n[j + 2], 15, 718787259)
            g = self.f(g, v, m, l, n[j + 9], 21, -343485551)
            l = self.t(l, i)
            g = self.t(g, a)
            v = self.t(v, d)
            m = self.t(m, h)
        return [l, g, v, m]

    def l(self, n, t):
        o = self.d(n)
        u = [0 for _ in range(16)]
        c = [0 for _ in range(16)]
        if len(o) > 16:
            o = self.i(o, 8 * len(n))
        for j in range(16):
            u[j] = 909522486 ^ o[j]
            c[j] = 1549556828 ^ o[j]
        u.extend(self.d(t))
        e = self.i(u, 512 + 8 * len(t))
        c.extend(e)
        r = self.a(self.i(c, 640))
        return r

    def s(self, n, t):
        return self.l(n, t)

    def g(self, n):
        d = list('0123456789abcdef')
        e = []
        for c in list(n):
            c = ord(c)
            e.append(d[c >> 4 & 15])
            e.append(d[15 & c])
            r = ''.join(e)
        return r

    def C(self, n, t):
        return self.g(self.s(n, t))

    def __call__(self, password, token):
        return self.C(token, password)
class BASE64:
    #js:atob() base64加密
    def __init__(self):
        self.base64Alpha = 'LVoJPiCN2R8G90yg+hmFHuacZ1OWMnrsSTXkYpUq/3dlbfKwv6xztjI7DeBE45QA'

    def encode(self, s):
        r = []
        x = len(s) % 3
        if x:
            s = s + '\0'*(3 - x)
        for i in range(0,len(s),3):
            d = s[i:i+3]
            a = ord(d[0]) << 16 | ord(d[1]) << 8 | ord(d[2])
            r.append(self.base64Alpha[a>>18])
            r.append(self.base64Alpha[a>>12 & 63])
            r.append(self.base64Alpha[a>>6 & 63])
            r.append(self.base64Alpha[a & 63])
        if x == 1:
            r[-1] = '='
            r[-2] = '='
        if x == 2:
            r[-1] = '='
        return ''.join(r)
def getTime():
    #取时间 等同于js里面的 Date.toValue()
    t = time.time()
    return int(round(t * 1000))
callback = 'jQuery{0}_{1}'.format(random.getrandbits(100), getTime())
def get_challenge():
    #登录认证第一步
    url = 'http://172.19.0.5/cgi-bin/get_challenge'
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30'
    }
    #callback = 'jQuery{0}_{1}'.format(random.getrandbits(100), getTime())
    params = {'callback':callback,
              'username':username,
              'ip':local_ip,
              '_':getTime()}
    r = requests.get(url, params=params, headers=headers)
    #print(r.url)
    print(r.text)
    data = r.text[len(callback)+1:-1]
    token = json.loads(data)['challenge']
    return token
def statusTest():
    #ping 百度来测试网络是否连通
    import subprocess
    ret = subprocess.run("ping baidu.com -n 1", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    s1 = str(ret.stdout, encoding='gbk')
    return True if "0% 丢失" in s1 else False
def encode_userinfo(userinfo, token):
    #对用户信息进行SRBX1
    userinfo = json.dumps(userinfo).replace(' ','')
    if len(userinfo) == 0:
        return ''
    sc = len(userinfo)
    if sc % 4:
        userinfo += '\0' * (4-(sc%4))
    sv = []
    for i in range(0, sc, 4):
        while i >> 2 >= len(sv):
            sv.append(0)
        sv[i >> 2] = ord(userinfo[i]) | ctypes.c_int32(ord(userinfo[i+1]) << 8).value | \
                     ctypes.c_int32(ord(userinfo[i+2]) << 16).value | ctypes.c_int32(ord(userinfo[i+3]) << 24).value
    sv.append(sc)
    v = sv[:]
    sc = len(token)
    sv = []
    for i in range(0, sc, 4):
        while i >> 2 >= len(sv):
            sv.append(0)
        sv[i >> 2] = ord(token[i]) | ctypes.c_int32(ord(token[i+1]) << 8).value | \
                     ctypes.c_int32(ord(token[i+2]) << 16).value | ctypes.c_int32(ord(token[i+3]) << 24).value
    k = sv[:]
    while len(k) < 4:
        k.append(0)
    n = len(v) - 1
    z = v[n]
    y = v[0]
    c = ctypes.c_int32(0x86014019 | 0x183639A0).value
    q = math.floor(6 + 52 / (n + 1))
    d = 0
    m = None
    e = None
    while q > 0:
        d = d + c & (0x8CE0D9BF | 0x731F2640)
        d = ctypes.c_int32(d).value
        e = (d >> 2 & 0xFFFFFFFF >> 2) & 3
        for p in range(n):
            y = v[p + 1]
            m = (z >> 5 & 0xFFFFFFFF >> 5) ^ ctypes.c_int32(y << 2).value
            m += (y >> 3 & 0xFFFFFFFF >> 3) ^ ctypes.c_int32(z << 4).value ^ (d ^ y)
            m += k[p & 3 ^ e] ^ z
            v[p] = ctypes.c_int32(v[p] + m & (0xEFB8D130 | 0x10472ECF)).value
            z = v[p]
        y = v[0]
        m = (z >> 5 & 0xFFFFFFFF >> 5) ^ ctypes.c_int32(y << 2).value
        m += (y >> 3 & 0xFFFFFFFF >> 3) ^ ctypes.c_int32(z << 4).value ^ (d ^ y)
        m += k[(p + 1) & 3 ^ e] ^ z
        v[n] =ctypes.c_int32(v[n] + m & (0xBB390742 | 0x44C6F8BD)).value
        z = v[n]
        q -= 1
    lv = v[:]
    ld = len(lv)
    lc = ctypes.c_int32(ld - 1 << 2).value
    for i in range(ld):
        lv[i] = ''.join([chr(lv[i] & 0xff), chr((lv[i] >> 8 & 0xFFFFFFFF >> 8) & 0xff),
                        chr((lv[i] >> 16 & 0xFFFFFFFF >> 16) & 0xff),
                        chr((lv[i] >> 24 & 0xFFFFFFFF >> 24) & 0xff)])
    l = ''.join(lv)
    base64 = BASE64()
    return r'{SRBX1}' + base64.encode(l)

def srun_portal(username,password):
    #登录认证第二部
    url = 'http://172.19.0.5/cgi-bin/srun_portal'
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47'
    }
    #callback = 'jQuery{0}_{1}'.format(random.getrandbits(100),getTime())
    md5 = MD5()
    token= get_challenge()
    hmd5 = md5(password, token)
    userinfo = {'username':username,
                'password':password,
                'ip':local_ip,
                'acid':'28',
                'enc_ver': 'srun_bx1'
                }
    info = encode_userinfo(userinfo, token)
    chkstr = token+username+token+hmd5+token+'28'+token+local_ip+token+'200'+token+'1'+token+info
    sha1 = hashlib.sha1()
    sha1.update(chkstr.encode())
    chksum = sha1.hexdigest()
    params = {'callback':callback,
              'action':'login',
              'username':username,
              'password':r'{MD5}' + hmd5,
              'os':'Windows10',
              'name':'Windows',
              'double_stack':0,
              'chksum':chksum,
              'info':info,
              'ac_id':28,
              'ip':local_ip,
              'n':200,
              'type':1,
              '_':getTime()}
    r = requests.get(url, params=params, headers=headers)
    print(r.text)
    if 'Login is successful' in r.text:
        print('登录认证成功!')
    elif 'ip_already_online' in r.text:
        print("您已在线!")
    elif statusTest()==True:
        print("您虽然不在线但是有网")
    else:
        print('登陆失败,请检查acid或者密码是否正确')
def main():
    if local_ip == '':
        print('本机IP获取失败,请检查网络连接')

    username=input("用户名")
    password=input("密码")
    print('登录用户名:{}'.format(username))
    print('本机ipv4地址:{}'.format(local_ip))
    srun_portal(username,password)

if __name__ == '__main__':
    temp=local_ip
    while True:
        main()
        time.sleep(3600)

3.1 编写配置文件

配置文件如下:
1.config

[mysql]
username=
password=

3.2.功能封装与定时

完成上面的步骤之后我们就可以开始对登陆代码进行封装了,然后定时一小时重新登陆一次即可。

四.题外话

在这里插入图片描述
校园网安全认证和提高信息技术水平有个毛关系?要么是为了限制设备数圈钱(说这的那的,网费和居民区一样贵服务还差),要么就是…
总之没见过这么对付的商业计划书。

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谁的BUG最难改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值