0
点赞
收藏
分享

微信扫一扫

DLL注入:远程线程注入

Dll 代码:

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <tlhelp32.h>

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBox(NULL,L"DLL_PROCESS_ATTACH",L"LYSM",NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

注入器代码:

#include "stdafx.h"
#include<stdio.h>
#include<Windows.h>
#include<TlHelp32.h>
#include <iostream>

using namespace std;

// 进程名查PID
DWORD getProcessHandle(LPCTSTR lpProcessName)
{
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process = {sizeof(PROCESSENTRY32)};

while (Process32Next(hProcessSnap,&process))
{
if(strcmp(process.szExeFile, lpProcessName) == 0){return process.th32ProcessID;}
}

cout << "没有找到进程" << endl;
return 0;
}

int main(int argc,char *argv[])
{

// 初始化
DWORD dwpid = getProcessHandle("Injector.exe");
LPCSTR lpDllName = "E:\\MyFiles\\Programing\\vs2012\\MyPrograms\\Test_Dll\\Debug\\Test_Dll.dll";

// 取 Injector.exe 句柄
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS, // 所有权限
FALSE, // 进程不继承句柄
dwpid // PID
);
if(!hProcess){cout << "OpenProcess 失败: " << GetLastError() << endl;}

// 为 dll 分配内存,并记录基地址
DWORD dwSize = strlen(lpDllName)+1;
LPVOID lpRemoteBuf = VirtualAllocEx(
hProcess, // 进程句柄
NULL, // 分配的起始地址
dwSize, // 分配的区域大小
MEM_COMMIT, // 类型,MEM_COMMIT:分配内存
PAGE_READWRITE // 内存保护属性,PAGE_READWRITE:可读可写
);

// 写入内存
if(!WriteProcessMemory(
hProcess, // 进程句柄
lpRemoteBuf, // dll 基地址指针
lpDllName, // 写入内容的缓冲区指针
dwSize, // 缓冲区字节大小
NULL // 接收实际写入的字节数
))
{cout << "WriteProcessMemory 失败:" << GetLastError() << endl;}

// 创建远程线程
HANDLE hNewRemoteThread = CreateRemoteThread(
hProcess, // 进程句柄
NULL, // 默认安全描述符,不继承句柄
NULL, // 默认的堆栈初始大小
(LPTHREAD_START_ROUTINE)LoadLibraryA, // 远程线程起始地址
lpRemoteBuf, // 线程函数基地址指针
NULL, // 线程在创建之后立即运行
NULL // 不返回线程标识符
);
if(!hNewRemoteThread){cout << "CreateRemoteThread 失败:" << GetLastError() << endl;}

// 等待线程句柄返回
WaitForSingleObject(
hNewRemoteThread, // 线程句柄
INFINITE // 超时时间,INFINITE:不返回则一直等待
);

// 关闭线程句柄
CloseHandle(hNewRemoteThread);


getchar();
return 0;
}

此处为 32 位程序,所以注入 64 位进程会失败!

64 位注入,参考

int main()
{
BOOL bFlag = FALSE;

char *szDllName = "MSGDLL.dll";
//bFlag = EnablePrivilege(SE_DEBUG_NAME); //返回值为1时代表成功

//得到目标进程句柄
HANDLE hDestProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, );

LPTHREAD_START_ROUTINE dwAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");

//在目标进程的地址空间内分配一个内存块
LPVOID pRemoteSpace = VirtualAllocEx(hDestProcess, NULL, strlen(szDllName) + , MEM_COMMIT,
PAGE_READWRITE);

//向上一步的内存块中写入数据,就是要加载的DLL名字
bFlag = WriteProcessMemory(hDestProcess, pRemoteSpace, szDllName, strlen(szDllName) + , );

//在目标进程内创建线程,线程的入口函数就是LoadLibraryA, 参数就是Dll名字
HANDLE hThread = CreateRemoteThread(hDestProcess, NULL, , dwAddr, pRemoteSpace,
NULL,
); //前面都是成功的,就到了这一步,返回的错误是5,Access denied,权限不够
//本来以为我的VS是以管理员权限启动的,那么我这个进程应该权限就都够了,
//看来不行,必须程序提权
//我提权了之后,发现还是不行,之后上网查了
//发现是32位注入到64位中会有问题,所以我换了个x64,然后显然线程运行成功了,
//但是现在远程进程却崩溃了,估计是DLL是32的,我换个DLL编译方式再试试
//我编译了64位的DLL,然后还是崩溃的,之后我发现了应该是我函数地址传的有问题
//因为32位的LoadLibraryA地址是DWORD,但64位却是ULONGLONG,所以仅仅改变编译方式还不够
//必须用一个足够容纳8个字节地址的类型来保存,这样就够了

