alexsuntop 发表于 2024-3-20 10:46

Proxifier强制代{过}{滤}理HTTP绕过身份检测

本帖最后由 alexsuntop 于 2024-3-20 10:51 编辑

题主非逆向专业,如有不足请多多海涵。这是题主第一次发帖,这里描述的内容可能过于抽象或不详细,如果有其他问题我将继续更新以供学习交流。

> 似乎所有代==理,都被加了 `{过}{滤}`,第一次用 52,额

最近发现一个付费软件使用 HTTP 验证是否购买,所以想绕过直接使用。考虑到软件方商业权益和本帖合法性,暂时不提供相关软件的任何信息,本帖只提供思路。

> 这里提醒一下,如果你没有已经购买过的样本来学习,那这一点还是很难实现的,还是老老实实脱壳破解吧。题主有幸得到一份已经购买过朋友的样本,所以学到了验证方法。

首先题主通过 Fiddler 拦截请求,实现了上述过程,把有效的返回替换了原有返回内容,成功实现了注册。然后在虚拟机中试验成功了。

软件使用了 HTTP 没用 HTTPS,直接访问 IP 地址的。现在的思路是使用 Proxifier 强制软件走代{过}{滤}理,然后自己编写一个 HTTP 服务作为代{过}{滤}理服务器。Proxifier 默认不允许 HTTP 代{过}{滤}理,需要手动开启一下。

