前言

这几天在弄进程注入的事情,一直做不出来直接的进程注入,也就是不要dll的注入。因为dll注入据说容易触发杀软,但是弄了两天没弄出来。代码明明不报错,目标进程一旦注入就崩溃,完全没有提示信息,windows日志也没有什么有价值的线索。所以今天就尝试了dll注入,结果一次成功了。。。

前提

  • 进程间内存独立

运行在安全模式下的Windows,每个进程的内存空间都是独立的,互相不能访问彼此,所以代码注入才是一件比较麻烦的事情

  • 所有进程中 kernel32.dll地址相同

每个进程都会加载kernel32.dll,并且在那些进程中,这个库的地址都是一样的

原理

dll注入主要分为如下几个步骤

  • 提权:如果不提权的话,进程列表中很多进程是打不开的,并且可能获取不到PROCESS_ALL_ACCESS权限
  • 获取PID:这部分不是必须的,但是PID每次运行都不一样,所以最好能获取,这里通过CreateToolhelp32Snapshot()函数获取进程,遍历结果之后得到对应的PID
  • 打开进程:通过OpenProcess()函数打开进程,同时指定权限是PROCESS_ALL_ACCESS权限,否则后面操作会失败,如果要获取这个权限就得先提权
  • 通过VirtualAllocEx()函数在目标进程中申请内存,然后用WriteProcessMemory()函数将LoadLibraey()函数的参数准备好写入到内存中
  • 通过LoadLibrary()函数加载kernel32.dll,实际上进程都会加载这个,第二次加载似乎直接获取模块句柄了。
  • 通过GetProcAddress()函数获取到LoadLibraryW()函数的地址,因为kernel32.dll在所有进程中的地址都相同,所以,在本进程中获取的函数地址在目标进程中也是那个函数
  • 通过CreateRemoteThread()函数在目标进程中创建一个线程,执行LoadLibraryW()函数载入自己的dll

代码

  • 注入代码
