动态加载dll的实现+远线程注入
1.在目标进程中申请内存
2.向目标进程内存中写入shellcode(没有特征,编码比较麻烦)
3.创建远线程执行shellcode
之前可以看到shellcode很难编写还要去依赖库,去字符串区等等很麻烦,为了让被注入代码更容易编写,最好的方法就是通过dll来编写
dll加载:
1.静态调用:通过在我们的程序中添加头文件,以及lib文件来完成调用,前提就是获取dll然后还有头文件
2.动态调用:仅仅只需要一个dll即可完成调用
先写个试一下
#include <Windows.h>
__declspec(dllexport) void Test(){
MessageBox(NULL, NULL, NULL, NULL);
}

可以看到我们的Test,但是这种方式会对Test进行名称粉碎,由c++编译器添加的,需要告诉编译器使用c的方式来命名函数,所以我们这么写,然后还需要指明函数参数的调用约定
1.__stdcall 标准 栈传参,函数内部(被调用者)平栈
2. __cdecl c 栈传参,函数外部(调用者)平栈
3. __fastcall 快速 寄存器传参
4. __thiscall 类的thiscall调用约定,使用ecx寄存器来传递this指针
extern "C"{
__declspec(dllexport) void __stdcall Test(){
MessageBox(NULL, NULL, NULL, NULL);
}
}

上面写到__stdcall是函数内部平参这里来看看
void __stdcall test(int n1, int n2){
return;
}
int main()
{
test(1, 2);
return 0;
}
两个返回8一个返回4
void __stdcall test(int n1, int n2){
002013C0 push ebp
002013C1 mov ebp,esp
002013C3 sub esp,0C0h
002013C9 push ebx
002013CA push esi
002013CB push edi
002013CC lea edi,[ebp-0C0h]
002013D2 mov ecx,30h
002013D7 mov eax,0CCCCCCCCh
002013DC rep stos dword ptr es:[edi]
return;
}
002013DE pop edi
002013DF pop esi
002013E0 pop ebx
002013E1 mov esp,ebp
002013E3 pop ebp
002013E4 ret 8
很明显改变了参数返回的时候值就会变化而且是函数内部的变化所以是函数内部平栈,绝大部分的windows api都是stdcall,但是也有特例,比如wsprintf
char szBuf[256] = {0};
wsprintfA(szBuf,"%s","1234");
这里很明显因为他是由外界传入的参数来决定多少,所以是函数外部平参
继续回到动态加载dll
1.将目标dll加载到我们进程中
HMODULE hDll = LoadLibraryA("./TestDLL.dll");
返回值是模块句柄


这里就可以看到我们的dll完全被加载到我们的内存里面来了,所以说返回的模块句柄也就是当前dll在当前进程中的首地址,加载过程是由我们的操作系统来完成的(包括各节的扩展分配内存,重定位等等),有时候也可以自己写loadlibraby因为用这个函数太官方了,自己写就叫做内存加载,这是很多病毒的手法
2.计算函数的位置
都有个偏移

可以看到偏移是11122
LPVOID lp = GetProcAddress(hDll, "Test");

可以看到20000+11122 = 31122
也可以写个def
LIBRARY
EXPORTS
Test
这里得到的就是个函数指针
typedef void(*PFN_FPP)();
PFN_FPP lp = (PFN_FPP)GetProcAddress(hDll, "Test");
最后再调用就可以了
lp();
但是如何要求目标进程调用Loadlibrary来加载我们的dll,最后运行我们的dll中的导出函数


可以看到Loadlibrary是存在于Kernel32.dll中的,所以先去找目标进程中的Kernel32.dll的位置,一般程序中都有Kernel32.dll这个,因为他是个很基本的dll
然后再找到该dll导出的loadlibraryA或W函数的位置
因为我们都是用的同一个kernel32.dll所以我们可以通过一个公式堆出来目标进程中的loadlibrary的地址
公式:目标的loadlibrary - 目标的kernel32地址 = 本地的loadlibrary - 本地的kernel32地址
//获取进程句柄
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
HANDLE hDestModule = NULL;
//接下来找到该进程中kernel32.dll的基址
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
MODULEENTRY32 mo32 = { 0 };
mo32.dwSize = sizeof(MODULEENTRY32);
bRet = Module32First(hSnap, &mo32);
while (bRet)
{
bRet = Module32Next(hSnap, &mo32);
wprintf(mo32.szExePath);
std::wstring wstr = mo32.szExePath;
if (wstr.find(L"KERNEL32.DLL") != std::string::npos){
hDestModule = mo32.modBaseAddr;
break;
}
}
LPVOID lpDestAddr = NULL;
if (hDestModule != NULL){
//获取本进程的kernel32地址
HMODULE hkernel32 = GetModuleHandleA("KERNEL32.DLL");
//计算函数的位置
LPVOID lploadlibrary = GetProcAddress(hkernel32, "LoadLibraryA");
//获取了目标进程中的loadlibrary的地址
lpDestAddr = (char*)lploadlibrary - (char*)hkernel32 + (char*)hDestModule;
}
我们获取到了loadlibrary的地址后就通过CreateRemoteThread加载dll地址和函数地址来调用
//1.在目标进程开辟空间
LPVOID lpAddr = VirtualAllocEx(
hProcess, //在目标进程中开辟空间
NULL, //表示任意地址,随机分配
1, //内存通常是以分页为单位来给空间 1页=4k 4096字节
MEM_COMMIT, //告诉操作系统给分配一块内存
PAGE_EXECUTE_READWRITE
);
if (lpAddr == NULL){
printf("Alloc error!");
return 0;
}
DWORD dwWritesBytes = 0;
char* pDestDllPath = R"(G:\mytools\TestDll\jiazai\Debug\TestDLL.dll)";
//2.在目标进程中写入目标dll的路径
bRet = WriteProcessMemory(
hProcess, //目标进程
lpAddr, //目标地址 目标进程中
pDestDllPath, //源数据 当前进程中
strlen(pDestDllPath)+1, //写多大
&dwWritesBytes //成功写入的字节数
);
if (!bRet){
VirtualFreeEx(hProcess, lpAddr, 1, MEM_DECOMMIT);
return 0;
}
//3.向目标程序调用一个线程 创建远程线程 执行写入代码
HANDLE hRemoteThread = CreateRemoteThread(hProcess, //目标进程
NULL,
0,
(LPTHREAD_START_ROUTINE)LoadLibraryA, //目标进程的回调函数
lpAddr, //回调参数
0,
NULL
);