![](https://attach.52pojie.cn//forum/202403/20/101025s0zsvspgnw6pieww.png?l)

本来想软件如果通过域名访问,直接修改 hosts 把域名重定向到本地就好了,发现只访问 IP 还挺麻烦,目前没想到能不使用 Proxifier 的方法,如有方法还请评论区建议。

题主主修人工智能,因此擅长 Python,通过 Python aiohttp 框架编写一个 HTTP 服务器,并代{过}{滤}理一个 IP 下的服务:

```python
import asyncio
import re
import socket
from datetime import datetime, timedelta
from multiprocessing import Queue

from aiohttp import ClientSession
from aiohttp.web import Application, Request, Response, RouteTableDef, run_app

from src.config import LOCK_VERSION, TARGET_HOST, TARGET_PORT, TEMPLATE

routes = RouteTableDef()


def is_port_available(host: str, port: int) -> bool:
    """检查端口是否可用"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    result = sock.connect_ex((host, port))
    sock.close()
    return result != 0


async def _make_proxy(request: Request) -> Response:
    """返回代{过}{滤}理数据"""
    async with ClientSession() as session:
      async with session.request(
            method=request.method,
            url=f"http://{TARGET_HOST}:{TARGET_PORT}{request.path}",
            headers=request.headers,
            params=request.query,
            data=await request.read() if request.can_read_body else None,
      ) as response:
            headers = {
                "Accept": response.headers.get("Accept", ""),
                "Host": response.headers.get("Host", ""),
                "Content-type": response.headers.get("Content-type", ""),
                "Set-Cookie": response.headers.get("Set-Cookie", ""),
                "Expires": response.headers.get("Expires", ""),
                "Referer": response.headers.get("Referer", ""),
                "Location": response.headers.get("Location", ""),
                "User-Agent": response.headers.get("User-Agent", ""),
                "Cookie": response.headers.get("Cookie", ""),
            }
            headers.pop("Transfer-Encoding", None)
            return Response(
                body=await response.read(),
                headers=headers,
                status=response.status,
            )
```

软件通过字符串匹配获取软件的余剩使用日期(不得不说太 low 了),直接注册到两年后。

这就是一个基本的 HTTP 代{过}{滤}理服务,下面是代{过}{滤}理 GET 请求:

```python
@routes.get("/{tail:.*}")
async def proxy_get(request: Request):
    """代{过}{滤}理所有 GET 请求"""
    queue: Queue = request.app["queue"]
    current_date = datetime.now().strftime("%Y-%m-%d")
    code = request.query.get("s_code", "")
    # 注册拦截器
    if "/reg.php":
      end_date = (datetime.now() + timedelta(days=730)).strftime("%Y-%m-%d")
      queue.put(f"获取到机器码:{code},正在注册到 {end_date}。")
      return Response(
            text=TEMPLATE.format(
                code=code,
                current_date=current_date,
                end_date=end_date,
            ),
            headers={
                "Content-type": "text/html; charset=UTF-8",
            },
      )

    is_locked = request.app.get("is_locked", False)
    # 检查是否锁版本
    if "/update.php" in request.path and is_locked:
      queue.put(f"检测到版本请求,已锁定版本")
      return Response(
            text=LOCK_VERSION.format(
                current_date=current_date,
            ),
            headers={
                "Content-type": "text/html; charset=UTF-8",
            },
      )
    return await _make_proxy(request)
```

解释一下:

- `queue`:进程队列
- `LOCK_VERSION`:是否锁定版本,如果有需求可以自己设计
- `TARGET_HOST`:目标主机 IP
- `TARGET_PORT`:代{过}{滤}理目标端口
- `TEMPLATE`:返回的模板代码,自己根据需要写

锁定版本是防止软件强制更新,我已经抓到以前的响应模板,这样如果需要锁定版本可以直接发送之前的更新请求的响应。

这里进程队列用于和其他进程通信,这里我使用 Python 标准库 TK 来设计 UI。可以通过 UI 查看日志信息。

下面是运行服务的代码:

```python
@routes.post("/{tail:.*}")
async def proxy_post(request: Request):
    """代{过}{滤}理所有 POST 请求"""
    return await _make_proxy(request)


def run_simple_server(queue: Queue, host: str, port: int):
    """运行服务器"""
    app = Application()
    app["queue"] = queue
    app.add_routes(routes)
    if not is_port_available(host, port):
      queue.put(f"端口 {port} 被占用!请勿重复打开程序,现在请关闭全部程序后重试。")
      return
    try:
      queue.put(f"注册机启动成功!")
      queue.put({"msg": "ready"})
      run_app(app, host=host, port=port)
    except RuntimeError:
      pass


if __name__ == "__main__":
    run_simple_server(Queue(), "127.0.0.1", 8899)
```

我这里还使用多进程以便能通过进程通信:

```python
import multiprocessing as mp

from src.server import run_simple_server
from src.ui import simple_tkinker_ui

HOST = "127.0.0.1"
PORT = 8899

if __name__ == "__main__":
    mp.freeze_support()
    queue = mp.Queue()

    p1 = mp.Process(target=run_simple_server, args=(queue, HOST, PORT))
    p1.start()

    p2 = mp.Process(target=simple_tkinker_ui, args=(queue, HOST, PORT))
    p2.start()
```

如果你觉得你不需要 UI,可以删除对应部分运行,直接打印日志。

UI 的代码太长,没有放出来。其实也无关紧要,以上代码用来学习测试即可。

这里使用 Nuitka 打包代码:

```bat
@echo off
python -m nuitka --standalone --onefile ^
    --mingw64 --show-progress --disable-console ^
    --plugin-enable=tk-inter --output-dir=dist ^
    --assume-yes-for-downloads main.py
```

这样每次使用软件之前启动一下脚本和 Proxifier,软件就以为自己已经注册过了。

不知道有没有更简单的,在 Windows 上实现 HTTP 拦截的方法。因为请求是 IP 地址没有加密,理论上可以在网关上拦截然后不再需要注册机和 Proxifier,但是有点复杂,Linux 似乎有工具直接支持拦截 HTTP 包。

先写到这,如果有不详细的地址再更新。

ghostwindows 发表于 2024-3-20 18:55

fidller有一个插件可以直接重定向到本地文件,叫stave

moonlune 发表于 2024-3-20 21:52

此类似类方法很久以前用过,但是当时使用的是Proxomitron。原理是,某个软件每次启动都会http联网发送一个验证,如果是符合的验证码,那么会返回某段注册成功信息。然后只要把返回的某段信息无论是什么,都给修改为返回注册成功信息,就可以了。

wfghim 发表于 2024-3-21 10:11

pc端,有个收费软件,是验证mac地址的,每个mac地址可以试用3天,每次打开软件,都用mac地址请求服务器,服务器返回可以试用的天数,我用Fiddler Script 篡改了响应的报文,达成了白嫖

pentest686 发表于 2024-3-20 23:49

cyhcuichao 发表于 2024-3-20 23:40
APP有代{过}{滤}理检测 只要打开就不能截包有什么办法吗

1、使用基于VPN模式的Postern
vproxid、rproxid、
https://github.com/postern-overwal/postern-stuff
2、使用基于iptables的ProxyDroid
https://github.com/cxf-boluo/magisk_All/blob/main/apks/org.proxydroid.apk

夏驰 发表于 2024-3-20 13:10

感谢分享,但是新手还是不会操作{:1_923:}

lambchasr 发表于 2024-3-20 13:15

mark,收藏备用{:1_921:}

听说哥 发表于 2024-3-20 13:23

虽然不知道怎么用,感谢分享

pentest686 发表于 2024-3-20 13:24

mitmproxy应该可以,mitm监听80端口,再通过host将域名定位到本机。只启动mitmproxy就可以,不是开发,不擅长编程,仅提供思路

juqkai 发表于 2024-3-20 13:42

如果是你自己用,感觉可以去路由器里面找找,看有没有拦截转发的功能,

risingsun 发表于 2024-3-20 13:52

pentest686 发表于 2024-3-20 13:24
mitmproxy应该可以,mitm监听80端口,再通过host将域名定位到本机。只启动mitmproxy就可以,不是开发,不擅 ...

我使用mitmproxy,安装了证书,但是https的包还是都抓不到,不知道为啥。

dd1ka 发表于 2024-3-20 14:03

很好的思路,值得学习,感谢大佬分享

n1ghtc4t 发表于 2024-3-20 14:22

思路很好 值得学习 点赞

pjy612 发表于 2024-3-20 15:27

以前易语言里面有个 网络拦截组件 还挺强的。
页: [1] 2 3 4
查看完整版本: Proxifier强制代{过}{滤}理HTTP绕过身份检测