数据解码:挑战不常见爬虫逆向分析,揭开数据迷雾的面纱

17 篇文章 4 订阅
9 篇文章 2 订阅

​大家好,我是TheWeiJun,欢迎来到我的公众号。在这篇文章中,我们将探索如何使用Python通过文件上传来与对方服务器进行交互,并将文件转换为其他格式。我们将使用Python中的MultipartEncoder来编码参数,从而实现整个流程的逆向操作。无论是上传图片、音频还是文档,本文将为你揭示这个神奇的魔法过程,让你轻松驾驭文件处理的艺术。让我们一起进入这个充满奇迹和创造力的世界吧!

特别声明:本公众号文章只作为学术研究,不作为其他不法用途;如有侵权请联系作者删除。

 目录

一、前言介绍

二、网站分析

三、参数分析

四、参数还原

五、思路总结

趣味模块

Kim,一个热爱阅读小说的小伙子,沉迷于mobi格式的书籍中。然而,他面临一个问题 - 他找不到开源的包来将mobi转换为txt格式。绝望之际,他听说了一个神秘的逆向网站服务。他好奇而兴奋地决定一试身手。通过黑客般的技能,他将mobi文件投入逆向网站的深渊,瞬间,文件以txt的形式重新浮现!从此,Kim在无数的字母中探索着无尽的故事。他的阅读世界因为那个奇特而有趣的模块而变得更加多姿多彩。


一、前言介绍

在当今数字化的时代,文件格式转换成为了日常生活中不可或缺的一部分。从文档、图片到音频和视频,我们经常需要将它们在不同的格式之间进行转换。然而,有时我们会遇到一些特殊的格式,它们并不常见或缺乏对应的开源转换工具。这时,我们就需要动用一些独特的技术手段。

本文将带你进入一个神秘的逆向网站服务的世界,它以其独特的技术能力而闻名。我们将以一个喜欢阅读小说的年轻人Kim为主人公,他面临将mobi格式转换为txt的问题。无法找到开源的解决方案,Kim最终决定尝试逆向网站的服务。我们将探索他的奇妙冒险,见证他如何通过逆向技术改变了他的阅读体验。现在,让我们踏入这个充满创意和神秘的文件格式转换的世界吧!


二、网站分析

1、首先打开我们本次需要转换格式的网站,页面功能截图大致如下所示:

2、点击页面中的选择文件按钮,上传我们需要转换的文件,然后点击Target选择转换格式。并在Network中查看请求包,截图如下所示:

3、 查看Google浏览器页面中文件输出结果,截图如下所示:

4、 点击打开转换后的txt文件,看看转换结果是否准确,截图如下所示:

总结:文件是转换成功了,就是字体是乱码了(这个我们稍后一起解决)。接下来我们分析一下请求转换接口参数,来模拟下整个转换流程如何用代码去实现吧。


三、参数分析

  1.  点击Payload栏目,查看完整请求包Form Data,截图如下所示:

  • file:                二进制文件流

  • targetformat:  转换格式

  • code:            每个格式是固定的

  • filelocation:  local固定不变

  • legal:             固定的,网站警告

2.  直接开干,感觉没啥难度,也没啥加密值。复制整个请求到curl在线工具中,截图如下所示:

3. copy代码到pycharm中,直接请求发包后,输出截图如下所示:

总结:我们查看打印结果,发现输出结果报错了。很显然,我们需要对data体进行重新组包了,浏览器里curl出来的是无法通过对方服务器校验的。接下来,我们一起进入data请求体组包环节吧。


四、参数还原

1. 通过分析headers中的Content-Type参数值,我们可以看到数据类型为multipart/form-data,接下来编辑完整代码如下:

import requestsfrom requests_toolbelt import MultipartEncoderheaders = {    'Accept': '*/*',    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',    'Cache-Control': 'no-cache',    'Connection': 'keep-alive',    'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryCOUm5fNrq0VkgLsv',    'Origin': 'https://www.xxx.com',    'Pragma': 'no-cache',    'Referer': 'https://www.xxx.com/',    'Sec-Fetch-Dest': 'empty',    'Sec-Fetch-Mode': 'cors',    'Sec-Fetch-Site': 'same-site',    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',    'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"',    'sec-ch-ua-mobile': '?0',    'sec-ch-ua-platform': '"macOS"',}fields = {        "file": open('data/转换数据测试文件.mobi', "rb"),        "targetformat": "txt",        "code": "86000",        "oAuthToken": "",        "filelocation": "local",        "legal": "Our PHP programs can only be used in aconvert.com. We DO NOT allow using our PHP programs in any third-party websites, software or apps. We will report abuse to your cloud provider, Google Play and App store if illegal usage found!",    }url = f"https://s5.xxx.com/convert/convert9.php"m_data = MultipartEncoder(fields, boundary='----WebKitFormBoundaryqol36GPsnkBoFwtK')headers['Content-Type'] = m_data.content_typedata = m_data.to_string()response = requests.post('https://s5.xxxx.com/convert/convert9.php', headers=headers, data=data)print(response.text)

2. 代码编辑完毕后,运行代码,response出现对方服务警告,截图如下:

总结:我们不允许从任何第三方网站,软件或应用程序直接运行我们的PHP程序! 可以啊,居然还能识别到。我感觉这个网站没有这么严格,肯定是缺少一些关键性参数。

3. 经过认真分析后,观察初始data、payload中的Content-Type参数值,截图如下:

4. 将刚刚看到的Content-Type参数值类型加入到file字段中,完整代码如下:

import requestsfrom loguru import loggerfrom requests_toolbelt import MultipartEncoderdef covert_mobi(filename):    headers = {        'Accept': '*/*',        'Accept-Language': 'zh-CN,zh;q=0.9',        'Cache-Control': 'no-cache',        'Connection': 'keep-alive',        'Origin': 'https://www.xxx.com',        'Pragma': 'no-cache',        'Referer': 'https://www.xxx.com/',        'Sec-Fetch-Dest': 'empty',        'Sec-Fetch-Mode': 'cors',        'Sec-Fetch-Site': 'same-site',        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',        'sec-ch-ua': '"Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"',        'sec-ch-ua-mobile': '?0',        'sec-ch-ua-platform': '"macOS"',    }    fields = {        "file": (filename, open(filename, "rb"), "application/octet-stream"),        "targetformat": "txt",        "ocrlan": "0",        "oAuthToken": "",        "filelocation": "local",        "legal": "Our PHP programs can only be used in aconvert.com. We DO NOT allow using our PHP programs in any third-party websites, software or apps. We will report abuse to your cloud provider, Google Play and App store if illegal usage found!",    }    server_code = 30 if filename.endswith("pdf") else 5    url = f"https://s{server_code}.xxx.com/convert/convert9.php"    m_data = MultipartEncoder(fields, boundary='----WebKitFormBoundaryqol36GPsnkBoFwtK')    headers['Content-Type'] = m_data.content_type    data = m_data.to_string()    try:        resp = requests.post(url=url, headers=headers, data=data)        filename = resp.json().get("filename")        server = resp.json().get("server")        url = f"https://s{server}.xxxx.com/convert/p3r68-cdx67/{filename}"        logger.debug(url)        response = requests.get(url, headers=headers, proxies={})        response.encoding = 'utf-8'    except Exception as e:        print(e)    else:        return response.textif __name__ == '__main__':    data = covert_mobi("data/转换数据测试文件.mobi")    print(data)

5. 代码运行后,最后展示打印输出截图如下:

6. kim兄弟给我说,军哥能不能给爬虫提提速改成Go语言版本。经过研究后,附上Go语言版本代码如下:

package mainimport (  "bytes"  "encoding/json"  "fmt"  "io"  "mime/multipart"  "net/http"  "os")type ResItem struct {  Filename string `json:"filename"`  Ext      string `json:"ext"`  Server   string `json:"server"`  State    string `json:"state"`}func main() {  // 创建一个缓冲区来构建multipart请求体  item := convertMobi()  filename := item.Filename  server := item.Server  convert_url := fmt.Sprintf("https://s%s.xxx.com/convert/p3r68-cdx67/%s", server, filename)  content := download(convert_url)  fmt.Println(string(content))}func download(url string) []byte {  // 创建GET请求并设置请求头  req, err := http.NewRequest("GET", url, nil)  if err != nil {    fmt.Println(err)  }  req.Header.Set("Referer", "https://www.xxx.com/")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")  // 发送请求并获取响应  client := &http.Client{}  resp, err := client.Do(req)  if err != nil {    fmt.Println(err)  }  defer resp.Body.Close()  // 读取响应内容  respBody, err := io.ReadAll(resp.Body)  if err != nil {    fmt.Println(err)  }  return respBody}func convertMobi() ResItem {  body := &bytes.Buffer{}  writer := multipart.NewWriter(body)  // 添加文件字段  file, err := os.Open("/Users/xxxx/Desktop/转换数据测试文件.mobi")  if err != nil {    fmt.Println(err)  }  defer file.Close()  part, err := writer.CreateFormFile("file", "转换数据测试文件.mobi")  if err != nil {    fmt.Println(err)  }  io.Copy(part, file)  fmt.Println(writer.FormDataContentType())  // 添加其他字段  err = writer.WriteField("targetformat", "txt")  err = writer.WriteField("oAuthToken", "")  err = writer.WriteField("ocrlan", "0")  err = writer.WriteField("filelocation", "local")  err = writer.WriteField("legal", "Our PHP programs can only be used in aconvert.com. We DO NOT allow using our PHP programs in any third-party websites, software or apps. We will report abuse to your cloud provider, Google Play and App store if illegal usage found!")  // 结束写入请求体  err = writer.Close()  if err != nil {    fmt.Println(err)  }  // 创建POST请求并设置请求头  req, err := http.NewRequest("POST", "https://s5.xxx.com/convert/convert9.php", body)  if err != nil {    fmt.Println(err)  }  req.Header.Set("Content-Type", writer.FormDataContentType())  req.Header.Set("Referer", "https://www.xxx.com/")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")  // 发送请求并获取响应  client := &http.Client{}  resp, err := client.Do(req)  if err != nil {    fmt.Println(err)  }  defer resp.Body.Close()  // 读取响应内容  respBody, err := io.ReadAll(resp.Body)  if err != nil {    fmt.Println(err)  }  item := ResItem{}  err = json.Unmarshal(respBody, &item)  if err != nil {    fmt.Println(err)  }  return item}


五、思路总结

回顾整个分析流程,本次总结主要概括为以下几点:

  • 不常见爬虫如何分析参数组包

  • multipart/form-data类型初识

  • Python、Go语言版本代码实现

  • Content-Type参数类型判断

本篇分享到这里就结束了,欢迎大家关注下期,我们不见不散☀️☀️✌️

往期推荐

革新之路:重新设计Scrapy调度器,让爬虫速度翻倍

猿人学逆向比赛第四题-gRPC题解 | Go版本

DX滑块验证码别乱捅!一不小心就反爬了。

某安网别逆向,一不小心就......

微信自动聊天机器狗,配置chatGPT,比Siri还智能!

作者简介

我是TheWeiJun,有着执着的追求,信奉终身成长,不定义自己,热爱技术但不拘泥于技术,爱好分享,喜欢读书和乐于结交朋友,欢迎扫我微信与我交朋友💕

分享日常学习中关于爬虫及逆向分析的一些思路,文中若有错误的地方,欢迎大家多多交流指正💕

文章来源:逆向与爬虫的故事

原文链接:数据解码:挑战不常见爬虫逆向分析,揭开数据迷雾的面纱

微信搜公众号:逆向与爬虫的故事;给我一个关注!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逆向与爬虫的故事

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

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

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

打赏作者

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

抵扣说明:

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

余额充值