可以看到注入成功了
完整代码
// shellcode.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <TlHelp32.h>
#include <string>
typedef void(*PFN_FOO)();
int main()
{
//获取快照
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe32;
DWORD pid = 0;
pe32.dwSize = sizeof(PROCESSENTRY32);
//查看第一个进程
BOOL bRet = Process32First(hSnap, &pe32);
while (bRet)
{
bRet = Process32Next(hSnap, &pe32);
if (wcscmp(pe32.szExeFile, L"procexp.exe") == 0){
pid = pe32.th32ProcessID;
break;
}
}
//获取进程句柄
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
HANDLE hDestModule = NULL;
//接下来找到该进程中kernel32.dll的基址
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
MODULEENTRY32 mo32 = { 0 };
mo32.dwSize = sizeof(MODULEENTRY32);
bRet = Module32First(hSnap, &mo32);
while (bRet)
{
bRet = Module32Next(hSnap, &mo32);
wprintf(mo32.szExePath);
std::wstring wstr = mo32.szExePath;
if (wstr.find(L"KERNEL32.DLL") != std::string::npos){
hDestModule = mo32.modBaseAddr;
break;
}
}
LPVOID lpDestAddr = NULL;
if (hDestModule != NULL){
//获取本进程的kernel32地址
HMODULE hkernel32 = GetModuleHandleA("KERNEL32.DLL");
//计算函数的位置
LPVOID lploadlibrary = GetProcAddress(hkernel32, "LoadLibraryA");
//获取了目标进程中的loadlibrary的地址
lpDestAddr = (char*)lploadlibrary - (char*)hkernel32 + (char*)hDestModule;
}
//1.在目标进程开辟空间
LPVOID lpAddr = VirtualAllocEx(
hProcess, //在目标进程中开辟空间
NULL, //表示任意地址,随机分配
1, //内存通常是以分页为单位来给空间 1页=4k 4096字节
MEM_COMMIT, //告诉操作系统给分配一块内存
PAGE_EXECUTE_READWRITE
);
if (lpAddr == NULL){
printf("Alloc error!");
return 0;
}
DWORD dwWritesBytes = 0;
char* pDestDllPath = R"(G:\mytools\TestDll\TestDLL\Debug\TestDLL.dll)";
//2.在目标进程中写入目标dll的路径
bRet = WriteProcessMemory(
hProcess, //目标进程
lpAddr, //目标地址 目标进程中
pDestDllPath, //源数据 当前进程中
strlen(pDestDllPath)+1, //写多大
&dwWritesBytes //成功写入的字节数
);
if (!bRet){
VirtualFreeEx(hProcess, lpAddr, 1, MEM_DECOMMIT);
return 0;
}
//3.向目标程序调用一个线程 创建远程线程 执行写入代码
HANDLE hRemoteThread = CreateRemoteThread(hProcess, //目标进程
NULL,
0,
(LPTHREAD_START_ROUTINE)lpDestAddr, //目标进程的回调函数
lpAddr, //回调参数
0,
NULL
);
return 0;
}
所以我们直接把代码写入dll里面就可以为所欲为了,但是不要写同步的代码,不然加载dll会卡死,然后如果我们想要获取到我们注入模块的地址,其实就是需要lpDestAddr的返回值,这里怎么获取,就有一个小技巧,hRemoteThread 这个是线程的模块而lpDestAddr才是我们注入的dll的地址,这里其实只需要获取线程的退出码,就可以获得loadlibrarya的返回基地址
DWORD dwRetCode;
//获取远线程的退出值
GetExitCodeThread(hRemoteThread, &dwRetCode);

