Python 自动化加固流程
来源:互联网 发布:软件专业有哪些课程 编辑:程序博客网 时间:2024/05/16 03:45
这里的加固指的是那种需要把文件上传到第三方网站上, 等它加固完成之后再下载下来的场景.这里就以梆梆加固为例, 通过Python脚本将这个过程自动化起来.既然牵扯到第三方的网站, 那么这个脚本绝大多数的操作都跟网络请求相关. 简单设计一下脚本的结构, 先封一个基类出来对外提供一些基础的网络操作, 方面以后扩展使用.子类根据实际的业务场景对外提供功能方法.
根据梆梆加固的业务流程来拆解脚本需要做的步骤.大致可以分为五步, 分别是登录, 上传文件开始加固, 检测加固状态, 下载已加固文件, 删除应用.下面就详细介绍每个步骤如果分析如何实现.
登陆梆梆
使用梆梆加固肯定是需要登陆的, 所以要自动化这个流程首当其冲得就是要模拟登陆, 拿到cookie之后存储起来, 这样之后请求接口的时候带着有登陆信息的cookie就不会被拦截登录了. 在使用urllib2默认的opener是不支持cookie相关操作的, 所以在父类的初始化方法中初始化cookie库, 构建出支持cookie自定义的opener, 并将其装载为全局的opener.
cookie_jar = cookielib.LWPCookieJar()self.__cookie_support = urllib2.HTTPCookieProcessor(cookie_jar)opener = urllib2.build_opener( self.__cookie_support, urllib2.HTTPHandler)urllib2.install_opener(opener)
接下来分析一下梆梆的登录流程, 使用chrome抓取登录接口.从图中可以看到登录接口的url以及post数据的格式. 这里的账号和密码是明文的, randomID经过测试可以设置一个固定的值.
知道了需要什么数据直接就可以实现子类中的登录方法了.首先将账号密码和其他固定的参数先构建出来, 再调用父类封装好的post方法并接受response的返回信息, 并打印出来.如果返回数据中有”code”:0则代表登录成功.
def login(self, user_name, user_password): print 'prepare to login bangbang website...' login_params = {'account': user_name, 'password': user_password, 'randomID': '0.6358602885605047', 'randomCode': '', 'rememberChecked': 'false', } result = self.post(self.__login_url, login_params, self.__header) print result if "\"code\":0" in result: self.__logined = True print 'login succeed!' else: print 'login failed!'
根据打印的结果来看是登录成功的. 返回的数据中除了code代表请求状态之外, 其他的数据这里都用不到. 由于父类已经初始化了cookielib, 此时用户的cookie信息已经存储起来了.
{ "code":0, "enumlastupdate":0, "modelId":0, "msg":"https://dev.bangcle.com/Apps/index"}login succeed!
上传文件开始加固
登录成功之后就要上传apk文件让梆梆对其加固. 先在web端走一下流程, 发现可以分为两步, 第一步先上传文件然后跳转到一个确认加固页面, 第二步点击确认加固.通过抓包可以看到文件上传的接口请求.
上传文件
经过测试, 该接口的返回数据如下.这个msg字段的数据很可疑, 我们继续往下看.
{ "code":0, "modelId":0, "msg":"583142"}
upload接口请求完成之后紧跟着又请求了一个addapk的接口, 请求参数中多了一个appId的字段, 而这个值跟post接口返回的msg是一模一样的, 看来这个msg就是appId.这个值要存起来, 后续还会用到.最后这个接口的数据返回是重定向的确认加固页面.
开始加固
接下来在确认加固页面点击加固按钮之后又抓到了一个接口请求.从这个接口的参数中可以看到又多了一个不确定的参数, 是一个token. 找了一下也没有请求其他的接口了, 最后在addapk的返回数据(确定加固页面的源码)中找到了这个token字段. 既然找到了token在哪就好处理了, 直接用正则把它的值摘出来就可以了.
$.ajax( { data : { authenticityToken:'e085497b0562a74216f57b51544eb3646a4ba981' }, type : "post", url : '/home/hideheadertip', success : function(data) { }});
接口请求成功后返回如下数据, 梆梆后台开始对apk进行加固.这个时候web端应用列表中可以看到刚才上传的应用.
{ "code":0, "modelId":0, "msg":"添加成功!"}
抓包分析完了流程之后就可以开始用脚本实现了.这个阶段比登录要复杂不少, 牵扯到了三个接口的调用, 并且接口之间的数据还都是互相依赖的.
上传文件
父类中的上传文件接口是通过poster实现的, 首先通过poster注册一个opener, 并将之前的cookie相关信息添加进该opener中.
opener = poster.streaminghttp.register_openers()opener.add_handler(self.__cookie_support)
再使用poster的编码方法将dir参数数据编码出包含Content-Length和Content-Type的头信息以及包含文件流的数据参数, 并发出请求.
post_data, post_header = multipart_encode(upload_data)print post_headerrequest = urllib2.Request(upload_url, post_data, post_header)return urllib2.urlopen(request).read()
回到子类的业务流程. 首先判断一下当前是否是登录状态, 然后构建文件上传的参数, 请求上传接口, 根据返回值判断接口成功状态.
if self.__logined is False: print 'should be logined!' returnupload_params = {'name': file_name, 'file': open(file_name, "rb")}result = self.upload(self.__upload_url, upload_params)print resultjson_result = json.loads(result)if 0 != json_result['code']: print 'upload apk failed!' returnprint 'upload apk succeed!'
讲上传接口返回的appId保存起来请求addapk接口, 并且从请求结果中将token信息摘出来保存起来.
self.__app_id = json_result['msg']add_params = {}add_params['appId'] = self.__app_idresult = self.get(self.__add_app_url, add_params)self.__auth_token = re.findall(r"authenticityToken:'(.+?)'", result)[0]
开始加固
在第一步中已经拿到了appId和token, 将它们和默认参数拼接起来调用complete接口完成文件的上传并且开始加固.
complete_params = {'appId': self.__app_id, 'authenticityToken': self.__auth_token, 'appCategoryId': '', 'isCeping': 'true', 'isReinforce': 'true' }result = self.post(self.__complete_app_url, complete_params, self.__header)
检测加固状态
在web端开始加固之后会自动跳转到应用列表页面, 这时会请求getappinfos接口获取当前app的信息. 请求参数没什么特别的, 只要登录了这些参数都可以固定起来.
而返回数据中就有很多字段了, 看下图中黑色框起来的字段, 先通过appId找到我们刚才上传的app, 然后根据自己的理解reinforceStatus这个字段代表了加固状态, 8代表的是安检中.
过一会等加固完成了之后再刷新一下web页, 重新找到app信息. 这次可以看到状态变成10代表加固完成.
既然有字段可以判断加固的状态, 那就可以通过脚本轮询这个接口直到加固完成. 根据以下流程图完成这部分逻辑并记录加固状态.
首先做一些初始化工作:判断是否登录, 是否上传成功, 构建默认请求参数. 建立一个60次的循环.
check_params = { 'pageSize': '8', 'page': '1', 'param': ''}check_count = 0while check_count <= 60: check_count += 1
在循环中请求getappinfos接口. 反序列化返回数据到对象中, 并根据code状态决定是否跳过这次循环进入下一次循环中.
result = self.get(self.__check_status_url, check_params)json_result = json.loads(result)if 0 != json_result['code']: print 'check app reinforce status failed!' continue
遍历json对象中的results数组, 这里的每一个item就代表一个应用. 从item中的id字段也就是前面的appId信息过滤出我们正在操作的应用. 再根据上面对字段的分析, 判断reinforceStatus是否完成加固. 如果加固还没有完成则休眠10s继续轮询.
for result_item in json_result['results']: if str(result_item['id']) != self.__app_id: continue if result_item['reinforceStatusCode'] == '10': print 'reinforce app reinforce succeed!' self.__reinforced = True returnif self.__reinforced is False: print 'sleeping 10s...' time.sleep(10)
下载加固后文件
在web端等加固完成之后就可以下载加固过的apk包. 这里抓到了两个接口调用. 第一个是请求参数w为appId的downapkcode接口, 返回数据中有很多字段, 先不管看第二个接口.
{ "code":0, "info":{ "code":"d7076e3810ad628875af97b58b6fc9953f95122e", "model_id":583145, "sid":"355d0d0f167b4ffbaf8fa8be27de4fa724238509", "user_id":620615 }, "modelId":0, "msg":""}
第二个调用的就是下载文件的接口downloadfile, 该接口的参数除了id是appId, type固定之外都是通过第一个接口返回值确定的.
套路都了解了之后就先判断当前是否是登录状态, 是否加固完成. 然后根据appId请求接口解析结果, 判断状态之后获得sid, user_id和code字段值.
download_code_params = { 'appId': self.__app_id, 'hideDownloadNotice': 'false'}result = self.post(self.__download_code_url, download_code_params, self.__header)print resultjson_result = json.loads(result)
集齐参数之后就可以调用父类的download方法, 将文件下载到指定的路径下.
download_params = { 'id': self.__app_id, 'sid': json_result['info']['sid'], 'user_id': json_result['info']['user_id'], 'code': json_result['info']['code'], 'type': '1'}self.download(self.__download_apk_url, download_params, downlaod_path)
删除应用
为什么走完上面的流程之后要把应用从梆梆应用列表中删除呢? 因为根据目前梆梆的业务流程, 相同版本的同一个应用只能加固一次.如果要把加固脚本持续集成起来可能每天都要加固一次.所以我们要每次加固完成之后就把应用删除掉, 方便下次加固使用.
删除应用同样抓包, 定位到参数为appId和token的接口delById. 这些参数信息我们都有保存, 直接拿来调用就行了.
同样先判断是否登录是否上传成功, 然后拼装参数执行post, 最后根据返回结果输出最终状态就完成整个脚本的最后一步.
delete_params = { 'authenticityToken': self.__auth_token, 'appId': self.__app_id}result = self.post(self.__delete_app_url, delete_params, self.__header)
汇总
BangBangHttp
类实现了之后在外部就可以通过对象方便得使用加固的功能.也可以将账号, 密码, 输入和输出这四个属性作为外部参数传递进来, 丰富使用场景.
bang_bang = BangBangHttp()bang_bang.login('account', 'pwd')bang_bang.upload_apk('test.apk')bang_bang.check_reinforce_status()bang_bang.download_apk('reinforced.apk')bang_bang.delete_app()
转载请注明出处:http://blog.csdn.net/l2show/article/details/55803455
- Python 自动化加固流程
- Android项目自动化--apk的打包、加固及其发布
- 软件自动化测试流程
- QTP自动化测试流程
- QTP自动化测试流程
- 软件自动化测试流程
- QTP-自动化测试流程
- 前端自动化流程
- 功能自动化测试流程
- 前端流程自动化
- 自动化测试基本流程
- 流程自动化布局
- 流程自动化布局
- Grunt 自动化安装流程
- 流程自动化布局
- 自动化部署流程设计
- appium自动化测试流程
- 前端开发流程自动化
- jsp内置对象request
- Js~对数组的操作
- 36辆车,6条跑道,无计时器,最少几次比赛可以选出前三
- Linux中的进程描述符
- 5.Java常用API 1
- Python 自动化加固流程
- JSP/FTL 中获取param、request、session、application中的值
- The launch image set named LaunchImage did not have any applicable content
- synchronized 修饰在 static方法和非static方法的区别
- JAVA学习笔记
- 历届试题 埃及分数(穷举)
- virtualenv
- 语言的战争
- 放苹果