2018-07-13 DLL注入(一)

DLL注入是把指定的DLL加载到另一个进程的内存空间中去。


DLL注入技术:1、通过远程线程注入

                         2、通过全局消息钩子注入

                         3、通过注册表注入

                         4、通过输入法注入

                         5、驱动注入

                         6、在启动进程时挂起主线程,写入指令后再恢复线程

                         7、DLL劫持

                         8、修改PE文件导入表

                         9、使用NtMapViewOfSection注入

                         10、使用SetThreadContext注入


通过远程线程注入:1、用OpenProcess打开要注入进程的句柄

                                2、用VirtualAllocEx在远程进程中申请一段内存,长度为DLL路径长度+1(多出来的一字节用于存放\0)

                                3、用WriteProcessMemory将DLL的路径远程写入申请的内存中

                                4、用CreateRemoteThread将LoadLibraryA作为线程启动函数,参数为DLL的路径,远程创建线程

                                5、用CloseHandle关闭线程句柄

                                6、调用DllMain函数,在函数里完成要做的事。

实现代码:

BOOL InjectDll(DWORD dwProcessID, char* dllPath){//参数:目标进程ID、DLL路径

FARPROC FuncAddr = NULL;

HMODULE hdll = LoadLibrary(TEXT("Kernel32.dll"));//加载DLL

if (hdll != NULL){

FuncAddr = GetProcAddress(hdll, "LoadLibraryA");//获取LoadLibraryA函数地址

if (FuncAddr == NULL)return FALSE;

}

HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION, FALSE, dwProcessID);//获取进程句柄

if (hProcess == NULL)return FALSE;

DWORD dwSize = strlen(dllPath) + 1;

LPVOID RemoteBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);//远程申请内存

DWORD dwRealSize;

if (WriteProcessMemory(hProcess, RemoteBuf, dllPath, dwSize, &dwRealSize))//远程写内存

{

DWORD dwThreadId;

HANDLE hRemoteThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)FuncAddr, RemoteBuf, 0, &dwThreadId);//创建远程线程

if (hRemoteThread == NULL)

{

VirtualFreeEx(hProcess, RemoteBuf, dwSize, MEM_COMMIT);

CloseHandle(hProcess);

return FALSE;

}

//释放资源

WaitForSingleObject(hRemoteThread, INFINITE);

CloseHandle(hRemoteThread);

VirtualFreeEx(hProcess, RemoteBuf, dwSize, MEM_COMMIT);

CloseHandle(hProcess);

return TRUE;

}

else

{

VirtualFreeEx(hProcess, RemoteBuf, dwSize, MEM_COMMIT);

CloseHandle(hProcess);

return FALSE;

}

}


通过全局消息钩子注入

通过设置全局消息钩子来实现dll注入,然后窗体有相关消息请求会自动加载注入dll,在入口处做处理。

dll注入期间注入程序不可以退出,否则dll内核句柄有可能被释放

源码:

DLL调用

/*

HMODULE h = LoadLibrary(L"xx.dll");

_SetHook SetHook = (_SetHook)GetProcAddress(h,"SetHook");

_UnHook UnHook = (_UnHook)GetProcAddress(h,"UnHook");

SetHook();

Sleep(10000);

UnHook();

CloseHandle(h);

*/


//DLL相关代码 

#include <windows.h>

#include <tlhelp32.h>

#include <psapi.h>


#pragma comment(lib,"psapi.lib")


#pragma data_seg("Yrrehs")

HHOOK HT = NULL;

#pragma data_seg()

HINSTANCE DLLhinst = NULL;

LRESULT CALLBACK CProc(int nCode,WPARAM wParam,LPARAM lParam){

return CallNextHookEx(HT,nCode,wParam,lParam);

}

//安装钩子

extern "C" __declspec(dllexport) BOOL SetHook(){

HT = SetWindowsHookEx(WH_CALLWNDPROC,CProc,DLLhinst,0);

if(HT == NULL){

return false;

}

return true;

}

//卸载钩子

extern "C" __declspec(dllexport) BOOL UnHook(){

BOOL HM_BOOL = FALSE;

if(HT != NULL){

HM_BOOL = UnhookWindowsHookEx(HT);

}

return HM_BOOL;

}

//获得进程名

wchar_t* GetProcessName(DWORD processID){

HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,processID);

wchar_t *procName = new wchar_t[MAX_PATH];

GetModuleFileNameEx(hProcess,NULL,procName,MAX_PATH);

CloseHandle(hProcess);

return procName;

}

//获得进程名

wchar_t* GetProcessName(wchar_t *FileName){

size_t len = wcslen(FileName);

size_t i = len-1;

for(;i>=0;i--){

if(FileName[i] == L'\\'){

break;

}

}

wchar_t *temp = FileName + i + 1;

return temp;

}

BOOL WINAPI DllMain(HINSTANCE hinstDll,DWORD fdwReason,LPVOID lpvReserved){

DLLhinst = hinstDll;

if(DLL_PROCESS_ATTACH == fdwReason){

wchar_t *procName = GetProcessName(GetCurrentProcessId());

if(_wcsicmp(L"xxx.exe",GetProcessName(procName))==0){

//XXXXXX

}

}

if(DLL_PROCESS_DETACH == fdwReason){

}

return TRUE;

}



通过注册表注入

