发布日期:2024-09-26 14:14 点击次数:119
按理来说,本东说念主不该发表此类专科著作,鄙东说念主零散碎屑化的开发资格,让本东说念主大胆向各位网友痔疮 肛交,在远控方面作念少量演示确认,指摘少量我方的强劲。
设施工程代码地址:点击此处下载。
设施分为两个部分,边界端和被控端,他们之间通过网罗来连结和交互,其责任历程大体如下:
被控端每隔20毫秒截屏,图像经过压缩,通过tcp网罗传输给边界端,边界端对接收到的视频帧及时刷新泄露;被控端及时接收边界端的对屏幕的操作音讯(主淌若键盘的按键、鼠方向位置和行动等),并在本端模拟这些键盘鼠标操作。
边界端代码主要在RemoteControlRecver.cpp和RemoteControlListener.cpp中,被控端代码主要在RemoteControlProc.cpp和RemoteControl.cpp中。
设施是我方对远控的少量探索和demo演示,结束历程吻合本文念念路,天然离商用有很远距离,但从本色的使用遵循看,仍是具备了远控的基础功能和遵循。
(一)旨趣经典的远控,比如国际的TeamViewer、国内近几年出现的ToDesk,功能深广且精密复杂,但这并不确认它的望尘莫及(远控软件,除非算法上的冲破,无论表面和工程本领,只怕都无法为野心开发者赢得博士学位),它的旨趣无非即是:将被控端的屏幕及时复制到主控端并保持刷新,主控端就像使用腹地的屏幕雷同,使用菜单、键盘输入、鼠标点击等视觉交互,主控端在该屏幕上的键盘和鼠标操作,通过网罗传输给被控端,更变为被控详察应的键盘和鼠标操作。
天然这是极为简短的形色,执行中要酌量许多其他身分,比如对网罗流量的酌量:如果每一帧画面都是截屏数据,要保证动画的连贯传神,每秒至少要传输24帧以上的画面,每一帧画面如果接受24位真彩色、屏幕分辨率假设是最常用的1920x1080,此时,未压缩前的大小是6220800字节,压缩后一般最少也有150-200kb傍边(压缩率跟画面的像素酌量,一般来讲,常见的图像压缩算法,越是像素成列无端正、相对速率畅通越快、变化率越大的像素值,压缩比越低),这时每秒的带宽压力要达到80M/b(10MB)以上,有些网罗环境下,这是一个恐怖的数字,本色环境可能够不上,因此,若何压缩减少视频传输流量,画面的高清泄露、升迁反馈速率和边界的丝滑进度,是此类软件的中枢本领之一。
一般来说,要结束此类软件的敏捷开发,最快捷的模式是使用第三方开发包,比如大名鼎鼎的ffmpeg,此开发包中有多种决策不错结束高效的视频传输,如h264、h265公约接口,此类接口不错将传输数据减少1到2个数目级,本色测试数据流量在每秒几百kb致使100kb/s以下,仍是不错中意本色需要,然而,这么的网罗流量或者本色泄露画面的玄虚遵循并不够优秀,从测试中发现,微软自带的费力边界软件mstsc.exe,在100kb以内的网速下,画面泄露依然了了、边界依然保持畅通,这就不是第三方开发包不错狂妄达到的。另外此类第三方接口中莫得键盘鼠标音讯的惩办,许多定制化需求不行被中意,还需要对开发包进一步定制和开发。
如果对第三方开发包不太舒畅,那就只好我方出手手撸代码了。
(二)结束细节妖怪荫藏在细节中。从告诫上来说,就算很通俗的表面形色,工程执行中也会有许多细节需要填坑夯实,理学在前挖坑,工程学在后填坑,这也许即是工程学(比如软件工程)存在的有趣吧。
底下即是对念念路的细节形色。
主控端的具体代码逻辑如下:每一个被控客户端的费力连结,边界端需要创建两个线程,一个进展与被控端网罗通讯,一个进展窗口泄露刷新和窗口音讯。网罗通讯线程有两个膨大节点,一个节点是膨大recv函数,接收被控端的截屏数据;另一个膨大节点是膨大send函数,发送泄露窗口的键盘鼠标音讯。窗口泄露和音讯惩办线程主淌若及时刷新和泄露被控端的截屏,切入点是依靠窗口的WM_PAINT音讯,每当网罗通讯线程接收到一帧截屏后会调用InvalidateRect(参数是泄露窗口的HWND句柄),此时窗口设施会膨大刷新历程。此线程另外一个功能是,拿获主控端的在泄露窗口中的键盘鼠标音讯,并存放在全局变量中,这么网罗通讯线程就不错读取和发送给被控端,被控端模拟点击和键盘输入,将收到的键盘鼠标音讯退换为腹地的键盘鼠标操作。
另外需要防御的是,两个线程中,资源请求和开释、连结边界等主淌若在泄露刷新窗口线程中完成的,在主控和被控之间因各式原因断开连结时,要保证总共的资源都有用开释。
两个线程共用的客户端结构体如下:
被控端设施比较通俗,主淌若在一个轮回中,赢得截屏数据,发送给边界端,然后接收边界端的键盘鼠标音讯,并将这些键盘鼠标音讯退换为腹地的键盘鼠标音讯。
代码中的api接受了函数指针的调用模式,去掉前边的lp前缀就不错相接了。主要的功能模块如下:
1. 被控端截屏发送给边界端。从网上的贵府来看,截屏功能的结束方法如下:
色之阁上头有几点需要啰嗦几句:(1) windows上gdi二维图像api都是用DC句柄来结束的。测试发现,GetDC(0)等同于CreateDC("display",0, 0, 0),也等同于GetDC(GetDesktopWindow()),这几种用法都是用来赢得桌面的DC。
(2) CreateCompatibleBitmap函数中的HDC要使用桌面的HDC,而不行是新创建的内存hdcmem,这是一个掩藏的知识盲点,microsoft的讲解如下: 莽撞是,CreateCompatibleBitmap产生的hBitmap位图中的位数和状貌跟使用的hdc参数中的保持一致,而使用CreateCompatibleDC函数创建的HDC默许都是2位的位图。
(3) GetDIBits函数有文档中未指明的知识盲点。比如lpbi参数指向的BITMAPINFO,在8位256色状貌模式下,要给调色板留住空间,调色板一般需要另外的1024字节大小的空间,不然调用此api会发生内存越界非常。另外,此函数如果不知说念若何填写BITMAPINFO位图参数,不错在第一次调用时,lpData参数为空,调用后,函数会自动填充BITMAPINFO结构的参数,然后第二次调用此函数,即可得到相应参数的位图数据。
BITMAPINFO结构体界说如下:
该函数的官方文档如下: 防御这里的形色,如果lpvBits参数有用,那么前6个参数必须驱动化,而且扫描线的数值必须是Dword对王人。前6个参数指的是biSizeImage之前的6个参数,biSizeImage的计较比较复杂,无论位图的状貌深度是几许位,扫描线长度必须要4字节对王人。测试中还发现扫描线的行数并不需要dword对王人。
文档中说,函数调用时hbitmap参数不行被SelectObject选中,测试中发现,hbitmap即使仍是被调用了SelectObject函数被选中,调用时也不错告捷。
截图撑持8位、16位、24位、32位状貌值,测试设施使用的16位色。从视觉遵循上,16位色跟24位,不雅看起来区别很小,零散是24位色(32位色联系于24位色仅仅增多了alpha值透明度),仍是逾越东说念主的眼睛对状貌的识别进度的上限,再高的状貌值仍是没挑升念念。由于传输的是像素值,而不是跟jpeg或者其他视频流算法中使用的近似压缩值(或者近似压缩块),是以画面的了了度是很好的,这亦然比拟较于ffmpeg品级三方开发包使用h264、h265压缩视频流的上风。
另外,忽视稽查文档的英文版,汉文版好多翻译不准确或者绝顶不严谨,永恒依赖汉文翻译,会导致开发水平得不到升迁。
2. 数据压缩传输。接受zip压缩,压缩参数迷惑为最大化压缩,压缩比估值大约是6-20倍。如果是8位的位图帧,分辨率1920x1080,一帧压缩后约莫是60-120KB;如果是16位,压缩后约莫为100-300KB;32位的话,约莫是150-600KB。天然这么的压缩比仍然难以中意本色需求,此文在第三个话题中会详确先容若何减少视频流量,最终不错将网罗流量缩短到平均100KB/S。3. 截屏帧的泄露刷新。主要代码如下:
代码中,lpClientBitmap指向接收到的内存中的bmp文献,调用CreateDIBSection函数是为了创建一个近似于此bmp文献式样和参数的hbitmap句柄后,然后将bmp文献的像素值拷贝到句柄指向的像素内存地址中,并使用StretchBlt将像素值泄露在面前窗口中的客户区中,因为客户端和就业器的窗口大小可能不雷同,是以使用StretchBlt结束缩放而不是BitBlt函数。同期要防御,CreateDIBSection函数第一个参数为0,0即相当于GetDC(0),代表桌面窗口的HDC,这点在官方文档中并未确认,然而不错成功使用。
4. 键盘鼠标音讯。边界音讯的收发和视频帧是次序关系,而不是异步关系,被控端每发送一帧截屏后接收边界端的键盘鼠标音讯,并将此音讯模拟为本机的键盘鼠标操作;与此同期,边界端每接收一帧截屏后发送键盘鼠标音讯。由于网罗通讯使用禁锢模式,此时一定要保证,被控端的先发送和后接收、边界端先接受再发送,主控和被控任何的膨大分支都要永诀膨大这两对代码节点,不然会变成网罗收发的死锁。另外,边界端如果发现,键盘鼠方向位置和行动跟前次的值疏通,就会向被控端发送一个REMOTE_DUMMY_PACKET数据包,告诉被控端,边界端莫得边界音讯给你,你不错适合的增多截屏延时(一次增多10毫秒),以便减少网罗销耗。主要的键盘鼠标结构体如下:
该结构由几个全局变量存放:键盘按键值,鼠标左键、中键、右键是否有点击行动,鼠标滚轮的滚动距离,鼠方向坐标位置等。边界端的窗口设施监听鼠标键盘音讯,将这些音讯填充为上述结构体,并由通讯线程发送给被控端。
被控端通过keybd_event和mouse_event将收到的边界信息退换为本机的键盘鼠标音讯。例子代码如下:
(三)减少网罗流量的悉力测试中发现,本色的网速有可能比设想中偏低,比如许多就业器网罗带宽只好几百kb/s,上述依靠传输截屏帧的泄露模式,按照40ms一帧的延时,8位位图数据帧,经过zip压缩后,网罗流量不错平均减少10倍傍边也即是约莫1~2MB/s傍边,依然无法中意本色需求,经过酌量,接受了如下几种改善步调:
客户端每次截屏后动态延时。当就业端莫得鼠标键盘等边界信息后,发送延时音讯REMOTE_DUMMY_PACKET给客户端,客户端每收到一个这么的数据包,截屏延时自动增多10ms,最长到2000ms为止,而收到键盘鼠标等边界音讯后,延时坐窝收复到默许的REMOTE_CLIENT_SCREEN_MIN_INTERVAL值,这么不错权贵的减少网罗流量。 将截屏数据帧的式样由bmp更变为jpeg。bmp是原始像素值式样,jpeg是压缩后的像素式样,同期jpeg压缩算法是对每一块像素块进行压缩,经测试,在保证图像质料80%以上的条款下,其压缩比约莫在10-40倍,然而这对zip压缩的上风并不彰着(zip的压缩比平均在6-30倍傍边),而且jpeg使用起来也较为繁琐,是以弃之未用。天然,如果改为jpeg式样的话,每一帧截屏的网罗流量还能减少约莫25%。 发送截屏帧前,膨大屏幕像素比对操作。对每一帧截屏的总共像素值保存副本,每次截屏后跟前次的截屏数值比对,如果改变的像素值数目逾越一帧像素总额的一半,就发送通盘的截屏帧,不然只发送发生变化的像素值(式样是像素位置和像素的值,总共像素点在发送缓冲区中线性成列,并在zip压缩后传输);如果跟上一帧比拟总共,像素点均未发生任何变化(这才是绝大大都情况),则发送延时音讯。测试发现,在很短的截屏周期内,被控屏幕每一帧画面,不可能每一个像素都发生变化,改变的只好很少一小部分,致使80%的监控周期内,通盘屏幕的总共像素值未发生任何变化,此时不需要传送任何像素信息。这里还有一个知识,在windows下的截屏是莫得鼠方向,因此,鼠方向点击和出动,也不会导致截屏像素点的任何改变。经测试发现,中度操作时,平均每个截屏周期,屏幕上变化的像素值,少的只好几十几百个字节,多的也只好几十kb,此种方法将发送截屏的概率下跌了90%以上。天然,我合计还有一种近似的方法,即是监听WM_PAINT音讯,将重绘的像素块发送给主控端,这种模式跟像素值比对旨趣疏通,仅仅结束模式不同。此段主要代码逻辑如下:此处第一个StretchBlt函数的作用是,将主控端泄露窗口大小更变为适合被控端宽度高度的大小,原因是,被控端无法得知主控端泄露窗口的大小,被控发送的像素值位置是对本窗口的偏移值,如果双方窗口大小不一致,那么被控端的像素位置值就失去了有趣。此时通过StretchBlt函数退换后,就不错将像素值成功写入退换后的hbitmap,并再次调用StretchBlt函数,将客户端的窗口大小休养为主控端泄露窗口的大小。此处也用到了SetDIBits和GetDIBits函数,该函数上边仍是讲过了,功能比较深广,然而使用起来比较复杂。此处有个内存越界的bug,也即是像素的偏移值会大于通盘截屏的像素个数总额,会导致WriteLog那一滑的膨大,原因应该是,双方的窗口大小不一致,若被控的窗口比较大,而主控端窗口比较小,主控端的缓冲区是按照主控窗口大小分派的,退换坐标后,有可能发生内存溢出。
像素值比对函数如下:
ScreenFrameChecker函数分8位、16位、24位、32位4种状貌深度值,跟上一帧比对截屏像素值,复返发生变化的像素值个数。为了加速速率,也不错按照每种端正,比如每次8个字节比对,或者使用simd辅导优化,每次比对16字节。
(四)不及和颓势 实例代码中未结束主控端和被控端的剪贴板的分享,以及文献复制粘贴操作。 使用截屏模式握取屏幕内容,然后压缩通过网罗发送,这种机制太慢了。通过QueryPerformanceCounter高精度时钟测试,一帧截屏时分支拨大约率在20-40毫秒之间,加上解压和网罗传输的时分损耗,这么的一帧画面时分销耗可能逾越50毫秒致使100毫秒。这么的速率对应于每秒20帧以上的速率来说,将是一个致命颓势,无法达到野心要求,这可能是因为线程切换或者API接口本人的问题,最佳能将一帧握屏时分销耗减少到10毫秒以内。 压缩算法使用zip,zip本人时分销耗绝顶少,测试几百kb的数据、压缩率最高时平均时分销耗在5毫秒傍边,zip压缩是无损压缩,图像数据并不需要无损压缩,假如有其他合适的压缩算法,有较小的像素损构怨较好的时分销耗,可能会有几毫秒的遵循升迁,然而不行算一个中枢问题。 其他许多细节惩办不及。[课程]Android-CTF解题方法汇总!痔疮 肛交