一天学硬件,一天学软件。哈~正所谓【软硬兼施】啊。今天轮到学软件了,由于之前对DLL木马有一些研究,大部分木马都是通过远程线程注入的方式实现无进程执行。早就想学 这种技术了,无奈当时自身的编程技术还不到那个境界,现在试试。。。
花了一下午的时间, 查询相关资料,看视频 教程,大概给弄懂怎么回事了。就是将木马的实现功能全部写在一个DLL中(DLL 也是可执行文件,但是不可以直接执行,需要EXE调用),然后找个目标进程(一般是IE进程,突破防火墙~),将自身路径写入到该进程空间内,然后在该进程中寻找LoadLibraryA()这个加载DLL 的函数地址,通过远程线程函数使该进程执行LoadLibraryA()这个加载函数,加载DLL。 直白点,就是先将DLL的路径写入到目标进程空间内,然后在目标进程空间内寻找 LoadLibraryA()这个函数的地址,再利用LoadLibraryA()这个函数调用木马的DLL。相当于执行了木马...然后木马就可以随意的xxoxoxox你的电脑了~
远程线程注入的细分过程 共可分5 步:
1、通过进程PID 打开目标进程获得目标进程句柄。(为了能操作该进程就要获得它的句柄)
利用到的API: HANDLE OpenProcess( DWORD dwDesiredAccess,BOOL bInheritHandle, DWORD dwProcessId);
功能:OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。
函数原型:
HANDLE OpenProcess( DWORD dwDesiredAccess, //权限
BOOL bInheritHandle, // 是否继承句柄
DWORD dwProcessId // 目标进程的PID标识符
);
返回值: 如成功,返回值为指定进程的句柄。 如失败,返回值为空,可调用GetLastError获得错误代码。
2、根据上面提供的目标进程句柄在其申请一块内存空间。(用于存放DLL的完整路径)
利用到的API:LPVOID VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType, DWORD flProtect )
功能:VirtualAllocEx 函数的作用是在指定进程的虚拟空间保留或提交内存区域,除非指定MEM_RESET参数,否则将该内存区域置0。
函数原形:
LPVOID VirtualAllocEx(
HANDLE hProcess, // 进程句柄
LPVOID lpAddress, // 获取内存空间的区域
SIZE_T dwSize, // 要获取空间的大小
DWORD flAllocationType, // 内存分配的类型
DWORD flProtect // 内存页保护
);
返回值:执行成功就返回分配内存的首地址,不成功就是NULL。
3、将DLL的路径写入到目标进程内申请的内存空间。(因为进程间是有边界的,不能互相访问彼此的内存空间)
利用到的API:BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten );
功能: 此函数能写入某一进程的内存区域(直接写入会出Access Violation错误,故需此函数)。
函数原形:
BOOL WriteProcessMemory(
HANDLE hProcess, // 进程句柄
LPVOID lpBaseAddress, // 内存空间分配的首地址
LPVOID lpBuffer, // 写入的内容
DWORD nSize, // 写入的内容大小
LPDWORD lpNumberOfBytesWritten // 不知道干嘛用 ...
);
返回值:非零值代表成功。
4、在目标进程中寻找LoadLibraryA()这个函数的函数地址。(找到函数地址才能调用它)
利用到的API: FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );
HMODULE GetModuleHandle ( LPCTSTR lpModuleName );
功能:GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。
函数原型:
FARPROC GetProcAddress(
HMODULE hModule, // DLL模块句柄
LPCSTR lpProcName // 函数名
);
返回值:
如果函数调用成功,返回值是DLL中的输出函数地址。
如果函数调用失败,返回值是NULL。得到进一步的错误信息,调用函数GetLastError。
说明:GetModuleHandle 获取一个应用程序或动态链接库的模块句柄
参数:lpModuleName 模块名称 如果参数是NULL 则获取自身句柄
返回值:如执行成功成功,则返回模块句柄。零表示失败。通过GetLastError获得错误信息
5、创建远程线程,根据上面找到LoadLibraryA()的函数地址,调用该函数,LoadLibraryA()函数的参数就是目标进程中的DLL路径 (这时就是执行我们的DLL 了)
利用到的API:HANDLE WINAPI CreateRemoteThread( __in HANDLE hProcess, __in LPSECURITY_ATTRIBUTES lpThreadAttributes, __in SIZE_T dwStackSize, __in LPTHREAD_START_ROUTINE lpStartAddress, __in LPVOID lpParameter, __in DWORD dwCreationFlags, __out LPDWORD lpThreadId );
功能:创建一个在其它进程地址空间中运行的线程(也称:创建远程线程).
函数原型:
HANDLE WINAPI CreateRemoteThread(
1 __in HANDLE hProcess, // 目标进程句柄
__in LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性
__in SIZE_T dwStackSize, // 线程栈初始大小
__in LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数
__in LPVOID lpParameter, // 线程参数
__in DWORD dwCreationFlags, // 创建的标志 (立即执行、挂起等)
__out LPDWORD lpThreadId // 线程句柄
);
返回值: 如果调用成功,返回新线程句柄.
如果失败,返回NULL.
具体实现代码:(EXE)
======================================================================================================
#include <windows.h>
#include <stdio.h>
BOOL InjectDll(char *DllPath, DWORD dwProcessID)
{
if ( (DllPath == NULL) && (dwProcessID < 0))
return FALSE;
// 1、打开目标进程获得目标进程句柄 // 权限 ,句柄继续承,加成PID
HANDLE hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,0,dwProcessID);
if (hRemoteProcess == NULL)
return FALSE;
// 2、通过目标进程句柄在其申请一块内存空间 // 进程句柄,获取内存地址区域,分配的内存大小,内存分配的类型,内存页保护
LPVOID RemoteProcessSize = VirtualAllocEx(hRemoteProcess,NULL,strlen(DllPath)+1,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
if (RemoteProcessSize == NULL)
return FALSE;
// 3、将DLL的路径写入到目标进程内申请的内存空间
// 进程句柄,要写入的内存首地址,写入的内容,内容的大小,未知
BOOL bRet = WriteProcessMemory(hRemoteProcess,RemoteProcessSize,DllPath,strlen(DllPath)+1,0);
if(!bRet)
return FALSE;
// 4、将函数LoadLibraryA的入口地址作为我们的远程线程的入口地址
// 当远程线程启动时,就会调用LoadLibraryA 装载我们的DLL // 模块句柄 /*获取模块句柄(模块名)*/ ,函数名
PTHREAD_START_ROUTINE ScanLoad = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle("Kernel32.DLL"),"LoadLibraryA");
if (ScanLoad == NULL)
return FALSE;
/* 哈前天才刚从小凡那挖过来的知识点 没想到现在就用上了。再次感谢我家滴小凡!o(∩_∩)o 哈哈 PTHREAD_START_ROUTINE 这个其实是函数型指针,原型typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); 用来指向LoadLibraryA 函数 */
// 5、创建远程线程执行DLL 这里其实就是用LoadLibraryA 加载我们的DLL
HANDLE hRemoteThread = NULL;
// 目标进程句柄,线程安全属性,线程初始大小,线程函数(目标中的LoadLibraryA),函数参数(就是目标进程中的DLL路径),标志,线程句柄
hRemoteThread = CreateRemoteThread(hRemoteProcess,NULL,0,ScanLoad,RemoteProcessSize,0,0);
if(hRemoteThread == NULL)
return FALSE;
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
if (InjectDll("D:\\ssdddd.dll",1552)) // 传递DLL 完整路径和需要注入的目标进程的PID
MessageBox(0,"注入成功!","",MB_SYSTEMMODAL);
else
MessageBox(0,"注入失败!","",MB_SYSTEMMODAL);
}
========================================================================================================
这个是被调用的DLL:========================================================================================================
#include "windows.h"
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad) // 这是个回调函数 也是DLL 入口点
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH: // 进程被调用
MessageBox(NULL,"嘎嘎~DLL自身被调用~","进程被调用 ",MB_SYSTEMMODAL);
break;
case DLL_THREAD_ATTACH: // 线程被调用
MessageBox(NULL,"嘎嘎~目标程序启动了一个线程~","线程被调用 ",MB_SYSTEMMODAL);
break;
case DLL_PROCESS_DETACH: // 进程退出
MessageBox(NULL,"嘎嘎~目标进程退出~","进程退出",MB_SYSTEMMODAL);
break;
case DLL_THREAD_DETACH: // 线程退出
MessageBox(NULL,"嘎嘎~目标线程退出~","线程退出",MB_SYSTEMMODAL);
break;
}
return(TRUE);
}
========================================================================================================
远程线程注入还有其他的方式,好像是将要实现的功能函数直接写入到目标进程内,在明白进程内执行该函数...不过原理应该都是一样滴,远程线程注入还有其他的用处,例如外挂啊、破解补丁啊、等等...
嗯,这就是今天理解到的东西,刚接触,可能有些地方理解错了,请大家不要见笑哈,欢迎批评指正~ 有兴趣的童鞋可以加我的QQ:1007566569 共同探讨
等学会了远程线程注入,准备开始研究研究HOOK了,HOOK 更好玩~ 兴奋吖~~
花了一下午的时间, 查询相关资料,看视频 教程,大概给弄懂怎么回事了。就是将木马的实现功能全部写在一个DLL中(DLL 也是可执行文件,但是不可以直接执行,需要EXE调用),然后找个目标进程(一般是IE进程,突破防火墙~),将自身路径写入到该进程空间内,然后在该进程中寻找LoadLibraryA()这个加载DLL 的函数地址,通过远程线程函数使该进程执行LoadLibraryA()这个加载函数,加载DLL。 直白点,就是先将DLL的路径写入到目标进程空间内,然后在目标进程空间内寻找 LoadLibraryA()这个函数的地址,再利用LoadLibraryA()这个函数调用木马的DLL。相当于执行了木马...然后木马就可以随意的xxoxoxox你的电脑了~
远程线程注入的细分过程 共可分5 步:
1、通过进程PID 打开目标进程获得目标进程句柄。(为了能操作该进程就要获得它的句柄)
利用到的API: HANDLE OpenProcess( DWORD dwDesiredAccess,BOOL bInheritHandle, DWORD dwProcessId);
功能:OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。
函数原型:
HANDLE OpenProcess( DWORD dwDesiredAccess, //权限
BOOL bInheritHandle, // 是否继承句柄
DWORD dwProcessId // 目标进程的PID标识符
);
返回值: 如成功,返回值为指定进程的句柄。 如失败,返回值为空,可调用GetLastError获得错误代码。
2、根据上面提供的目标进程句柄在其申请一块内存空间。(用于存放DLL的完整路径)
利用到的API:LPVOID VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType, DWORD flProtect )
功能:VirtualAllocEx 函数的作用是在指定进程的虚拟空间保留或提交内存区域,除非指定MEM_RESET参数,否则将该内存区域置0。
函数原形:
LPVOID VirtualAllocEx(
HANDLE hProcess, // 进程句柄
LPVOID lpAddress, // 获取内存空间的区域
SIZE_T dwSize, // 要获取空间的大小
DWORD flAllocationType, // 内存分配的类型
DWORD flProtect // 内存页保护
);
返回值:执行成功就返回分配内存的首地址,不成功就是NULL。
3、将DLL的路径写入到目标进程内申请的内存空间。(因为进程间是有边界的,不能互相访问彼此的内存空间)
利用到的API:BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten );
功能: 此函数能写入某一进程的内存区域(直接写入会出Access Violation错误,故需此函数)。
函数原形:
BOOL WriteProcessMemory(
HANDLE hProcess, // 进程句柄
LPVOID lpBaseAddress, // 内存空间分配的首地址
LPVOID lpBuffer, // 写入的内容
DWORD nSize, // 写入的内容大小
LPDWORD lpNumberOfBytesWritten // 不知道干嘛用 ...
);
返回值:非零值代表成功。
4、在目标进程中寻找LoadLibraryA()这个函数的函数地址。(找到函数地址才能调用它)
利用到的API: FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );
HMODULE GetModuleHandle ( LPCTSTR lpModuleName );
功能:GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。
函数原型:
FARPROC GetProcAddress(
HMODULE hModule, // DLL模块句柄
LPCSTR lpProcName // 函数名
);
返回值:
如果函数调用成功,返回值是DLL中的输出函数地址。
如果函数调用失败,返回值是NULL。得到进一步的错误信息,调用函数GetLastError。
说明:GetModuleHandle 获取一个应用程序或动态链接库的模块句柄
参数:lpModuleName 模块名称 如果参数是NULL 则获取自身句柄
返回值:如执行成功成功,则返回模块句柄。零表示失败。通过GetLastError获得错误信息
5、创建远程线程,根据上面找到LoadLibraryA()的函数地址,调用该函数,LoadLibraryA()函数的参数就是目标进程中的DLL路径 (这时就是执行我们的DLL 了)
利用到的API:HANDLE WINAPI CreateRemoteThread( __in HANDLE hProcess, __in LPSECURITY_ATTRIBUTES lpThreadAttributes, __in SIZE_T dwStackSize, __in LPTHREAD_START_ROUTINE lpStartAddress, __in LPVOID lpParameter, __in DWORD dwCreationFlags, __out LPDWORD lpThreadId );
功能:创建一个在其它进程地址空间中运行的线程(也称:创建远程线程).
函数原型:
HANDLE WINAPI CreateRemoteThread(
1 __in HANDLE hProcess, // 目标进程句柄
__in LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性
__in SIZE_T dwStackSize, // 线程栈初始大小
__in LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数
__in LPVOID lpParameter, // 线程参数
__in DWORD dwCreationFlags, // 创建的标志 (立即执行、挂起等)
__out LPDWORD lpThreadId // 线程句柄
);
返回值: 如果调用成功,返回新线程句柄.
如果失败,返回NULL.
具体实现代码:(EXE)
======================================================================================================
#include <windows.h>
#include <stdio.h>
BOOL InjectDll(char *DllPath, DWORD dwProcessID)
{
if ( (DllPath == NULL) && (dwProcessID < 0))
return FALSE;
// 1、打开目标进程获得目标进程句柄 // 权限 ,句柄继续承,加成PID
HANDLE hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,0,dwProcessID);
if (hRemoteProcess == NULL)
return FALSE;
// 2、通过目标进程句柄在其申请一块内存空间 // 进程句柄,获取内存地址区域,分配的内存大小,内存分配的类型,内存页保护
LPVOID RemoteProcessSize = VirtualAllocEx(hRemoteProcess,NULL,strlen(DllPath)+1,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
if (RemoteProcessSize == NULL)
return FALSE;
// 3、将DLL的路径写入到目标进程内申请的内存空间
// 进程句柄,要写入的内存首地址,写入的内容,内容的大小,未知
BOOL bRet = WriteProcessMemory(hRemoteProcess,RemoteProcessSize,DllPath,strlen(DllPath)+1,0);
if(!bRet)
return FALSE;
// 4、将函数LoadLibraryA的入口地址作为我们的远程线程的入口地址
// 当远程线程启动时,就会调用LoadLibraryA 装载我们的DLL // 模块句柄 /*获取模块句柄(模块名)*/ ,函数名
PTHREAD_START_ROUTINE ScanLoad = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle("Kernel32.DLL"),"LoadLibraryA");
if (ScanLoad == NULL)
return FALSE;
/* 哈前天才刚从小凡那挖过来的知识点 没想到现在就用上了。再次感谢我家滴小凡!o(∩_∩)o 哈哈 PTHREAD_START_ROUTINE 这个其实是函数型指针,原型typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); 用来指向LoadLibraryA 函数 */
// 5、创建远程线程执行DLL 这里其实就是用LoadLibraryA 加载我们的DLL
HANDLE hRemoteThread = NULL;
// 目标进程句柄,线程安全属性,线程初始大小,线程函数(目标中的LoadLibraryA),函数参数(就是目标进程中的DLL路径),标志,线程句柄
hRemoteThread = CreateRemoteThread(hRemoteProcess,NULL,0,ScanLoad,RemoteProcessSize,0,0);
if(hRemoteThread == NULL)
return FALSE;
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
if (InjectDll("D:\\ssdddd.dll",1552)) // 传递DLL 完整路径和需要注入的目标进程的PID
MessageBox(0,"注入成功!","",MB_SYSTEMMODAL);
else
MessageBox(0,"注入失败!","",MB_SYSTEMMODAL);
}
========================================================================================================
这个是被调用的DLL:========================================================================================================
#include "windows.h"
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad) // 这是个回调函数 也是DLL 入口点
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH: // 进程被调用
MessageBox(NULL,"嘎嘎~DLL自身被调用~","进程被调用 ",MB_SYSTEMMODAL);
break;
case DLL_THREAD_ATTACH: // 线程被调用
MessageBox(NULL,"嘎嘎~目标程序启动了一个线程~","线程被调用 ",MB_SYSTEMMODAL);
break;
case DLL_PROCESS_DETACH: // 进程退出
MessageBox(NULL,"嘎嘎~目标进程退出~","进程退出",MB_SYSTEMMODAL);
break;
case DLL_THREAD_DETACH: // 线程退出
MessageBox(NULL,"嘎嘎~目标线程退出~","线程退出",MB_SYSTEMMODAL);
break;
}
return(TRUE);
}
========================================================================================================
远程线程注入还有其他的方式,好像是将要实现的功能函数直接写入到目标进程内,在明白进程内执行该函数...不过原理应该都是一样滴,远程线程注入还有其他的用处,例如外挂啊、破解补丁啊、等等...
嗯,这就是今天理解到的东西,刚接触,可能有些地方理解错了,请大家不要见笑哈,欢迎批评指正~ 有兴趣的童鞋可以加我的QQ:1007566569 共同探讨
等学会了远程线程注入,准备开始研究研究HOOK了,HOOK 更好玩~ 兴奋吖~~