使用WindowsAPI在Ring3进行系统操作
使用Windows API在Ring3对系统进行操作
Cmd
使用管道通信
客户端
- LoadLibrary(“Cmd.dll”);
- GetProcAddress 获取下述各种函数地址
- SetPipeCommunication开启管道通信
- 启动cmd.exe,SetPipeData发送服务端的数据
- 启动线程,GetPipeData获取管道内的数据(cmd返回的),向服务端发送
- 析构时UnsetPipeCommunication释放管道
服务端
接受到客户端返回的东西然后展示
用户输入要在客户端cmd运行的东西,发送出去(IOCP)
登录
客户端
- capGetDriverDescription获取打印机、摄像头等外部设备信息
- RegOpenKey打开注册表键句柄,RegQueryValueEx传入句柄和要查的键string获取值
- 上述方法查到进程信息,在HARDWARE\DESCRIPTION\System\CentralProcessor\0,ProcessorNameString
- 发送到服务端
服务端
拿到信息设置进数据结构里面
服务管理
客户端
- LoadLibrary(“Service.dll”);
- SeEnumServiceList枚举服务信息,自己遍历一下放进BufferData,发送到服务端
- 接受服务端发过来的Method,ServiceName,调用SeCofigService设置服务信息。重复步骤2.
服务端
LoadLibrary(“Service.dll”);获取SeEnumServiceList地址
解析客户端发过来的Buffer,展示信息。调用SeEnumServiceList展示本机的服务信息
客户端信息有:
“服务名称”,
“显示名称”,
“启动类型”,
“运行状态”,
“可执行文件路径”
“服务名称”,
“显示名称”,
“启动类型”,
“运行状态”,
“可执行文件路径”
本地信息有:”真实名称”,
“显示名称”,
“启动类型”,
“运行状态”,
“可执行文件路径”根据选择给客户端发操作。
Method:
1 启动
2 停止
3 自启动
4 手动启动
即时消息
客户端
- #pragma comment(lib, “WINMM.LIB”) 时钟回调,其实是实现展示一下以后就关闭。消息到了响一下铃声
- 消息来了设置事务,然后展示到窗口
服务端
- 获取编辑框里面的数据,检测到回车就发出去
文件管理
客户端
- LoadLibrary(“File.dll”);
- GetLocalHardDiskInfo获取磁盘信息
- GetLocalFileList获取文件信息
- 解析一下,发到服务端去
服务端
- CreateFileA通过DiskVolumeName打开卷句柄,通过DeviceIOControl传递FSCTL_QUERY_USN_JOURNAL得到UNS
USN是Update Service Number Journal or Change Journal的英文缩写,直译为“更新序列号”,是对NTFS卷里所修改过的信息进行相关记录的功能。当年微软发布Windows 2000时,建立NTFS 5.0的同时,加入了一些新功能和改进了旧版本的文件系统,为它请来了一位可靠的秘书,它可以在分区中设置监视更改的文件和目录的数量,记录下监视对象修改时间和修改内容。没错,它就是USN日志。当这个功能启用时,对于每一个NTFS卷,当发生有关添加、删除和修改文件的信息时,NTFS都使用USN日志记录下来。 - 再发FSCTL_ENUM_USN_DATA遍历记录,展示
- 监视UNS,维护数据结构
- LoadLibrary(“File.dll”); GetLocalHardDiskInfo展示服务端的信息
- 展示信息包括
“名称”,
“显示名称”
“文件系统”
“类型”,
“总大小”,
“可用空间” - 发送到客户端重新请求文件信息(我好像没找到操作客户端的函数)
系统管理
客户端
进程管理
- LoadLibrary(“Process.dll”);
- GetProcAddress获取SeEnumProcessList,遍历进程信息。解析以后发到服务端
- 接收消息,调用Ring3KillProcess杀进程。
窗口管理
- LoadLibrary(“Window.dll”);(这尼玛也有对应的dll,跪了。。)
- GetProcAddress获取下述函数地址
- GetWindowList获取打开的窗口信息,解析一下发服务端
- 接收消息,调用SetWindowStatus设置窗口状态(最小化等),调用PostWindowMessage向窗口发信息(关闭等)
服务端
进程管理
- LoadLibrary(“Process.dll”);,SeEnumProcessList,Ring3KillProcess,查看和操作本机的进程。
- Wow64EnableWow64FsRedirection 禁止文件重定向
- 展示客户端的进程信息
- 客户点击杀进程,发消息给客户端,或者对本地操作
- 点击了获取进程模块信息,调用
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,ProcessID)
获取信息,并开一个新窗口展示
进程模块管理
- GetModuleHandle(“Process.dll”);(这说明这个dll已经被导入,直接获取句柄。LoadLibrary会重新映射进内存并增加引用计数)
- GetProcAddress拿到SeEnumProcessModuleList,传进PID即可获取到所有模块信息,解析以后放上窗口。包括:
“模块地址”,
“模块大小”,
“模块完整路径”,
“模块类型”,
窗口管理
- LoadLibrary(“Window.dll”); 下述函数地址都GetProcAddress而来
- 展示客户端和本机的消息,内容有:”窗口句柄”,
“窗口名称”,
“窗口类名称
“窗口状态”,
“启用/禁用”
“线程ID”,
“进程ID”,
“占位” - GetWindowList,SetWindowStatus,PostWindowMessage操作本机,或给客户端发消息操作客户端
- RestartForbidWindow重启被禁用的窗口
- FixWindowTitleBar重设窗口标题
远控
客户端
- 开线程,设置线程回调
- 线程回调中向服务端发送bmp位图
- 发送第一张截图
- 一直发送下一张截图
- 接受服务端消息,发送给位图。调用BlockInput可以锁上鼠标键盘等待消息,或解锁进行操作。
- 解析发来的数据,调用SetCursorPos移动鼠标,SetCapture设置画面,mouse_event和keybd_event传递键盘鼠标事件。
- GetClipboardData获取剪切板发给服务端,SetClipboardData根据消息设置剪切板
以上靠<Windows.h>(WinUser.h)提供的API实现。位图操作如下
- GetSystemMetrics获取屏幕分辨率
- 构建BITMAPINFOHEADER位图结构体
- GetDesktopWindow获取屏幕句柄。GetDC获取屏幕DC。
设备描述表(DC)是Windows中的一种数据结构,它包含GDI需要的所有关于显示界面情况的描述字段,包括相连的物理设备和各种各样的状态信息。在Windows画图之前,Windows程序从GDI获取设备描述表句柄(HDC),并在每次调用完GDI输出函数后将句柄返回给GDI。屏幕上的每一个窗口都对应一个DC,可以把DC想象成一个视频缓冲区,对这这个缓冲区的操作,会表现在这个缓冲区对应的屏幕窗口上。 - CreateCompatibleDC创建设备上下文,CreateDIBSection把信息分配进位图里
- 截图位于m_BitmapInfo->bmiHeader.biSizeImage
- 光标调用GetCursorPos传入POINT结构
- 每次分段扫描全屏幕,调用BitBlt传入DC句柄,新的位图和旧的按结构作比较,如果不同就修改,然后返回新的位图
服务端
- 根据句柄CreateCompatibleDC获取DC,CreateDIBSection把信息分配进位图里,SelectObject择一对象到指定的设备上下文环境,SetScrollRange指定滚动条范围的最小值和最大值
- 得到被控端发来的数据 ,将他memcpy拷贝到HBITMAP的缓冲区中,这样一个图像就出现了
- 后续更新一下变化部分的屏幕数据然后BitBlt、DrawIconEx重绘,memcmp比较鼠标位置,根据鼠标是否移动和屏幕是否变化判断是否重绘鼠标,防止鼠标闪烁
- 汇编实现的代码控制ESI指向的数据(我看不懂了)
- 根据枚举类型,判断要做的操作。要获取客户端剪切板,需要一直获取,所以提交到完成端口队列。同样把自己的剪切板也要一变化就发到客户端去。
- 还用了内存池来管理。详见浅析nginx内存池
注册表管理
客户端
全给注释了,啥也没做。其实建立好通信,就和服务端的操作一样了。
服务端
- LoadLibrary(“Register.dll”);,以下函数都用这个做ModuleBase调用GetProcAddress
- SeEnumRegisterDirList遍历注册表目录。解析HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE、HKEY_USERS、HKEY_CURRENT_CONFIG等等目录
- SeEnumRegisterItemList遍历注册表Item,列出名称,类型,数据。分开REG_SZ,REG_DWORD,REG_QWORD,REG_BINARY,REG_EXPAND_SZ
- 后续没有啥删除,修改的操作。。。
内核管理
只有客户端有
客户端
- LoadLibraryA(“Ntdll.DLL”)
- GetProcAddress拿到ZwShutdownSystem关机。需要提权到关机权限,OpenProcessToken拿Token然后AdjustTokenPrivileges权限那一套,或者EnableSeDebugPrivilege
- 负责和服务端通信。
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.