同一个文件允许同一个dll加载多次而且地址是不变的只是引用次数会+1

动态加载dll的实现+远线程注入的更多相关文章
- 用宏定义封装LoadLibrary,方便的动态加载dll
同学们动态加载dll的时候是不是感觉挺麻烦的,每次都::LoadLibrary,::GetProcAddress,还要typedef一堆函数.最近闲来无聊,用宏封装了一下,可以少写不少代码,用来也挺方 ...
- Delphi静态加载DLL和动态加载DLL示例
下面以Delphi调用触摸屏动态库xtkutility.dll为例子,说明如何静态加载DLL和动态加载DLL. 直接上代码. 1.静态加载示例 unit Unit1; interface uses W ...
- C# 利用反射动态加载dll
笔者遇到的一个问题,dll文件在客户端可以加载成功,在web端引用程序报错.解决方法:利用反射动态加载dll 头部引用加: using System.Reflection; 主要代码: Assembl ...
- c#实现动态加载Dll(转)
c#实现动态加载Dll 分类: .net2009-12-28 13:54 3652人阅读 评论(1) 收藏 举报 dllc#assemblynullexceptionclass 原理如下: 1.利用反 ...
- unity3d动态加载dll的API以及限制
Unity3D的坑系列:动态加载dll 一.使用限制 现在参与的项目是做MMO手游,目标平台是Android和iOS,iOS平台不能动态加载dll(什么原因找乔布斯去),可以直接忽略,而在Androi ...
- Unity3D的坑系列:动态加载dll
我现在参与的项目是做MMO手游,目标平台是Android和iOS,iOS平台不能动态加载dll(什么原因找乔布斯去),可以直接忽略,而在Android平台是可以动态加载dll的,有了这个就可以实现代码 ...
- C#,动态加载DLL,通过反射,调用参数,方法,窗体
.net中常会用到动态加载DLL,而DLL中可能包含各种参数.方法.窗体,如何来调用动态加载这些参数.方法.窗体呢? 在C#中,我们要使用反射,首先要搞清楚以下命名空间中几个类的关系: System. ...
- 动态加载Dll时,通过Type生成类对象
原文:动态加载Dll时,通过Type生成类对象 转:http://www.cnblogs.com/zfanlong1314/p/4197383.html "反射"其实就是利用程序集 ...
- c#实现动态加载Dll
原文:c#实现动态加载Dll 原理如下: 1.利用反射进行动态加载和调用. Assembly assembly=Assembly.LoadFrom(DllPath); //利用dll的路径加载,同时将 ...
随机推荐
- SpringBoot--- SpringSecurity进行注销,权限控制
SpringBoot--- SpringSecurity进行注销,权限控制 环境 IDEA :2020.1 Maven:3.5.6 SpringBoot: 2.0.9 (与此前整合的版本2.3.3 不 ...
- 自动化项目Jenkins持续集成
一.Jenkins的优点 1.传统网站部署流程 一般网站部署的流程 这边是完整流程而不是简化的流程 需求分析—原型设计—开发代码—内网部署-提交测试—确认上线—备份数据—外网更新-最终测试 ,如果 ...
- Http请求的三个常见问题
我们做的大多数项目,必不可少的需要向后台发送请求获取数据,常用的http请求就是post请求和get请求 那么引出一个最常见的问题——Q:post请求和get请求有什么区别? A: 从语义上我们可以这 ...
- 赫然:Windows Live Writer 批量博客更新软件使用教程
http://www.wocaoseo.com/thread-144-1-1.html 推广人员需要使用多个博客,一个一个登陆更新是很麻烦的事情,网上的桌面批量更新博客软件也不少,今天在此推荐大家使用 ...
- Apache Tika实战
Apache Tika实战 Tika 简介 Apache Tika 是一个内容分析工具包,可以检测上千种文件类型,并提取它们的元数据和文本.tika在设计上十分精巧,单一的接口使它易于使用,在搜索引擎 ...
- 使用 C# 捕获进程输出
使用 C# 捕获进程输出 Intro 很多时候我们可能会需要执行一段命令获取一个输出,遇到的比较典型的就是之前我们需要用 FFMpeg 实现视频的编码压缩水印等一系列操作,当时使用的是 FFMpegC ...
- Typed Lua
https://the-ravi-programming-language.readthedocs.io/en/latest/ravi-overview.html https://github.com ...
- 给IE9及其以下等不支持classList属性的浏览器,添加classList属性
// 解决IE9及其以下 不支持classList属性的问题 if (!("classList" in document.documentElement)) { Object.de ...
- 常见的开源 License
目录 什么是开源软件 什么是 license 商业许可证与开源许可证 对开发者的影响 开源许可证的类型 如何选择开源许可证 什么是开源软件 开放源代码的软件.假设有一天自我感觉代码能力不错,写了个小工 ...
- LAMP环境之编译安装httpd服务
“Apache HTTP Server”是开源软件项目的杰出代表,它基于标准的 HTTP 网络协议提供网页浏览服务. 在配置 Apache 网站服务之前,需要正确安装好 httpd 服务器软件.htt ...