们将在这个小小的城镇中相互扶持,共同生活下去
今宵之月,绝不西沉。只此美梦,不再苏醒。从今往后,生生世世,长相厮守,为你立誓。
我们不能让这次冒险之旅没有意义没有收获
我们的本质就是血,一层层地重复,然后世代脉脉相传的血才是黑血的真实
当你知道自己被爱著的时候就不会自卑了asd
不要哭,我还没有努力到要哭的程度,不甘心就可以了das
既不回头,何必不忘;既然无缘,何必誓言;今日种种,似水无痕
空谈之类,是谈不久,也谈不出什么来的,它终必被事实的镜子照出原形,拖出尾巴而去
只愿涤荡四方,护得一世之隅。
你看你浪费了多少流星,哈哈……不牵个手也很浪费这样的夜晚呢
有形的东西迟早会凋零,但只有回忆是永远不会凋零的
已经无法回来的东西,得到和舍弃都很痛苦
Pain past is pleasure.11222
我因为后来离开村子,在远处看见这一村庄人的火焰。看见他们比熄灭还要寂静的那一场燃烧。我像一根逃出火堆的干柴,幸运而孤独地站在远处。
河川,激流逆流顺流回流,犹如人生前后进退往复不息
首页
统计
免费Chat GPT
关于
更多
友链
每日新闻
视频
高清壁纸
Search
1
2023彩虹易支付最新原版开源网站源码,完整的易支付源码,无后门
465 阅读
2
ThinkPHP6的常见问题解答
387 阅读
3
Spring Boot之七牛云分片上传
241 阅读
4
小狐狸ChatGPT付费创作系统V2.4.9独立版 +WEB端+ H5端 + 小程序端(支持分享朋友圈、破解弹窗)
230 阅读
5
国内最好用的六款虚拟机软件
211 阅读
技术分享
源码分享
课程分享
号卡套餐
移动专区
电信专区
联通专区
广电专区
软件仓库
电脑软件
安卓软件
活动线报
值得一看
Search
标签搜索
技术分享
源码
源码分享
css
安卓软件
活动线报
软件
课程分享
号卡
电脑软件
PHP
值得一看
HTML
js
教程
chatgpt
AI
小程序
ThinkPHP
联通
老K博客
累计撰写
420
篇文章
累计收到
338
条评论
今日撰写
0
篇文章
首页
栏目
技术分享
源码分享
课程分享
号卡套餐
移动专区
电信专区
联通专区
广电专区
软件仓库
电脑软件
安卓软件
活动线报
值得一看
页面
统计
免费Chat GPT
关于
友链
每日新闻
视频
高清壁纸
用户登录
登录
搜索到
6
篇与
的结果
2024-11-06
python批量图片转webp格式
主要流程就是将非webp的图片转换后丢到指定目录,已经是webp的就直接丢过去。有三个参数, input_folder , output_folder , qualityinput_folder你要转换的图片文件夹output_folder转换后输出的路径quality图片压缩质量,默认80,一般也不用改。要注意的是,权限要给够,不然可能复制失败。下面是代码import os from PIL import Image def convert_images_to_webp(input_folder, output_folder, quality=80): """ Convert all non-WebP images in the input_folder to WebP format and save them to output_folder. Existing WebP images are skipped. Args: - input_folder (str): The folder containing images to convert. - output_folder (str): The folder where converted WebP images will be saved. - quality (int): The quality of the converted WebP images, default is 80. """ # Check if output folder exists, if not, create it if not os.path.exists(output_folder): os.makedirs(output_folder) # Iterate over all files in the input folder for filename in os.listdir(input_folder): if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif')): # Construct the full file path file_path = os.path.join(input_folder, filename) # Open the image image = Image.open(file_path) # Convert and save the image in WebP format webp_filename = os.path.splitext(filename)[0] + '.webp' webp_path = os.path.join(output_folder, webp_filename) image.save(webp_path, 'webp', quality=quality) print(f"Saved {filename}") elif filename.lower().endswith('.webp'): webp_path = os.path.join(output_folder, filename) with open(file_path, 'rb') as file: with open(webp_path, 'wb') as output_file: output_file.write(file.read()) print(f"Skipping existing WebP file: {filename}") print(f"All non-WebP images from {input_folder} have been converted and saved to {output_folder}") if __name__ == '__main__': convert_images_to_webp('photos', 'photos/webp2') 效果
2024年11月06日
13 阅读
0 评论
0 点赞
2024-07-11
python并发执行request请求
在Python中,我们可以使用requests库来发送HTTP请求,并使用threading、multiprocessing、asyncio(配合aiohttp)或 concurrent.futures 等库来并发执行这些请求。这里,我将为我们展示使用 concurrent.futures.ThreadPoolExecutor 和requests库并发执行HTTP请求的示例。使用concurrent.futures.ThreadPoolExecutor并发发送请求示例首先,我们需要安装requests库(如果还没有安装的话):bash pip install requests然后,我们可以使用以下代码来并发地发送HTTP GET请求:import concurrent.futures import requests # 假设我们有一个URL列表 urls = [ 'http://example.com/api/data1', 'http://example.com/api/data2', 'http://example.com/api/data3', # ... 添加更多URL ] # 定义一个函数,该函数接收一个URL,发送GET请求,并打印响应内容 def fetch_data(url): try: response = requests.get(url) response.raise_for_status() # 如果请求失败(例如,4xx、5xx),则抛出HTTPError异常 print(f"URL: {url}, Status Code: {response.status_code}, Content: {response.text[:100]}...") except requests.RequestException as e: print(f"Error fetching {url}: {e}") # 使用ThreadPoolExecutor并发地执行fetch_data函数 with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # 你可以根据需要调整max_workers的值 future_to_url = {executor.submit(fetch_data, url): url for url in urls} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: # 通过调用future.result()来获取函数的返回值,这会阻塞,直到结果可用 # 但是请注意,这里我们只是打印结果,没有返回值,所以调用future.result()只是为了等待函数完成 future.result() except Exception as exc: print(f'Generated an exception for {url}: {exc}') 在这里简单解释一下这个代码示例。(1)我们首先定义了一个URL列表,这些是我们想要并发访问的URL。(2)然后,我们定义了一个函数 fetch_data ,它接收一个URL作为参数,发送GET请求,并打印响应的状态码和内容(只打印前100个字符以节省空间)。如果发生任何请求异常(例如,网络错误、无效的URL、服务器错误等),它会捕获这些异常并打印错误消息。(3)使用 concurrent.futures.ThreadPoolExecutor ,我们可以轻松地并发执行fetch_data函数。我们创建了一个ThreadPoolExecutor实例,并指定了最大工作线程数(在这个例子中是5,但我们可以根据需要调整这个值)。然后,我们使用列表推导式将每个URL与一个Future对象关联起来,该对象表示异步执行的函数。(4)最后,我们使用as_completed函数迭代所有完成的Future对象。对于每个完成的Future对象,我们调用result方法来获取函数的返回值(尽管在这个例子中我们没有使用返回值)。如果函数执行期间发生任何异常,result方法会重新引发该异常,我们可以捕获并处理它。这个示例展示了如何使用Python的 concurrent.futures 模块来并发地发送HTTP请求。这种方法在IO密集型任务(如网络请求)上特别有效,因为它允许在等待IO操作完成时释放CPU资源供其他线程使用。requests库并发发送HTTP GET请求的完整Python代码示例以下是一个使用 concurrent.futures.ThreadPoolExecutor 和requests库并发发送HTTP GET请求的完整Python代码示例:import concurrent.futures import requests # 假设我们有一个URL列表 urls = [ 'https://www.example.com', 'https://httpbin.org/get', 'https://api.example.com/some/endpoint', # ... 添加更多URL ] # 定义一个函数来发送GET请求并处理响应 def fetch_url(url): try: response = requests.get(url, timeout=5) # 设置超时为5秒 response.raise_for_status() # 如果请求失败,抛出HTTPError异常 return response.text # 返回响应内容,这里只是作为示例,实际使用中可能不需要返回 except requests.RequestException as e: print(f"Error fetching {url}: {e}") return None # 使用ThreadPoolExecutor并发地发送请求 def fetch_all_urls(urls): with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # 使用executor.map来自动处理迭代和Future的获取 results = executor.map(fetch_url, urls) # 处理结果(这里只是简单地打印出来) for result in results: if result is not None: print(f"Fetched content from a URL (truncated): {result[:100]}...") # 调用函数 fetch_all_urls(urls) 在这个示例中,我们定义了一个fetch_url函数,它接收一个URL,发送GET请求,并返回响应内容(或在出错时返回None)。然后,我们定义了一个fetch_all_urls函数,它使用ThreadPoolExecutor并发地调用fetch_url函数,并将结果收集在一个迭代器中。最后,我们遍历这个迭代器,并打印出每个成功获取到的响应内容(这里只打印了前100个字符作为示例)。请注意,我们在 requests.get 中设置了一个超时参数(timeout=5),这是为了防止某个请求因为网络问题或其他原因而无限期地等待。在实际应用中,根据我们的需求调整这个值是很重要的。此外,我们还使用了 executor.map 来自动处理迭代和Future的获取。 executor.map 函数会返回一个迭代器,它会产生fetch_url函数的返回值,这些值在函数完成后会自动从相应的Future对象中提取出来。这使得代码更加简洁,并且减少了显式处理Future对象的需要。如何在Python中实现并发编程在Python中实现并发编程,主要有以下几种方式:(1)使用threading模块threading模块提供了多线程编程的API。Python的线程是全局解释器锁(GIL)下的线程,这意味着在任意时刻只有一个线程能够执行Python字节码。然而,对于I/O密集型任务(如网络请求),多线程仍然可以通过并发地等待I/O操作来提高性能。示例:import threading import requests def fetch_url(url): try: response = requests.get(url) response.raise_for_status() print(f"URL: {url}, Status Code: {response.status_code}") except requests.RequestException as e: print(f"Error fetching {url}: {e}") threads = [] for url in urls: t = threading.Thread(target=fetch_url, args=(url,)) threads.append(t) t.start() # 等待所有线程完成 for t in threads: t.join()(2)使用multiprocessing模块multiprocessing模块提供了跨多个Python解释器的进程间并行处理。这对于CPU密集型任务特别有用,因为每个进程都有自己的Python解释器和GIL,可以充分利用多核CPU的并行处理能力。示例:from multiprocessing import Pool import requests def fetch_url(url): try: response = requests.get(url) response.raise_for_status() return f"URL: {url}, Status Code: {response.status_code}" except requests.RequestException as e: return f"Error fetching {url}: {e}" with Pool(processes=4) as pool: # 设定进程池的大小 results = pool.map(fetch_url, urls) for result in results: print(result) (3)使用asyncio模块(针对异步I/O)asyncio是Python 3.4+中引入的用于编写单线程并发代码的库,特别适合编写网络客户端和服务器。它使用协程(coroutine)和事件循环(event loop)来管理并发。示例(使用aiohttp库进行异步HTTP请求):import asyncio import aiohttp async def fetch_url(url, session): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: tasks = [] for url in urls: task = asyncio.create_task(fetch_url(url, session)) tasks.append(task) results = await asyncio.gather(*tasks) for result, url in zip(results, urls): print(f"URL: {url}, Content: {result[:100]}...") # Python 3.7+ 可以使用下面的方式运行主协程 asyncio.run(main()) 注意: asyncio.run() 是在Python 3.7中引入的,用于运行顶层入口点函数。在Python 3.6及以下版本中,我们需要自己设置和运行事件循环。(4)使用concurrent.futures模块 concurrent.futures 模块提供了高层次的接口,可以轻松地编写并发代码。它提供了ThreadPoolExecutor(用于线程池)和ProcessPoolExecutor(用于进程池)。前面已经给出了ThreadPoolExecutor的示例,这里不再重复。ProcessPoolExecutor的用法与ThreadPoolExecutor类似,只是它是基于进程的。
2024年07月11日
12 阅读
0 评论
0 点赞
2024-05-10
18 岁少年如何发现虚拟机逃逸漏洞
背景介绍今天分享国外一位18岁白帽小哥如何在 VirtualBox 中发现一个相当古老(2019 年)的漏洞,该漏洞允许虚拟机到宿主机的逃逸,漏洞编号为CVE-2019-2703。本文将带你了解这位白帽小哥的思想链,从头到尾展示整个思考过程,最终引导他发现该漏洞。注意:本文中使用的 VirtualBox 版本为 6.0.4研究灵感首先这白帽小哥从 @_niklasb 和他的 VirtualBox 研究中收获了不少灵感。https://www.exploit-db.com/exploits/43878https://www.youtube.com/watch?v=fFaWE3jt7qU&t=460s&ab_channel=scrt.insomnihackhttps://phoenhex.re/2018-07-27/better-slow-than-sorry首先尝试找出哪些子系统可以通过虚拟机控制的输入来访问,最初的研究线索受到 Niklas 研究成果的启发,白帽小哥注意到有一个名为 RT_UNTRUSTED_VOLATILE_GUEST 的宏,它标记了到达宿主机的客户控制数据 – 这看起来是一个很好的入手点。在阅读了“Unboxing your Virtualbox”演示文稿后,其中 RT_UNTURESTED_VOLATILE_GUEST 宏的结果和演示文稿的交集之一是 VBVA 子系统。VBCA(Virtual Box Video Acceleration) 子系统当白帽小哥开始查看这个 Video Acceleration 代码时,他知道虚拟机中的视频子系统是一个危险的漏洞陷阱 – 大量的偏移/复制/缓冲区,所以从统计学角度来看 – 这里可能潜藏着大量的漏洞。Video Acceleration & VM 逃逸漏洞Video Acceleration子系统的本质是“让视频为虚拟机服务”,这基本上意味着实现绘制像素和绘制图像 – 并且它明显涉及到大量缓冲区/复制所述图像和像素的内存 – 就内存破坏漏洞而言,这从来都不是一个好主意!因此白帽小哥决定好好深入研究这个子系统,白帽小哥认为最著名的 VM 逃逸研究之一称为“Cloudburst” – Immunity(是的,老牌 Windows 调试器)于2008年进行的一项研究,该研究在BlackHat 2009上进行了展示,当时他们已经瞄准了视频子系统!Cloudburst 演示文稿Niklas(和其他 VirtualBox 研究人员)已经公布了不少脚本和内核模块,因此可以使用它们来快速访问 VBVA 子系统的某些区域,因此没必要重新发明轮子,直接尝试专注于虚拟机控制的输入以及使用现有脚本/内核模块可以轻松访问的代码。这样也可以保证,如果在代码中发现漏洞,那么触发漏洞就不会像其他攻击面那么困难。体力活浏览 RT_UNTRUSTED_VOLATILE_GUEST 宏的搜索结果,并手动将它们一一检查,有两个结果引起了白帽小哥的注意:crVBoxServerCrCmdClrFillProcess() crVBoxServerCrCmdBltProcess() 它们既有相似之处,也有不同之处。引起注意的一个结果是在文件“server_presenter.cpp”中,它从函数 crVBoxServerCrCmdClrFillProcess() 开始,如下所示:int8_t crVBoxServerCrCmdClrFillProcess(VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd) { VBOXCMDVBVA_CLRFILL_HDR const *pCmd = (VBOXCMDVBVA_CLRFILL_HDR const *)pCmdTodo; uint8_t u8Flags = pCmd->Hdr.u8Flags; uint8_t u8Cmd = (VBOXCMDVBVA_OPF_CLRFILL_TYPE_MASK & u8Flags); switch (u8Cmd) { case VBOXCMDVBVA_OPF_CLRFILL_TYPE_GENERIC_A8R8G8B8: { // ... return crVBoxServerCrCmdClrFillGenericBGRAProcess((const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8*)pCmd, cbCmd); } // ... } }这里需要注意的是将 pCmdTodo 参数标记为虚拟机缓冲区 ( RT_UNTRUSTED_VOLATILE_GUEST ) 的宏。可以看出,虚拟机控制的缓冲区被传递给一个名为 crVBoxServerCrCmdClrFillGenericBGRAProcess() 的内部函数 – 那么让我们看看这个函数的作用(不重要的代码部分已做过滤):static int8_t crVBoxServerCrCmdClrFillGenericBGRAProcess(const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd) { uint32_t cRects; const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects; // ... RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); // ... int8_t i8Result = crVBoxServerCrCmdClrFillVramGenericProcess(pCmd->dst.Info.u.offVRAM, pCmd->dst.u16Width, pCmd->dst.u16Height, pRects, cRects, pCmd->Hdr.u32Color); // ... return 0; }本质上,有 2 个函数被调用,其输入源自访客控制的数据: crVBoxServerCrCmdBltRecsUnpack() – 不会深入研究这个,因为另一个才是本文章漏洞的有趣函数crVBoxServerCrCmdClrFillVramGenericProcess() – 该函数尝试填充 VRAM(视频 RAM – 表示视频图像的内存部分,以像素填充)它以一种相当通用的方式做到这一点查看第二个函数 ( crVBoxServerCrCmdClrFillVramGenericProcess() ) 调用行 – 可以看到许多参数都是虚拟机控制的,有趣的是:offVRAM – 由虚拟机控制的 uint32_tu16Width – 由虚拟机控制的 uint16_tu16Height – 由虚拟机控制的 uint16_t本质上是希望将虚拟机发送指定宽度和高度尺寸的图像放置在 offVRAM 指定的偏移量中。看一下实际的函数内容:static int8_t crVBoxServerCrCmdClrFillVramGenericProcess(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color) { CR_BLITTER_IMG Img; int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img); // ... CrMClrFillImg(&Img, cRects, pRects, u32Color); return 0; }同样,从这里调用了 2 个函数:crFbImgFromDimOffVramBGRA() – 第一个调用,先看看它会做什么CrMClrFillImg() – 第二个调用,稍后再看深入研究 crFbImgFromDimOffVramBGRA() ,事情开始变得愈加有趣了:static int8_t crFbImgFromDimOffVramBGRA(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg) { uint32_t cbBuff = width * height * 4; if (offVRAM >= g_cbVRam || offVRAM + cbBuff >= g_cbVRam) { WARN(("invalid param")); return -1; } uint8_t *pu8Buf = g_pvVRamBase + offVRAM; crFbImgFromDimPtrBGRA(pu8Buf, width, height, pImg); return 0; }请记住以下限制:height 和 width 是由虚拟机控制的 uint16_t 值offVRAM 是由虚拟机控制的 uint32_t 解决整数溢出的一种可能方法是将结果保存在更大的存储变量中,从而防止结果溢出。在这种情况下,宽度和高度都是 uint16_t ,相乘后并保存到 uint32_t 变量中。在以上的例子中,仍然存在一个问题 – 2 个值并不是乘法中唯一的组成部分,它们被乘以 4 – 这就意味两个 uint16_t 变量的结果可能会溢出!进行乘法的原因是这里使用的 BPP(每像素位数)为 32字节(每个像素使用 4 个字节)函数中紧接着是验证 offVRAM 处写入 height * width * 4 字节偏移量,不会超出 VRAM 缓冲区 – 但由于 cbBuf 的计算错误,并且可能小于实际要写入的字节数,此处的检查错误!这里需要注意的一点是,实际写入的字节数取决于 width 和 height ,而不是上面计算的 cbBuff if 语句之后调用的第二个函数将构建一个结构体(称为 Img )来保存“请求”的信息。它将包含:在哪里写入数据(本质上是 VRAM + offVRAM )尺寸(提供的 width 和 height )每像素位数 (32)等等执行操作的代码:static void crFbImgFromDimPtrBGRA(void *pvVram, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg) { pImg->pvData = pvVram; pImg->cbData = width * height * 4; pImg->enmFormat = GL_BGRA; pImg->width = width; pImg->height = height; pImg->bpp = 32; pImg->pitch = width * 4; }如何利用它做一些有趣的事?现在我们已经发现了整数溢出,这恰好允许我们绕过边界检查 – 最大的问题是如何才能让它真正做一些有趣的事情?回到上面提到的一个函数, CrMClrFillImg() ,该函数是通过在易受攻击的函数内恶意构建的 Img 来调用的:static int8_t crVBoxServerCrCmdClrFillVramGenericProcess(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color) { CR_BLITTER_IMG Img; int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img); // ... CrMClrFillImg(&Img, cRects, pRects, u32Color); // NOTE: here Img is malicious return 0; }前面要回忆的另一件重要的事情是, pRects 和 cRects 是也是由虚拟机控制的“矩形”(可以在之前的代码片段中看到,在函数 crVBoxServerCrCmdClrFillGenericBGRAProcess() 中)OK,现在 CrMClrFillImg() 有了虚拟机控制的恶意 矩形 Img,让我们看看 RTRECT 结构是怎样的:/** * Rectangle data type, double point. */ typedef struct RTRECT { /** left X coordinate. */ int32_t xLeft; /** top Y coordinate. */ int32_t yTop; /** right X coordinate. (exclusive) */ int32_t xRight; /** bottom Y coordinate. (exclusive) */ int32_t yBottom; } RTRECT;基本上它具有允许我们绘制矩形的坐标,深入了解 CrMClrFillImg() 来看看我们的恶意参数是如何使用的。void CrMClrFillImg(CR_BLITTER_IMG *pImg, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color) { RTRECT Rect; Rect.xLeft = 0; Rect.yTop = 0; Rect.xRight = pImg->width; Rect.yBottom = pImg->height; RTRECT Intersection; /*const RTPOINT ZeroPoint = {0, 0}; - unused */ for (uint32_t i = 0; i < cRects; ++i) { const RTRECT * pRect = &pRects[i]; VBoxRectIntersected(pRect, &Rect, &Intersection); if (VBoxRectIsZero(&Intersection)) continue; CrMClrFillImgRect(pImg, &Intersection, u32Color); } }观察这个我们可以看到,它只是遍历我们传递给它的所有矩形,并尝试将它们中的每一个与“整个图像”(在上面的代码中称为 Rect)相交。如下所示:DECLINLINE(void) VBoxRectIntersect(PRTRECT pRect1, PCRTRECT pRect2) { Assert(pRect1); Assert(pRect2); pRect1->xLeft = RT_MAX(pRect1->xLeft, pRect2->xLeft); pRect1->yTop = RT_MAX(pRect1->yTop, pRect2->yTop); pRect1->xRight = RT_MIN(pRect1->xRight, pRect2->xRight); pRect1->yBottom = RT_MIN(pRect1->yBottom, pRect2->yBottom); /* ensure the rect is valid */ pRect1->xRight = RT_MAX(pRect1->xRight, pRect1->xLeft); pRect1->yBottom = RT_MAX(pRect1->yBottom, pRect1->yTop); }回想一下 X/Y 轴的工作原理,它与计算机科学中使用的常用坐标系完全相同(Y 向下增长,X 向右增长),如下所示: 假设 width = 11, height = 9 ,在 CrMClrFillImg 中设置的 Img 矩形将如上图所示。相交后,代码会验证公共区域是否为空 (VBoxRectIsZero()) ,如果不是,它会使用我们恶意制作的 Img 和相交的矩形调用 CrMClrFillImgRect() 。查看 CrMClrFillImgRect() 代码:void CrMClrFillImgRect(CR_BLITTER_IMG *pDst, const RTRECT *pCopyRect, uint32_t u32Color) { int32_t x = pCopyRect->xLeft; int32_t y = pCopyRect->yTop; int32_t width = pCopyRect->xRight - pCopyRect->xLeft; int32_t height = pCopyRect->yBottom - pCopyRect->yTop; Assert(x >= 0); Assert(y >= 0); uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * y + x * 4; crMClrFillMem((uint32_t*)pu8Dst, pDst->pitch, width, height, u32Color); }回想一下,Img 的指针没有正确设置,具体来说, pvData 指向 VRAM 中的偏移量,这样如果我们从那里写入宽度 高度 4 个字节,就会越界。总结该函数的作用如下:计算 pCopyRect 指定矩形的宽度和高度(在这种情况下,它始终是当前的矩形,与整个 Img 相交)调用 crMClrFillMem() 从计算的位置开始,使用指定的颜色和计算的尺寸填充矩形(可能超出范围!)相交点的精彩部分主要基于以下事实:恶意 Img 的尺寸(考虑 32 bpp)不适合 VRAM!由于我们可以将它与不同的矩形相交,所以我们可以从伪造的图像中“选择特定区域”并将数据写入其中!OOB 写入事实上,Img 的大矩形和我们制作的矩形之间存在交集,这意味着我们可以选择一个较小的矩形,并且该矩形也超出 VRAM 的界限,然后将我们的数据写入那里。上面所说的“小”是指它可以是任意大小和偏移量(某种程度上;仍然存在一些限制,例如一次写入 4 个字节)鉴于与 VRAM 不相符的大尺寸默认矩形,可以在任何我们希望的特定偏移量处写入我们想要的任何颜色 – 就像在任意偏移量处“绘制一个像素”一样。我们可以在计算出的已经超出界限的矩形内的任何点绘制一个像素,通过指定坐标 – 交点将导致以受控的长度和受控的偏移量写入 OOB。例如,如果在图片中指定从 xLeft=3, xRight=5, yTop=4, yBottom=5 开始仅绘制该矩形,使我们能够避免通配符复制并在任何给定偏移量处获得 OOB 写入。 接下来是查看其它结果,看看是否可以通过这种方法找到其它有趣的原语!白帽小哥查看了早期 RT_UNTRUSTED_VOLATILE_GUEST 宏,搜索(位于同一子系统中)引起注意的其他结果。另一个函数是 crVBoxServerCrCmdBltProcess() ,代码流的结构非常相似,查看该函数中的代码,同样可以使用虚拟机控制的数据获取 crVBoxServerCrCmdBltGenericBGRAProcess():/** @todo RT_UNTRUSTED_VOLATILE_GUEST */ int8_t crVBoxServerCrCmdBltProcess(VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd) { VBOXCMDVBVA_BLT_HDR const *pCmd = (VBOXCMDVBVA_BLT_HDR const *)pCmdTodo; uint8_t u8Flags = pCmd->Hdr.u8Flags; uint8_t u8Cmd = (VBOXCMDVBVA_OPF_BLT_TYPE_MASK & u8Flags); switch (u8Cmd) { // ... case VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8: { //... return crVBoxServerCrCmdBltGenericBGRAProcess((const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *)pCmd, cbCmd); }看一下 crVBoxServerCrCmdBltGenericBGRAProcess() ,跳到有趣的案例,其中同样包含虚拟机控制的参数: if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) crVBoxServerCrCmdBltVramToVram(pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects);它是一个将图像从一个位置复制到另一个位置的函数 – 它被称为 crVBoxServerCrCmdBltVramToVram() 通过阅读此函数,可以看到到达一个代码路径,该路径将虚拟机控制的维度传递给构建源/目标 Img -s 函数,使用了之前存在漏洞的函数! rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects); if (RT_FAILURE(rc)) { WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc)); return -1; }通过查看 crVBoxServerCrCmdBltVramToVramMem() 的实现方式(以及调用的易受攻击函数),可以看到:static int8_t crVBoxServerCrCmdBltVramToVramMem(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight, VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects) { CR_BLITTER_IMG srcImg, dstImg; int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &srcImg); // ... i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &dstImg); // ... CrMBltImg(&srcImg, pPos, cRects, pRects, &dstImg); return 0; }这与之前几乎相同,但这次它将数据从一个位置复制到另一个位置 – 由于我们 crFbImgFromDimOffVramBGRA() 中的问题,目标/源都可能被恶意构造!然后恶意的 Img -s 被传递给负责实际复制的 CrMBltImg() ,再次与虚拟机控制的矩形相交!但这次它将数据从 VRAM 中我们可以控制的一个位置(可以是 OOB)复制到 VRAM 中的另一个偏移量。然后,虚拟机可以读取该数据 – 因此我们可以获得 OOB 读取和 VRAM 的信息泄漏白帽小哥没有从这里编写完整的漏洞利用程序,因为他看到了具有类似原语的多个漏洞利用程序(特别是基于 VRAM 的 OOB),确认这是可以利用的。具体来说, Niklas 的此类漏洞还利用了与 VRAM 缓冲区相关的 OOB r/w ,这也在上面提到过:https://www.exploit-db.com/exploits/43878Crash 上图是白帽小哥调试主机操作系统的 VirtualBox 进程并触发崩溃的旧截图,在这张截图中, rax 相对于 VRAM 缓冲区超出了界限(已经到达未映射区域),而 edx 完全受到控制,从而触发了 OOB 写入。为了触发这个漏洞,白帽小哥在很大程度上依赖于 Niklas 的内核模块和 Python 脚本。
2024年05月10日
27 阅读
0 评论
0 点赞
2023-12-18
如何下载安装PyCharm并搭建Python开发环境
Python简介Python是一种高级编程语言,由荷兰程序员Guido van Rossum在1989年发明,其名称来自于Monty Python剧组。Python 是一种跨平台的解释性语言,经常用于开发 Web 应用程序、桌面软件和数据科学领域,是各种大数据处理和人工智能领域的首选语言。Python的优雅语法和易于上手的特点,使得它成为了初学者和专业开发者的首选语言之一。Python语言的特点:1.易于理解:Python语言语法简单,易于学习上手。2.易于编写:Python语言的开发速度很快,省去了很多底层的细节操作,可以快速实现功能。3.易于调试:Python语言的调试相对于其他语言是非常简单的,在开发过程中可以快速定位问题并解决。4.简洁性:Python语言的代码简洁性非常好,初学者很容易看懂。5.可拓展性:Python语言可以很好地与其他语言进行结合开发,扩展性非常好。Python生态圈Python生态圈是指在Python语言中,各种优秀的开源工具库、框架、组件和工具等资源组成的大集合,相互配合,以支持Python语言在不同领域的应用和发展。Python生态圈因其丰富的资源和各种高质量的库得到了广泛的认可。Python生态圈的组成:1.Python标准库:Python语言自带的库包括了众多的标准库和第三方库,可以快速实现众多功能。2.数据处理:Numpy, Pandas,Scipy等库支持数据处理和科学计算。3.机器学习:Python是机器学习中的主要语言,有Sklearn、TensorFlow等流行的机器学习库。4.Web开发:Python拥有多个流行的Web框架,如Django,Flask等,广泛应用于Web开发。总之,Python语言易学易用,生态圈丰富,已经成为了数据处理、科学计算、机器学习和Web开发等领域的首选语言,是一种非常优秀的编程语言。Python下载安装首先我们先右键“此电脑”,点击“属性”选项,进入设置界面找到“系统类型”,确定自己电脑操作系统的类型(现在的电脑基本都是64位)进入python官网:https://www.python.org/点击“Downloads”,在下拉栏选择“Windows”选择合适的版本进行下载图中Windows embeddable package是python的Windows可嵌入包,解压后是一个文件夹,该文件夹是一个最小python运行环境,不包括doc、idle、pip等。该版本主要用于嵌入其他程序之中。32-bit是指32位操作系统,下载的包适合32位操作系统,基于32位处理器。ARM64是AArch64状态下的处理器体系结构,下载的包适合ARM64处理器,基于64位处理器。我们用python进行程序开发,需要下载Windows Installer的安装程序,这个安装程序具有一个较为完整python开发环境。下载完成后,双击.exe文件开始安装测试python是否安装成功同时按住“win+r”键,输入“cmd”,进入终端 输入“python”命令,查看输入,如果出现如下输出,说明python环境搭建成功!PyCharm简介PyCharm是一款由捷克公司JetBrains开发的Python集成开发环境,它提供了强大的代码编辑、语法高亮和代码自动补全等功能,支持Django、Flask等主流Python框架。此外,PyCharm还内置了调试器、版本控制工具、测试工具和集成开发环境等功能,可以帮助开发者更加高效地开发Python应用。PyCharm具有以下主要特点:1.强大的代码编辑功能:PyCharm提供了丰富的代码编辑功能,包括代码高亮、智能代码补全、代码重构、代码自动格式化、代码导航等,可以大大提高开发效率。2.支持主流Python框架:PyCharm支持常见的Python框架,包括Django、Flask等,提供了相应的项目模板和代码片段,可以帮助开发者快速创建和完成Python应用的开发。3.内置调试器:PyCharm内置了强大的调试器,可以方便地对Python代码进行调试、故障排查和错误分析。4.版本控制工具:PyCharm提供了集成的版本控制工具,支持Git、SVN等常见版本控制系统,可以方便地管理和协作开发代码。5.测试工具:PyCharm集成了常见的测试工具,如unittest、pytest等,可以方便地编写和运行测试用例。6.集成开发环境:PyCharm提供了完整的集成开发环境,包括Python解释器、控制台、文件浏览器和集成终端等,方便开发者在一个应用程序内完成所有开发任务。总之,PyCharm是一款功能强大的Python集成开发环境,旨在提高开发者的生产力,使开发者可以更加高效地开发Python应用。它提供了丰富的功能和工具,适合不同类型的开发者,无论是新手还是专业开发者都能从中受益。PyCharm下载安装PyCharm windows版本下载地址:https://www.jetbrains.com/pycharm/download/#section=windows1.进入pycharm windows下载官网,选择“PyCharm Community Edition”的“Download”(有专业版和社区版,这里我们选择社区版就够用啦,毕竟专业版要收费滴)下载完成后进入下载目录,双击.exe文件开始安装点击“next”PyCharm环境搭建1.下载安装后,桌面上就可以看到PyCharm啦,让我们双击PyCharm运行它吧! 双击后会进入如下界面,我们点击“新建项目” “pythonProject”是项目名称,基础解释器选择上面安装的python的路径,配置好后点击“创建”即可 进入PyCharm后,会出现如下界面,单机右上角的“运行”按钮即可运行程序 出现以下结果说明运行成功啦,到此我们的PyCharm环境搭建就完成咯!
2023年12月18日
44 阅读
0 评论
0 点赞
2023-12-11
Python实现统计图像连通域的示例详解
数组统计函数ndimage提供一系列函数,可以计算标注后的数组的相关特征,比如最值、均值、均方根等。下列函数,如果未作其他说明,那么就有3个参数,分别是(input, labels=None, index=None),其中input为输入数组;labels为input的标签,形状和input相同;index为整数或者整数数列,为用于计算的label。示例如下import numpy as np import scipy.ndimage as sn x = np.random.randint(10, size=(3,3)) print(x) ''' [[0 3 5] [9 3 1] [1 5 7]] ''' sn.center_of_mass(x) # (1.1470588235294117, 1.088235294117647) sn.extrema(x) # (0, 9, (0, 0), (1, 0))连通域标记通过label函数,可以对数组中的连通区域进行标注,效果如下from scipy.ndimage import label import numpy as np a = np.array([[0,0,1,1,0,0], [0,0,0,1,0,0], [1,1,0,0,1,0], [0,0,0,1,0,0]]) labels, N = label(a) print(labels) ''' [[0 0 1 1 0 0] [0 0 0 1 0 0] [2 2 0 0 3 0] [0 0 0 4 0 0]] ''' print(N) 4在label函数中,还有一个用于规范何为“连通”的参数,即structure,其数据类型为二值数组,其维度与输入的input相同。在上面的示例中,连通域1,3,4尽管没有上下左右的联系,但在对角线上是有交集的,通过调整structure参数,可以提供一种将这三个区域连在一起的连通域方案。stru = np.ones([3,3]) bLab, bN = label(a, stru) print(bLab) ‘'‘ [[0 0 1 1 0 0] [0 0 0 1 0 0] [2 2 0 0 1 0] [0 0 0 1 0 0]] '‘'可见,这次只选出了两组连通域。连通域统计前面提到的所有统计函数,形参都有三个,分别是input, labels, index,其中input为输入数组,labels为将要处理的连通域,index为准备处理的连通域序号。np.random.seed(42) test = np.random.rand(5,5) test[test<0.8] = 0 labels, N = sn.label(test) print(N) # 2 print(labels) # ‘'‘ [[0 1 0 0 0] [0 0 2 0 0] [0 2 2 0 0] [0 0 0 0 0] [0 0 0 0 0]] '‘' print(test) ‘'‘ [[0. 0.95071431 0. 0. 0. ] [0. 0. 0.86617615 0. 0. ] [0. 0.96990985 0.83244264 0. 0. ] [0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. ]] '‘'接下来通过连通域统计函数,针对某个连通域进行计算>>> sn.mean(test, labels, 1) 0.9507143064099162 >>> sn.mean(test, labels, 2) 0.8895095462457837 >>> sn.mean(test, labels, 0) 0.0当index=1时,会找出labels中为1的位置,然后把test中这些位置的元素求平均。到此这篇关于Python实现统计图像连通域的示例详解的文章就介绍到这了,更多相关Python统计图像连通域内容请搜索老K博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持老K博客!
2023年12月11日
86 阅读
0 评论
0 点赞
1
2
CC BY-NC-ND