//另外一个需要注意的问题就是,为什么我在我这个进程中得到的LoadLibrary在远程进程中也可以用
//答案就是,系统DLL在各个进程中的映射地址都是一样的,不过具体情况具体分析,至少这个函数看来是一样的。

//在我完成了之后,我把EnablePrivileges这行注释掉了,但仍然注入成功,看来我用管理员权限运行VS2015之后就够了

//然后我又发现了一个问题,就是对同一个进程,加载dll只能一次,第二次就不会弹了
//原因,我目测是,DLL已经被加载了,所以第二次就不加载了,也就不执行DllMain那个函数了
//除非我创建一个线程再UnLoad那个LIB,之后再LOAD,这样应该就可以了
//也可以换个Dll名字,再LOAD, 反正方法很多。

DWORD dwErr = GetLastError();

return ;
}

注入器

//DLL的代码,用DLL方式生成一下,拉到前面EXE目录,或者系统目录都行,跟前面代码中DLL名字有没有加绝对路径有关
//这代码是书上的代码,直接复制了
/* ************************************
*《精通Windows API》
* 示例代码
* msg.c
* 6.5 动态链接库
**************************************/
/* 头文件 */
#include <Windows.h>
#include <Psapi.h>
/* 链接 */
#pragma comment (lib, "Psapi.lib")
/* 函数声明 */

// 使用__declspec(dllexport)声明导出函数
__declspec(dllexport) DWORD ExportExample(LPSTR szMsg, DWORD dwCode);

/*************************************
* DllMain
**************************************/
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // DLL模块的句柄
DWORD fdwReason, // 调用的情况
LPVOID lpReserved) // reserved
{
// 在不同的情况下都会调用DllMain函数,分别处理
switch (fdwReason)
{
// 加载Dll
case DLL_PROCESS_ATTACH:
{
CHAR lpMainMoudleName[MAX_PATH];
CHAR lpMessage[MAX_PATH + ];
// 获取PID 和主模块名,将弹出消息框
DWORD dwPID = GetCurrentProcessId();
GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH);
wsprintf(lpMessage, "Process name: %s, PID: %u ", lpMainMoudleName, dwPID);
MessageBox(NULL, lpMessage, "msg.dll", MB_OK);
break;
}
// 新建线程
case DLL_THREAD_ATTACH:
break;
// 线程退出
case DLL_THREAD_DETACH:
break;
// 释放Dll
case DLL_PROCESS_DETACH:

break;
}
return TRUE;
}

/*************************************
* DWORD ExportExample(LPSTR szMsg, DWORD dwCode)
* 功能 导出函数,显示消息
*
* 参数 LPSTR szMsg 字符串; DWORD dwCode 整形
**************************************/
DWORD ExportExample(LPSTR szMsg, DWORD dwCode)
{
LPVOID lpShowOut = HeapAlloc(GetProcessHeap(), , lstrlen(szMsg) + );
wsprintf((LPSTR)lpShowOut, "%s,%d", szMsg, dwCode);
MessageBox(NULL, (LPSTR)lpShowOut, "由导出函数弹出的消息!", MB_OK);
HeapFree(GetProcessHeap(), , lpShowOut);
return ;
}

需要注意的点都在那一大串注释中

64位进程,就得用64位的EXE来CreateRemoteThread, 另外DLL也应该是64位

32位进程,就得用32位的EXE来CreateRemoteThread, 另外DLL也应该是32位

把CreateRemoteThread的入口点函数设为LoadLibraryA(W),线程的那个参数设为DLL路径指针(在目标进程中,所以得把DLL路径拷到目标进程 中, 用VirtualAllocEx在目标进程中分配块空间,然后WriteProcessMemory).

这样可行的原因:

线程的函数原型DWORD ThreadProc(LPVOID lpParam)

LoadLibrary的函数原型HMODULE LoadLibrary(LPCTSTR lpFileName);

其实是一样的,指针都是同样大小,都只有一个参数,返回值无所谓..

另外在目标进程和本进程中LoadLibraryA(W)的虚拟地址是一样的..

版权声明:本博客文章与代码均为学习时整理的笔记,文章 [均为原创] 作品,转载请 [添加出处] ,您添加出处是我创作的动力!





举报

相关推荐

0 条评论