在系统中每一个进程加载User32.dll时,会受到DLL_PROCESS_ATTACH通知,当User32.dll对其进行处理时,会取得注册表键值HKEY_LOCAL_MACHINE\Software\Microsoft\windowsNT\CurrentVersion\Windows\AppInit_Dlls,并调用LoadLibrary来载入这个字符串指定的每个DLL。被调用的DLL会在系统调用它们的DllMain函数,并将参数fdwReason的值设为DLL_PROCESS_ATTACH时,对自己进行初始化。所以我们在这个键值中添加我们的Dll路径,即可实现注入。

注入流程:

1、打开注册表键值如下:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\

2、在上面的注册表项中操作AppInit_DLLs键值,在该键值中添加自己的DLL的全路径加dll名,多个DLL以逗号或者空格分开(因此在文件名中应该尽量不要存在空格),该键值只有第一个dll文件名可以包含路径,后面的都不能包含,因此最好将dll放在系统路径,这样可以不用包含路径也能被加载。

3、在该注册表项中添加键值LoadAppInit_DLLs,类型为DWORD,并将其值置为1。

关于注册表操作的API:

RegOpenKeyEx                         打开注册表键值

RegQueryValueEx                      查询键值

RegSetValueEx                           设置键值

RegCloseKey                               关闭键值


源码:

//打开键值

    nReg = RegOpenKeyEx(

        HKEY_LOCAL_MACHINE,

        m_szRegPath,

        0,

        KEY_ALL_ACCESS,

        &hKey);

    if(nReg != ERROR_SUCCESS)

    {

        return FALSE;

    } 

    //查询键值

    DWORD dwReadType;

    DWORD dwReadCount;

    TCHAR szReadBuff[1000] = {0};

    nReg = RegQueryValueEx(hKey,

        _T("AppInit_DLLs"),

        NULL,

        &dwReadType,

        (BYTE*)&szReadBuff,

        &dwReadCount);

    if(nReg != ERROR_SUCCESS)

    {

        return FALSE;

    }

    //是否dll名称已经在内容中

    tstring strCmpBuff;

    strCmpBuff = szReadBuff;

    if (!strCmpBuff.find(InjectFilePath))

    {

        return FALSE;

    }

    //有字符串就加入空格

    if (0 != _tcscmp(szReadBuff,_T("")))

    {

        _tcscat_s(szReadBuff,_T(" "));

    }

    _tcscat_s(szReadBuff,InjectFilePath);

    //把dll路径设置到注册表中

    nReg = RegSetValueEx(hKey,

        _T("AppInit_DLLs"),

        0,

        REG_SZ,

        (CONST BYTE*)szReadBuff,

        (_tcslen(szReadBuff)+1)*sizeof(TCHAR));


完成注册表注入之后,并不是希望所有程序都运行DLL里面的内容,需要在DLL中过滤窗口名称,让指定窗口名称的EXE文件运行DLL里的线程。所需API如下所示:

CreateThread                              创建线程

Sleep                                           睡眠

EnumWindows                            遍历窗口

GetWindowsText                         得到窗口名称

GetCurrentProcessId                  得到当前进程ID

GetWindowThreadProcessId      由HWND获得进程ID

为了实现此功能,需要在注入的DLL中创建线程,并在线程中执行遍历窗口函数,我们需要先获取窗口名称,与我们想运行的EXE名称进行对比,并进行进程ID对比,因为不光只有一个EXE文件的运行实例,经过这些过滤后,可以在指定的EXE文件中运行代码。

源码:

BOOL CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)

{

    TCHAR str[MAXBYTE] = {0};

    //得到窗口名称

    GetWindowText(hwnd,str,sizeof(str));

    //是否名称是计算器

    if(0 == _tcscmp(str,_T("计算器")))

    {

        //由于存在可能多个计算器,需要过滤线程ID

        //得到本身线程的ID

        DWORD dwCurrentProcessId = GetCurrentProcessId();

        DWORD dwFindCurrentProcessId = 0;

        //得到窗口线程ID

        GetWindowThreadProcessId(hwnd,&dwFindCurrentProcessId);

        //比较

        if (dwCurrentProcessId == dwFindCurrentProcessId)

        {

            *(PDWORD)lParam = 1;

            return FALSE;

        }

    }

    return TRUE;

}

DWORD ThreadProc(LPVOID lParam)

{

    //等待1秒时间以便于让windows创建窗口

    Sleep(1000);

    DWORD dwFind = 0;

    //遍历窗口,过滤窗口名称

    EnumWindows(lpEnumFunc,(LPARAM)&dwFind);

    if (!dwFind) return 0;


// 运行代码

    return 0;

}

BOOL InitInstance()

{

    DWORD dwThreadId;

    m_hThread = ::CreateThread(NULL, NULL,

        (LPTHREAD_START_ROUTINE)ThreadProc,

        this, NULL,&dwThreadId);

    return TRUE;

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,027评论 0 2
  • ## 可重入函数 ### 可重入性的理解 若一个程序或子程序可以安全的被并行执行,则称其为可重入的;即当该子程序正...
    夏至亦韵阅读 698评论 0 0
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,689评论 0 3
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,733评论 0 38
  • 其实目前还是值得感赏的,目前的生活都是我要的,天天在图书馆翻译书,每天吸引力法则用的也不错。所以说,2018...
    猫公主喵阅读 180评论 0 0