1.使用Fiddler进行抓包


使用Fiddle对夜神模拟器进行抓包的设置,详情参考 https://blog.csdn.net/agree_qy/article/details/82490940

设置完成后打开模拟器上的手游和Fiddler进行抓包,此次我们用登录功能作为例子:

注册好游戏账号点击“立即登录”

用Python完成某手游的登录验证_逆向分析

这时切换到fiddler,如图所示:

图中蓝色部分即为所抓到的登录包


用Python完成某手游的登录验证_发包_02


2.用python发送登录请求


代码如下:

# -*- coding:utf-8 -*-

import requests
import time
import tools
import json

pid = '1'
dev = '0d001e11875d004903dbabd464d31417'
sversion = '3.5.6'
scut = '1'
gid = '1006609'
mdev =''
version = '0.3.5'
refer = '1_1006609_10913_1022'
gwversion = '1.0.0'
android_id = '2f8d4d3f6c8a4914'
appkey = 'slDMjCNm0na18Jdxq79HgocQTf:GvF/W'

def login(uname, upwd):
    url = 'http://s-api.37.com.cn/sdk/login/'
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 5.1.1; OPPO R11 Plus Build/NMF26X)',
        'Host': 's-api.37.com.cn',
        'Connection': 'Keep-Alive',
        'Accept-Encoding': 'gzip'
        # 'Content - Length': '255'
    }

    t = time.time()
    sign_str = pid + gid + refer + dev + version + str(t) + appkey + uname + upwd
    sign = tools.md5(sign_str.encode('utf-8'))
    param = 'sign=' + sign \
            +'&pid=' + pid \
            +'&time=' + str(t) \
            +'&dev=' + dev \
            +'&sversion=' + sversion \
            +'&scut=' + scut \
            +'&gid=' + gid \
            +'&mdev=' + mdev \
            +'&upwd=' + upwd \
            +'&version=' + version \
            +'&refer=' + refer \
            +'&gwversion=' + gwversion \
            +'&uname=' + uname \
            +'&android_id=' + android_id
    response = requests.post(url=url, headers=headers, data=param)
    # print(param)
    print(response.text)
    ret_json = json.loads(response.text)
    if response.status_code == 200:
        if ret_json['msg'] == '成功':
            return True
    return False          #否定所有if

def get_token(uname, upwd):
    url = 'http://s-api.37.com.cn/sdk/login/'
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 5.1.1; OPPO R11 Plus Build/NMF26X)',
        'Host': 's-api.37.com.cn',
        'Connection': 'Keep-Alive',
        'Accept-Encoding': 'gzip'
        # 'Content - Length': '255'
    }

    t = time.time()
    sign_str = pid + gid + refer + dev + version + str(t) + appkey + uname + upwd
    sign = tools.md5(sign_str.encode('utf-8'))
    param = 'sign=' + sign \
            + '&pid=' + pid \
            + '&time=' + str(t) \
            + '&dev=' + dev \
            + '&sversion=' + sversion \
            + '&scut=' + scut \
            + '&gid=' + gid \
            + '&mdev=' + mdev \
            + '&upwd=' + upwd \
            + '&version=' + version \
            + '&refer=' + refer \
            + '&gwversion=' + gwversion \
            + '&uname=' + uname \
            + '&android_id=' + android_id
    response = requests.post(url=url, headers=headers, data=param)
    # print(param)
    # print(response.text)
    ret_json = json.loads(response.text)
    return (ret_json['data'])

if __name__ == '__main__':

    if login('jbzd3c757311','1262fa18') == True:
        print('login success')
        ''''''
    else:
        print('login error')
        exit(-1)

token_1 = get_token('jbzd3c757311','1262fa18')

工具类:
import hashlib

def md5(str):
    m = hashlib.md5()
    m.update(str)  # 传入需要加密的字符串进行MD5加密
    return m.hexdigest()  # 获取到经过MD5加密的字符串并返回

3.逆向分析

1.点击fiddler中的Raw分析内容:

用Python完成某手游的登录验证_python_03

图中sign的整行内容如下:

sign=a4f4eea04b7dcd619af26a5edf58af74&pid=1&time=1597315103&dev=0d001e11875d004903dbabd464d31417&sversion=3.5.6&scut=1&gid=1006609&mdev=&upwd=1262fa18&version=0.3.5&refer=1_1006609_10913_1022&gwversion=1.0.0&uname=jbzd3c757311&android_id=2f8d4d3f6c8a4914&

2.为方便查看,可以点击WebForms查看各对应值:

用Python完成某手游的登录验证_抓包_04

3.这个时候需要对游戏代码进行反编译,这里我们使用jadx工具进行反编译




说明:反编译出来代码可以用于代码分析,一般都是没法直接编译通过的。

经过加密的APP,反编译出来的代码肯定是混淆的。