#include <windows.h>
#include <iostream>
#include <tlhelp32.h> using namespace std; DWORD GetPidByName(LPCWSTR lpName)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if (!hSnap)
{
cout << "创建进程快照失败" << endl;
return 0;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap, &pe);
do
{
if (!_wcsicmp(lpName, pe.szExeFile))
{
return pe.th32ProcessID;
}
} while (Process32Next(hSnap,&pe));
return 0;
} // 提权
int EnableDebugPrivilege()
{
HANDLE token;
TOKEN_PRIVILEGES tp;
// 打开进程令牌环
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
{
cout << "打开进程令牌失败" << endl;
return 0;
}
// 获取进程本地唯一ID
LUID luid;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
cout << "获取LUID失败" << endl;
return 0;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
// 调整进程权限
if (!AdjustTokenPrivileges(token, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
cout << "提权失败" << endl;
return 0;
}
return 1;
} int main()
{
if (!EnableDebugPrivilege())
{
cout << "提权失败"<<endl;
return 0;
}
DWORD dwTargetPid = GetPidByName(L"notepad.exe");
if (!dwTargetPid)
{
cout << "获取PID失败" << endl;
return 0;
}
cout << "PID: " << dwTargetPid << endl; // 打开进程
HANDLE hTarget = OpenProcess(PROCESS_ALL_ACCESS,false,dwTargetPid);
if (!hTarget)
{
cout << "打开进程失败"<<GetLastError() << endl;
return 0;
} void* pLoadLibFuncParam = nullptr;
pLoadLibFuncParam = VirtualAllocEx(hTarget,0,4096,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
if (pLoadLibFuncParam == nullptr)
{
cout << "申请内存失败" << endl;
CloseHandle(hTarget);
return 0;
} LPCTSTR lpParam = L"D:\\1.dll";
if (!WriteProcessMemory(hTarget, pLoadLibFuncParam, (LPCVOID)lpParam, (wcslen(lpParam)+1)*sizeof(TCHAR), NULL))
{
cout << "写入内存失败" << endl;
CloseHandle(hTarget);
return 0;
}
HMODULE hNtdll = LoadLibrary(L"kernel32.dll");
if (!hNtdll)
{
cout << "加载模块错误" <<GetLastError()<< endl;
CloseHandle(hTarget);
return 0;
}
cout << "模块句柄: " << hNtdll << endl;
void* pLoadLibrary = nullptr;
pLoadLibrary = GetProcAddress(hNtdll, "LoadLibraryW");
if (pLoadLibrary == nullptr)
{
cout << "找不到函数" << endl;
CloseHandle(hTarget);
return 0;
}
cout << "函数地址: " << pLoadLibrary << endl;
DWORD dwThreadId = 0;
HANDLE hRemoteThread = CreateRemoteThread(hTarget, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, (LPVOID)pLoadLibFuncParam, 0,&dwThreadId);
if (!hRemoteThread)
{
cout << "创建进程失败" << endl;
CloseHandle(hTarget);
return 0;
}
cout<<"运行结束"<< hRemoteThread <<endl;
getchar();
getchar();
CloseHandle(hTarget);
return 0;
}
  • DLL中的代码

代码编译之后,放到D:\1.dll的位置

DWORD WINAPI ThreadProc()
{
MessageBox(NULL,L"我已成功打入敌人内部 By Startu",L"报告首长",0);
return 0;
} BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)ThreadProc,NULL,0,NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

一些问题

  • 为什么是LoadLibraryW()

我最开始获取的函数是LoadLibrary()函数,但是实际上这个函数并不存在,这个只是一个宏,在windows中,有两个函数LoadLibraryW()LoadLibraryA()分别用于,不同的编码

  • 为什么需要在目标进程中申请地址存放参数

当代码被注入到目标进程之后,实际上这段代码算是目标进程的,如果直接传入参数的本质是传入地址,直接在本进程中传入地址,

  • 调试问题

dll中的代码,所有的printf() 或者 cout的输出都看不到,曾经我诧异了很久,直到突然想起来,这里的输出都应该是由宿主程序输出的,但是宿主程序没有控制台,所以就看不到了。这种时候 MessageBox()就要用到了。另外,通过 命令行rundll32 1.dll func的方式可以加载dll,执行里面的函数

[C++] 进程注入dll版的更多相关文章

  1. windows目标进程注入dll

    在别的程序注入dll 步骤: ,获取目标进程ID,CreateToolhelp32Snapshot()函数; ,获取目标进程句柄,OpenProcess()函数; ,目标进程要一块内存,Virtual ...

  2. Wow64(32位进程)注入DLL到64位进程

    转载自: https://blog.poxiao.me/p/wow64-process-inject-dll-into-x64-process/ 向其他进程注入DLL通常的做法是通过调用CreateR ...

  3. 《windows核心编程系列》十九谈谈使用远程线程来注入DLL。

    windows内的各个进程有各自的地址空间.它们相互独立互不干扰保证了系统的安全性.但是windows也为调试器或是其他工具设计了一些函数,这些函数可以让一个进程对另一个进程进行操作.虽然他们是为调试 ...

  4. Windows x86/ x64 Ring3层注入Dll总结

    欢迎转载,转载请注明出处:http://www.cnblogs.com/uAreKongqi/p/6012353.html 0x00.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线 ...

  5. 详细解读:远程线程注入DLL到PC版微信

    一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 LoadLibrary() 函数,可以 ...

  6. 分析恶意驱动(进程启动apc注入dll)

    一.前言  用IDA也有好些时间了,以前就只会用F5功能玩无壳无保护的裸驱动,感觉太坑了,这两天就开始看网上大牛的逆向. 今天记录一下sudami曾经逆向过的fuck.sys.第一遍自己走的时候漏掉了 ...

  7. Hook任务栏时钟窗口(原理其实很简单,就是注入DLL到时钟窗口进程(explorer.exe))

    用过一些日历软件的小伙伴应该都知道它们都实现了在时钟窗口上的Hook,也就是屏蔽了系统原有的功能,实现自己的功能 某日历软件Hook时钟窗口后的效果 经过一番研究,发现原理其实很简单,就是注入DLL到 ...

  8. 微信 电脑版 HOOK(WeChat PC Hook)- 远程线程注入dll原理

    Windows加载dll的特性 1.Windows系统中,每个exe软件运行的时候,会加载系统模块kernel32.dll 2.所有加载进exe软件的系统模块kernel32.dll,内存地址都是一样 ...

  9. 通过修改EIP寄存器实现强行跳转并且注入DLL到目标进程里

    /* 描述 功能:通过修改EIP寄存器实现32位程序的DLL注入(如果是64位,记得自己对应修改汇编代码部分) 原理: 挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,然后把相关的指令机器 ...

  10. 使用远程线程来注入DLL

    使用远程线程来注入DLL DLL注入技术要求我们目标进程中的一个线程调用LoadLibrary来载入我们想要的DLL (1)用OpenProcess函数打开目标进程(2)用VirtualAllocEx ...

随机推荐

  1. vue2-vue3监听子组件的生命周期的两种方式

    1.生命周期 生命周期是指:vue实例从创建到销毁这一系列过程.vue官网生命周期如下图所示: vue的生命周期有多少个 beforeCreate, created, beforeMount, mou ...

  2. docker 发布web项目到linux

    一.准备工作 1.连接到Liunx的工具 MobaXterm 填好Ip 直接点ok就行 输入用户名和密码进入系统 2.已发布的.netcore网站或微服务 在要发布的项目上右键---->添加-- ...

  3. CreateProcess函数源码分析

    CreateProcess函数源码分析 ​ 源码版本:Windows 2003 源码 ​ 源码阅读工具:Source Insight 函数功能分析 函数原型 BOOL CreateProcessA( ...

  4. c++基础之函数

    距离上次更新又过了一周,又该更新新的读书笔记了.本次更新的主要是c++中函数部分的内容 c++ 中的函数与c语言中的函数大致用法或者语法是一样的,这里就不就这点详细展开了.需要注意的是c/c++中并没 ...

  5. TienChin 渠道管理-配置校验失败信息

    新建 ValidationMessages.properties: channel.name.notnull=渠道名称不能为空 channel.type.notnull=渠道类型不能为空 channe ...

  6. HarmonyOS实战[二]—超级详细的原子化服务体验[可编辑的卡片交互]快来尝试吧

    相关文章: HarmonyOS实战[一]--原理概念介绍安装:基础篇 [本文正在参与"有奖征文|HarmoneyOS征文大赛"活动] 1.创建HarmonyOS应用 选择Java程 ...

  7. 你天天用4G 这些基本常识都知道吗?

    不少朋友在选购4G智能手机的时候,经常可能会遇到这样的名词,五模十三频.五模十七频.双4G.移动4G.联通4G.那这些名词到底是什么意思呢?它们之间又有什么区别呢? 其实上面的这些说法其实都是比较具有 ...

  8. Linux服务器查看端口是否开启或占用

    一.查看端口是否启用 (1)lsof -i :8080 查看8080端口被哪个进程占用 (2)netstat -lnp|grep 8080 查看8080端口被哪个进程占用  (3)ss -nlap | ...

  9. NC223888 红色和紫色.md

    题目链接 题目 题目描述 漫长的生命总是无聊的.这天,小红和紫准备玩一个染色游戏. 她们拿出了一个有 \(n*m\) 个格子的网格,每个格子只能被染成红色或紫色.每个人可以任意选择一个格子染成红色和紫 ...

  10. NC23803 DongDong认亲戚

    题目链接 题目 题目描述 DongDong每年过春节都要回到老家探亲,然而DongDong记性并不好,没法想起谁是谁的亲戚(定义:若A和B是亲戚,B和C是亲戚,那么A和C也是亲戚),她只好求助于会编程 ...