一 被注入的目标程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <iostream> #include <Windows.h> // 默认是__cdecl调用约定,须手动平栈 void remote() { printf("无参的远程线程执行\n"); } // __cdecl调用约定,须手动平栈 int __cdecl remote2(int a) { printf("有参远程线程执行。a=%d\n", a); return a; } // __stdcall调用约定,自动平栈 int __stdcall remote3(int a, int b) { printf("两参远程线程执行。a=%d,b=%d\n", a, b); return a + b; } int main() { printf("remote pid=%d,remote函数内存地址=%p,remote2函数内存地址=%p, remote3函数内存地址=%p \n", GetCurrentProcessId(), remote, remote2, remote3); getchar(); } |
二 注入器程序
0.获取目标进程PID
windows 7
win7上,演示程序直接启动为命令提示符独立程序,FindWindow配合GetWindowThreadProcessId拿到的PID和任务管理器中看到的一致,可用。
1 2 3 4 5 6 7 8 |
LPCWSTR lpWindowName = L"路径\\App01-STD.exe"; // 程序运行后显示的标题 HWND windowHandler = FindWindowW(NULL, lpWindowName); printf("目标窗口句柄 %p\n", windowHandler); // ULONG pid, tid; tid = GetWindowThreadProcessId(windowHandler, &pid); printf("目标进程ID %d\n", pid); // 这个pid可用 printf("目标线程ID %x\n", tid); // |
windows 10
在win10上,命令提示符是一个父窗体,演示程序启动为它的一个标签。标题栏属性不好用了。
如下代码直接使用目标程序的真实PID。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
ULONG pid = 17344; // 目标程序可用的pid LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)0x4113ED; // 目标进程的函数地址 HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); HANDLE hThread = CreateRemoteThread( process, // ●hProcess 目标进程句柄.在其中创建线程 NULL, // lpThreadAttributes 新线程的安全描述符,并确定子进程是否可以继承返回的句柄。 0, // dwStackSize 新线程栈初始大小,以字节为单位。0=使用系统默认大小. lpStartAddress, // ●lpStartAddress 远程进程中线程的起始地址,必须存在于远程进程中 NULL, // ●lpParameter 传递给线程函数的参数的指针。 0, // dwCreationFlags 控制线程创建的标志。0=线程在创建后立即运行。 NULL // lpThreadId 指向接收线程标识符的变量的指针。 ); // 如果调用成功,返回新线程句柄. DWORD error = GetLastError(); // 0=无错 printf("错误:%d\n", error); CloseHandle(process); getchar(); |
查找目标进程
如下代码通过快照获取目标进程,测试windows7和windows10都成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#include <iostream> #include <windows.h> #include <Tlhelp32.h> // 创建进程快照需要包含头文件 //typedef struct tagPROCESSENTRY32 { // DWORD dwSize; //进程信息结构体大小, 首次调用之前必须初始化 // DWORD cntUsage; //引用进程的次数, 引用次数为0时, 则进程结束 // DWORD th32ProcessID; //进程的ID // ULONG_PTR th32DefaultHeapID;//进程默认堆的标识符, 除工具使用对我们没用 // DWORD th32ModuleID; //进程模块的标识符 // DWORD cntThreads; //进程启动的执行线程数 // DWORD th32ParentProcessID; //父进程ID // LONG pcPriClassBase; //进程线程的基本优先级 // DWORD dwFlags; //保留 // TCHAR szExeFile[MAX_PATH]; //进程的路径 //} PROCESSENTRY32; /// <summary> /// 根据程序文件名,获取其进程PID /// </summary> /// <param name="key">目标程序的文件名</param> /// <returns>进程PID</returns> DWORD getProcess(LPCWSTR key) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hSnapshot) { return 0; } PROCESSENTRY32 pi; pi.dwSize = sizeof(PROCESSENTRY32); //第一次使用必须初始化成员 BOOL bRet = Process32First(hSnapshot, &pi); DWORD childPid = 0; while (bRet) { DWORD pid = pi.th32ProcessID; std::wstring childPath = pi.szExeFile; if (childPath.find(key) != childPath.npos) { childPid = pid; printf("找到目标子进程ID=%d,路径=%ls \n", childPid, childPath.c_str()); break; } bRet = Process32Next(hSnapshot, &pi); } return childPid; } |
1.注入无参函数
注意编译平台,和目标程序统一为x86或x64,还要统一release或debug版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <iostream> #include <windows.h> #include <Tlhelp32.h> #include <string> /// 根据程序文件名,获取其进程PID DWORD getProcess(LPCWSTR key) { // 略 } /// <summary> /// 远程注入调用其它进程没有参数的函数 /// </summary> /// <param name="process">目标进程PID</param> void remoteNoneArgMethod(HANDLE process) { LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)0x4113ED; HANDLE hThread = CreateRemoteThread( process, // ●hProcess 目标进程句柄.在其中创建线程 NULL, // lpThreadAttributes 新线程的安全描述符,并确定子进程是否可以继承返回的句柄。 0, // dwStackSize 新线程栈初始大小,以字节为单位。0=使用系统默认大小. lpStartAddress, // ●lpStartAddress 远程进程中线程的起始地址,必须存在于远程进程中 NULL, // ●lpParameter 传递给线程函数的参数的指针。 0, // dwCreationFlags 控制线程创建的标志。0=线程在创建后立即运行。 NULL // lpThreadId 指向接收线程标识符的变量的指针。 ); // 如果调用成功,返回新线程句柄. DWORD error = GetLastError(); // 0=无错 printf("调用无参函数错误:%d\n", error); printf("~~~~~~~~~~~~~~~~~~~~~~~~\n"); } int main() { DWORD pid = getProcess(L"App01-STD"); if (0 == pid) { printf("未找到目标进程"); return 0; } HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); remoteNoneArgMethod(process); CloseHandle(process); getchar(); } |
2.注入1参函数
注意和目标程序统一为x86或x64,还要统一release或debug版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include <iostream> #include <windows.h> #include <Tlhelp32.h> // 创建进程快照需要包含头文件 DWORD getProcess(LPCWSTR key) { // 略 } /// <summary> /// 远程注入调用其它进程没有参数的函数 /// </summary> /// <param name="process">目标进程PID</param> void remoteOneArgMethod(HANDLE process) { LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)0x411046; int lpParameter = 19; HANDLE hThread = CreateRemoteThread( process, NULL, 0, lpStartAddress, (LPVOID)lpParameter, 0, NULL); DWORD error = GetLastError(); // 0=无错 printf("调用一参函数错误:%d\n", error); printf("~~~~~~~~~~~~~~~~~~~~~~~~\n"); } int main() { DWORD pid = getProcess(L"App01-STD"); if (0 == pid) { printf("未找到目标进程"); return 0; } HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); remoteOneArgMethod(process); CloseHandle(process); getchar(); } |
3.注入多参函数
注意和目标程序统一为x86或x64,还要统一是 release 版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include <iostream> #include <windows.h> #include <Tlhelp32.h> DWORD getProcess(LPCWSTR key) { // 略 } typedef struct _RemoteMethodAndArgs { DWORD method; // 目标进程的目标函数 int arg_a; // 目标函数的参数 int arg_b; // 目标函数的参数 }RemoteMethodAndArgs; // 注入器函数 void _stdcall MethodInjector(RemoteMethodAndArgs* methodAndArgs) { int a = methodAndArgs->arg_a; a++; typedef int(WINAPI* method_remote)(int, int); // 声明一个‘局部函数’,“结构”和目标函数一致 method_remote method; // 局部函数实例 method = (method_remote)methodAndArgs->method; // 局部函数指向目标函数 method(a, methodAndArgs->arg_b); // 调用函数 //printf("abc"); // 这个注入器函数内,不能有其它函数调用 } // 远程注入 void remoteTwoArgsMethod(HANDLE process) { //【首先】把注入器函数写入远程 const DWORD THREADSIZE = 4096; // 注入器函数占用的内存空间大小,足够大即可 // 在目标进程为注入器申请内存,返回的即注入器函数的地址 LPTHREAD_START_ROUTINE remoteThread = (LPTHREAD_START_ROUTINE)VirtualAllocEx(process, 0, THREADSIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!remoteThread) { printf("申请内存失败"); return; } // 将注入器写入内存 BOOL writed = WriteProcessMemory(process, remoteThread, &MethodInjector, THREADSIZE, 0); if (!writed) { printf("写入内存失败"); return; } //【然后】把参数数据写入远程 RemoteMethodAndArgs args; ZeroMemory(&args, sizeof(RemoteMethodAndArgs)); args.method = 0x401070; // 目标进程的目标函数 args.arg_a = 4; // 目标函数的参数 args.arg_b = 3; // 目标函数的参数 // 申请内存 RemoteMethodAndArgs* remoteData = (RemoteMethodAndArgs*)VirtualAllocEx(process, 0, sizeof(RemoteMethodAndArgs), MEM_COMMIT, PAGE_READWRITE); if (!remoteData) { printf("申请内存失败"); return; } // 写入内存 writed = WriteProcessMemory(process, remoteData, &args, sizeof(args), 0); if (!writed) { printf("写入内存失败"); return; } //【最后】调用已经在远程进程中的“注入器” DWORD byte_write; HANDLE hThread = CreateRemoteThread( process, // 目标进程 0, 0, remoteThread, // 已经注入的“注入器”函数 remoteData, // 参数 0, &byte_write); printf("子线程:%d", byte_write); } int main() { DWORD pid = getProcess(L"App01-STD"); //DWORD pid = getProcess(L"Feige"); if (0 == pid) { printf("未找到目标进程"); return 0; } HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); remoteTwoArgsMethod(process); CloseHandle(process); getchar(); } |
- end
声明
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/4441.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设