资源描述
计算机病毒入侵检测大作业
学院(系): 软件学院
专 业: 软件工程
班 级:
姓 名:
学生学号:
2011年 5 月 26日
摘要
线程是在一个进程里产生的多个执行进度实例,举个简单例子,一个网络文件传输程序如果只有一个线程(单线程)运作,那么它的执行效率会非常低下,因为它既需要从网络上读取文件数据,又需要把文件保存到磁盘,同时还需要绘制当前传输进度条,由于在代码的角度里这些操作只能一条条的顺序执行,程序就不能很好的做到在保存数据的同时绘制传输进度条,即使程序员将其勉强凑到一块执行,在用户方面看来,这个程序的响应会非常缓慢甚至直接崩溃,而“多线程”技术则是为了解决这种问题而产生的,采用“多线程”技术编写的应用程序在运行时可以产生多个同时执行的操作实例,例如一个采用“多线程”技术的网络文件传输程序就能同时分出三个进度来同时执行网络数据传输、文件保存操作和绘制传输进度条的操作,于是在用户看来,这个程序运行非常流畅,这就是线程的作用。在程序运行时,只能产生一个进程,但是在这个进程的内存空间(系统为程序能正常执行而开辟的独立内存领域)里,可以产生多个线程,其中至少有一个默认的线程,被称为“主线程”,它是程序主要代码的运行部分。
“线程注射”的全称是“远程线程注射”(remotethread injection),通常情况下,各个进程的内存空间是不可以相互访问的,这也是为程序能够稳定运行打下基础,这个访问限制让所有进程之间互相独立,这样一来,任何一个非系统关键进程发生崩溃时都不会影响到其他内存空间里的进程执行。但是在一些特定的场合里,必须让进程之间可以互相访问和管理,这就是“远程线程”技术的初衷,这个技术实现了进程之间的跨内存空间访问,其核心是产生一个特殊的线程,这个线程能够将一段执行代码连接到另一个进程所处的内存空间里,作为另一个进程的其中一个非核心线程来运行,从而达到交换数据的目的,这个连接的过程被称为“注射”(injection)。远程线程技术好比一棵寄生在大树上的蔓藤,一旦目标进程被注射,这段新生的线程就成为目标进程的一部分代码了,只要目标进程不被终止,原进程无论是否还在运行都不会再影响到执行结果了。
关键词:线程,注射(注入),内存空间,木马
目录
摘要 2
一、实验名称 3
二、实验目的 3
三、实验环境 4
四、木马线程注入技术原理和步骤 4
木马线程注入技术原理 4
木马线程注入技术步骤 5
五、算法及实验步骤 5
程序流程图 5
函数和数据结构分析 7
用到的Windows API 7
主进程的主要函数 11
自定义的数据结构 11
六、调试结果及实验结果 11
程序执行结果及截图 11
七、总结 12
八、参考文献 13
一、实验名称:木马线程注入技术
二、实验目的:
线程注入技术是木马程序和病毒程序在任务管理器中隐藏自身的方法之一,通过了解其原理,可以对如何防范和查杀此类病毒有所掌握。此外,自己开发的一些程序,也可以应用线程注入的原理实现一些必要的功能,或者可以通过线程注入技术实现键盘拦截、DLL注入、监控系统、游戏外挂(修改器)等功能。
三、实验环境:
Microsoft Visual C++6.0,Windows XP-32bit
四、木马线程注入技术原理和步骤:
木马线程注入技术原理:
木马程序更好的隐藏自身的方式不是以进程和服务的方式存在,而是完全溶入系统内核。因此,在设计时,不应把它做成一个应用程序,而是做成一个可以注入应用程序地址空间的线程。该应用程序必须确保绝对安全,这样才能达到彻底隐藏的效果,增加查杀的难度。线程注入式木马采用动态嵌入技术将自己的代码嵌入正在运行的进程中。
Windows中每个进程都有自己的私有内存空间,其他进程不得对该私有空间进行操作,但实际上,有很多方法可操作私有空间。动态嵌入技术很多,如窗口 Hook、挂接API、远程线程等,远程线程技术相对简单,只要有基本的进程线程和动态链接库的知识就可以轻松实现。
木马线程注入技术是通过在一个远程进程中创建木马线程的方法进入该进程的内存地址空间。可以通过CreateRemoteThread函数在一个远程进程内创建远程线程,被创建的远程线程可以共享远程进程的地址空间,这样就可以通过将木马植入系统认为是安全的进入远程进程的内存地址空间运行,达到木马程序隐藏自身的目的。
木马线程注入技术步骤:
1.打开远程进程,用OpenProcess打开远程进程,获得进程句柄,这是Windows编程的典型风格。
2.分配代码空间,使用VirtualAllocEx函数在远程进程的堆空间中分配一块区域用于存放寄生线程的代码。
3.写入线程代码,使用WriteProcessMemory函数把寄生线程的代码写入刚才在宿主进程中分配的代码空间。
4.分配数据空间,在远程进程的堆空间中分配一块区域用于存放寄生线程的数据资源。
5.写入线程参数,把寄生线程的启动参数及其他数据资源写入刚才分配的数据空间。
6.创建远程线程,使用CreateRemoteThread创建远程线程,可以获得此线程的ID和句柄。
7.释放无用资源,关闭过时的进程句柄和线程句柄。
五、算法及实验步骤:
程序流程图:
主程序流程:
注入线程流程:
函数和数据结构分析:
用到的Windows API:
BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb,
DWORD* pBytesReturned)
程序描述:获取系统中的所有进程对象
返回值:
函数执行成功,返回真(非零),否则返回假
参数:
pProcessIds:用来记录返回数据
cb:pProcessIds的大小
pBytesReturned:返回数据在pProcessIds中的大小
HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle,
DWORD dwProcessId)
程序描述:打开一个已存在的进程对象,并返回进程的句柄
返回值:
成功,返回值为指定进程的句柄。
失败,返回值为空,可调用GetLastError获得错误代码。
参数:
dwDesiredAccess:访问标识
bInheritHandle:句柄继承选项
dwProcessId :进程ID
BOOL EnumProcessModules(HANDLE hProcess, HMODULE* lphModule,
DWORD cb, LPDWORD lpcbNeeded)
程序描述:返回某个进程的模块信息
返回值:
成功,返回值为真。
失败,返回值为假,可调用GetLastError获得错误代码。
参数:
hProcess:进程句柄
lphModule:用来存储进程模块信息的数组
cb: lphModule的大小
lpcbNeeded:实际返回的模块大小
DWORD GetModuleBaseName(HANDLE hProcess, HMODULE lphModule,
LPSTR lpBaseName, DWORD nSize)
程序描述:获取进程模块信息中的名称
返回值:
成功,返回值为真。
失败,返回值为假,可调用GetLastError获得错误代码。
参数:
hProcess:进程句柄
lphModule:进程模块信息的数组
lpBaseName: 存储返回的名称的字符串指针
nSize:获取到的字符指针的大小
HANDLE GetCurrentProcess()
程序描述:获取当前进程的一个伪句柄
返回值:
成功,当前进程的伪句柄。
失败,返回值为空。
BOOL OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess,
PHANDLE TokenHandle)
程序描述:获取进程访问令牌的句柄
返回值:
成功,返回值为真。失败,返回值为假。
参数:
ProcessHandle: 要修改访问权限的进程句柄
DesiredAccess: 要进行的操作类型
TokenHandle: 返回的访问令牌指针
BOOL LookupPrivilegeValue(LPCTSTR lpSystemName, LPCTSTR lpName,
PLUID lpLuid)
程序描述:查看系统权限的特权值,返回到LUID结构体中
返回值:
成功,返回值为真。失败,返回值为假。
参数:
lpSystemName: 要查看的系统,本地系统直接用NULL
lpName: 要查看的特权信息的名称
lpLuid: 用于接收所返回的指定特权名称的信息
BOOL AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges,
PTOKEN_PRIVILEGES NewState, DWORD BufferLength,
PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength,)
程序描述:启用或禁止指定访问令牌的特权
返回值:
成功,返回值为真。失败,返回值为假。
参数:
TokenHandle: 包含特权的句柄
DisableAllPrivileges:禁用所有权限标志
NewState: 新特权信息的指针
BufferLength: 新特权信息的大小
PreviousState: 接收被改变特权当前状态的Buffer
ReturnLength: 接收的PreviousState缓存区要求的大小
DWORD GetModuleFileName(HMODULE hModule, LPSTR lpFilename,DWORD nSize)
程序描述:获取一个已装载模块的完整路径名称
返回值:
成功,返回复制到lpFilename的实际字符数量。失败,返回假。
参数:
hModule: 模块句柄
lpFilename: 用来存储返回路径的字符串缓冲区
nSize: 装载到缓冲区的最大字符数量
LPVOID VirtualAllocEx (HANDLE hProcess, LPVOID lpAddress,SIZE_T dwSize,
DWORD flAllocationType, DWORD flProtect)
程序描述:在指定进程的虚拟空间保留或提交内存区域
返回值:
成功,返回内存区域的首地址。失败,返回空。
参数:
hProcess: 申请内存所在进程句柄
lpAddress: 保留页面的内存地址,NULL自动分配
dwSize: 欲分配的内存大小
flAllocationType: 内存分配选项
flProtect: 区域的访问权限
DWORD WriteProcessMemory (HANDLE hProcess, LPVOID lpBaseAddress,
LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten)
程序描述:写入某一进程的内存区域
返回值:
成功,返回真。失败,返回假。
参数:
hProcess: 要写入进程的句柄
lpBaseAddress: 要写入的内存首地址
lpBuffer: 要写的数据指针
nSize: 要写入的字节数
lpNumberOfBytesWritten: 实际写入的字节数
HMODULE GetModuleHandle (LPCSTR lpModuleName)
程序描述:获取一个应用程序或动态链接库的句柄
返回值:
成功,返回模块句柄。失败,返回假。
参数:
lpModuleName: 指定模块名
DWORD GetCurrentProcessId ()
程序描述:获取当前进程的标识符
返回值:
成功,返回当前进程的标识符。失败,返回假。
FARPROC GetProcAddress (HMODULE hModule, LPCSTR lpProcName)
程序描述:检索指定的动态链接库(DLL)中的输出库函数地址
返回值:
成功,返回DLL中的输出函数地址。失败,返回空。
参数:
hModule: DLL模块句柄
lpProcName: 函数名
HANDLE CreateRemoteThread(HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
)
程序描述:创建远程线程
返回值:
成功,返回新线程句柄。失败,返回空。
参数:
hProcess: 线程所属进程的进程句柄
lpThreadAttributes: 线程的安全属性
dwStackSize: 线程初始大小
lpStartAddress: 在远程进程的地址空间中,线程函数的起始地址
lpParameter: 传给线程函数的参数
dwCreationFlags: 线程创建标识
lpThreadId : 线程IPD
主进程的主要函数:
DWORD processtopid(char * processname); //获取进程名对应的PID
BOOL EnablePriv(); //提升当前进程的权限,取得远程写入目标进程的特权
HANDLE CreateRemoteThreadProc(char * ProcessName); //线程注入主函数
自定义的数据结构:
为了便于远程线程代码的API的重定位,构造下面的struct结构
typedef struct _remoteparameter
{
DWORD rpWaitForSingleObject;
DWORD rpOpenProcess;
DWORD rpWinExec;
DWORD rpProcessPID;
HANDLE rpProcessHandle;
char path[MAX_PATH];
}REMOTEPARAM;
六、调试结果及实验结果:
程序执行结果及截图
在程序中CreateRemoteThreadProc函数的参数是"notepad.exe",即要注入的是记事本的程序,所以首先我们打开一个文本文件,发现这时在任务管理器中NODEPAD.EXE的PID是2840,然后我们运行我们的主程序,首先查找到NODEPAD.EXE的PID也是2840(控制台程序的第一行),之后依次执行:打开远程进程,分配内存,写入到远程进程(NODEPAD.EXE)的内存空间,创建远程线程。
之后只要我们不关闭NODEPAD.EXE,就无法关闭我们的控制台程序(每次我们关闭控制台程序,注入到NODEPAD.EXE中的线程就会再次启动我们的控制台程序)。
七、总结:
一直对木马和病毒的原理比较感兴趣,在大一时买的《黑客防线》,由于当时基础知识和编程能力都不是很强,所以对于上面的好多程序和原理都不是很明白,也有好多语言方面的知识都没有涉猎,大三刚开学的时候,重新翻出了这本书,发现里面的好多内容已经可以看懂了,而且有些基础的东西自己已经在这两年中掌握了,于是开始研究其中的若干章节,例如:利用程序操作系统服务、单实例运行、注册表管理、线程注入等等,于是自己的编程能力和底层只是又有了一定的提高,这次的程序主要也是参考这本书线程守护这一章的内容,此外,相关函数的用法参考了百度百科和MSDN ,另外又通过网络查询了线程注入技术的一些其他方面的应用,感觉收获颇丰。
八、参考文献:
1.《黑客防线-黑客编程VC专辑》
2.百度百科
3.百度文库(线程注入技术——应用)
4.
5.
6.
展开阅读全文