工作中碰到一个问题,需要把一个远控工具放到磁盘上,读取到内存中加载PE程序。
使用github中的加载PE文件程序RunPeMemory32位程序直接加载远控工具是没有问题的,为了隐蔽性,需要写一个服务dll,然后有Windows服务主程序svchost.exe来加载服务dll,在服务dll代码中加载远控工具PE文件。
这种方法实践不可行,猜测是远控工具是由golang写的,与svchost.exe中某些库不兼容,导致无法运行。
只能换一种方法,在服务dll中再次启动一个svchost.exe程序,传入特定的命令行参数,方便之后识别,需要下面几个步骤:
1. 调用CreateProcessA/W函数启动svchost.exe程序时挂起进程
2. 使用进程注入技术,调用VirtualAllocEx在目标进程空间中申请空间,存放服务dll的绝对路径,使用进程注入调用LoadLibraryA/W传入dll地址,获取线程返回值得到模块地址
3. 获取服务dll的导出函数的地址,服务dll除了ServiceMain函数还有一个导出函数,通过解析PE文件获取导出函数的相对偏移,加上上一步获取到的基地址
4. 使用线程注入技术调用导出函数,在导出函数中识别命令行参数,内存加载远控PE文件即可。
也可以不使用远程注入技术,使用跨进程写入shellcode:
1. 挂起进程后,获取主线程的线程上下文件环境,获取到EIP寄存器指向地址之后,修改EIP所在地址的内存页面属性,改为可读可写。
2. 查看挂起的svchost进程,看到内存模块只有ntdll模块,跨进程写入shellcode,如加载kernel32.dll、再加载目标dll,需要使用到ntdll中的加载dll函数。
3. 目标dll加载后,再调用导出函数。
这两种方法对比的话,第二种方法需要写入shellcode,兼容性不好,需要写x86和x67两套shellcode,第一种兼容性更好。