(如何使用jadx详情参考:https://blog.csdn.net/weixin_38193813/article/details/87904209   /   https://www.jianshu.com/p/34295008ee1f

用Python完成某手游的登录验证_逆向分析_05

打开文件后:

用Python完成某手游的登录验证_抓包_06

因为我们抓到的包是login包,所以可以直接点击放大镜通过URL地址来搜索代码位置:

用Python完成某手游的登录验证_逆向分析_07


跳转后界面如下:

用Python完成某手游的登录验证_逆向分析_08


黄色部分就是我们要找的代码部分,右键点击字母c,选择查找用例:


用Python完成某手游的登录验证_发包_09

结果如下:

用Python完成某手游的登录验证_抓包_10

选择第一个跳转:

用Python完成某手游的登录验证_逆向分析_11


str str2 对应的是账号 密码;进入addCommonParams

用Python完成某手游的登录验证_逆向分析_12

进入之后 一目了然

用Python完成某手游的登录验证_发包_13

选中sendRequest,按住ctrl进入:


用Python完成某手游的登录验证_发包_14

在此页面下进行分析:

根据抓包工具fiddler中WebForms我们按顺序分析:

用Python完成某手游的登录验证_抓包_04


sign 的值是通过MD5进行加密过的,

用Python完成某手游的登录验证_发包_16

getPaternerID 是pid 

用Python完成某手游的登录验证_发包_17

getGameID 是gid

用Python完成某手游的登录验证_抓包_18

用Python完成某手游的登录验证_抓包_19

分析结果:sign= pid + gid + refer + dev + version + time + appkey + uname + upwd 

当然我们不需要每一个值都去分析,只需要分析变化的值。

(如何判断是否是变化的值,小技巧:用两个不同的账号密码抓取两个登录包进行对比!)


固定不变的值可以放在代码前:

用Python完成某手游的登录验证_发包_20


fiddler中服务器响应结果:

用Python完成某手游的登录验证_抓包_21

{"state":1,"msg":"成功","data":{"token":"BASE64ZmI5OTd5UVhuNHc1dEo3ZU5mYW1JWjlqZ1JBdDdCOCt0RkgweVRsYzZWeGxGc2RITExTNk5KR0wzbDdnOUJoQTIxeEpRek05OTdaaHVaV2dnam9RczdScUdmT2tuTmt1MVRBOFNEWEc5b216eDNmK1lienBnNHYrVzFBSHFEL3gxZEZWWDY5TlFSY3lkOUpoK0dCMkEzZHFnNGZKVCtQT0VvZGMxT0pBNmJUakJTSHVRZVBQamoySUJ5bnROTlJrQUtRVXZrbWFUNmZqZGxVcWUzTWJWdDVnSWJ3","uid":1755727187,"uname":"jbzd3c757311","login_account":"jbzd3c757311","disname":"jbzd3c757311","sex":0,"alias":"","nick":"jbzd3c757311","birth":"","bp":"","bm":"","phone":"","nurl":"","lurl":"","turl":"","auth":{"code":0,"url":"https://39ej7e.com/sdk/sdk-smrz/?authType=0\u0026code=0\u0026triggerType=login\u0026operation=1\u0026gid=1006609\u0026pid=1\u0026dev=0d001e11875d004903dbabd464d31417\u0026token=BASE64ZmI5OTd5UVhuNHc1dEo3ZU5mV3JKWlV4ZzBkNHUwNCt2Vm4wd3pzQXZ3aGpRTWRCZTdUaFo4TGEzbDdwOUI1QTIxMGFUVE0xb09VNDdjTDEwMndVNUxwcUdmT2tuTmt1MVRBOFNEWEc5b216eDNmK1lienBnNHYrVzFBSHFEL3gxZEZWWDY5TlFSY3lkOUpoK0dCMkEzZHFnNGZKVCtQT0VvZGMxT0pBNmJUakJTSHVRZVBQamoySUJ5bnROTlJrQUtRVXZrbWFUNmZqZGxVcWUzTWJWdDVnSWJ3\u0026sversion=3.5.6\u0026refer=1_1006609_10913_1022\u0026scut=1","durl":"https://39ej7e.com/sdk/sdk-smrz/?authType=0\u0026code=0\u0026triggerType=login\u0026operation=1\u0026gid=1006609\u0026pid=1\u0026dev=0d001e11875d004903dbabd464d31417\u0026token=BASE64ZmI5OTd5UVhuNHc1dEo3ZU5mQ2dKNWxsZ2tGM3ZoeHQ2VkgveWpwVjZWeHZRTUFSS2JTNU41T0QzbDYxOVJaQWcxcFBURE0xcGJOdTY4YW4xVGtYNHJScUdmT2tuTmt1MVRBOFNEWEc5b216eDNmK1lienBnNHYrVzFBSHFEL3gxZEZWWDY5TlFSY3lkOUpoK0dCMkEzZHFnNGZKVCtQT0VvZGMxT0pBNmJUakJTSHVRZVBQamoySUJ5bnROTlJrQUtRVXZrbWFUNmZqZGxVcWUzTWJWdDVnSWJ3\u0026sversion=3.5.6\u0026refer=1_1006609_10913_1022\u0026scut=1","type":0,"isAuth":1,"needAddiction":0,"needAccumulateDuration":0,"interval":1,"allowRecharge":1},"iosinfo":{"gcopen":0,"gclogintimes":0}}}


代码中也要用这种响应结果来判断我们是否登陆成功:

运行代码后显示:

用Python完成某手游的登录验证_python_22

我们已经通过python发包成功登录该游戏!