dll 源码_【表哥有话说 第74期】Dll注入浅谈

一、DLL注入概述

1.简介

dll注入是一种将Windows动态链接库注入到目标进程中的技术,具体的说,就是将dll文件加载到一个进程的虚拟地址空间中。对某个进程进行dll注入,也就意味着dll模块与该进程共用一个进程空间,则这个dll文件就有了操纵这个进程空间的能力,以达到执行dll模块中的代码修改进程数据的能力。

2. 原理

DLL注入的工作原理是将自己的dll文件强制注入进其他进程,同时,被注入的DLL拥有目标进程的内存访问权限从而实现一些有用的功能。

例如:

  1. 改善功能与修复BUg

  2. 消息钩取

  3. API钩取

  4. 恶意代码

  5. ....

二、几种常见的DLL注入手段

各个方式都分为注入程序和DLL程序两部分,其中DLL基本都是一样的,我们的目标是把我们自己的DLL注入程序中,不同的方式使用不同的注入程序,从而实现DLL注入。

1.远程线程注入

所用主要API

  1. LoadLibrary():用来加载DLL文件,

  2. CreateRemoteThread() :在其他程序中启动远程线程,使程序自动启用LoadLibrary()函数,从而加载DLL文件

  3. WriteProcessMemory():在其他进程中写入数据

程序源码

BOOL InjectProgram(DWORD dwPID, LPCTSTR path){HANDLE hProcess = NULL, hThread = NULL;HMODULE hMod = NULL;LPVOID pRemoteBuf = NULL;DWORD dwBufSize = (DWORD)(_tcslen(path) + 1) * sizeof(TCHAR);LPTHREAD_START_ROUTINE pThreadProc;//用获取的PID找到注入进程的句柄hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);if (!hProcess){MessageBox(NULL, L"句柄失败", L"Error",MB_OK);_tprintf(L"Inject fail PID=%d,error is %d", dwPID, GetLastError);return 0;}//在目标进程的内存中分配空间pRemoteBuf = (LPVOID)VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);//在分配好的空间中写入dll文件名WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)path, dwBufSize, NULL);//获取LoadLibrary API的地址hMod = GetModuleHandle(L"kernel32.dll");pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");hThread = CreateRemoteThread(hProcess,NULL,0,pThreadProc,pRemoteBuf,0,NULL);if (!hThread){return 0;}WaitForSingleObject(hThread, INFINITE);CloseHandle(hThread);CloseHandle(hProcess);return TRUE;}int _tmain(int argc,TCHAR* argv[])  //主函数名为_tmain(),否则无法接受参数{if (argc != 3){MessageBox(NULL, L"Error", L"参数错误", MB_OK);OutputDebugString(L"参数数量不对");}else{BOOL flag;_tprintf(L"%d,Inject PID=%d", argc,(DWORD)_tstol(argv[1]));flag=InjectProgram((DWORD)_tstol(argv[1]), argv[2]);if (flag){MessageBox(NULL, L"YES", L"成功", MB_OK);}else{MessageBox(NULL, (LPCWSTR)&argv[1], L"错误", MB_OK);}}    }

2.修改注册表注入

手动改注册表

运行regedit.exe,可以打开注册表编辑器,

fd5b2420093c270069d2812ff7431dce.png

找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\windows NT\windows,我们需要该其中的两项

8f41e50d0fde0ce72f5da97a0ef1b145.png

需要改AppInit_DLLs,以及LoadAppInt_DLLs。

AppInit_DLLs的值会让程序在加载user32.dll时同时加载,就像你在食堂打一碗饭,食堂大妈顺手给了你一碗汤。

LoadAppInt_DLLs的值改为1,让程序加载上一项中修改的DLL地址。

重启之后生效。

程序自动注入

注入程序:

#define DSTKEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"BOOL RegInject(WCHAR* path);int main(){WCHAR Dllpath[MAX_PATH] = L"C:\\Users\\Y\\Desktop\\myhack.dll";BOOL flag = RegInject(Dllpath);if (flag){_tprintf(L"SUCCESS");}else{printf("erro\n");}    }BOOL RegInject(WCHAR* path){HKEY key = NULL;BYTE Dllpath[MAX_PATH] = { 0 };if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, DSTKEY, 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS){printf("Inject faile\n");return false;}memcpy((void*)Dllpath, path,_tcslen(path)*2+1);if (RegSetValueEx(key, L"AppInit_DLLs", 0, REG_SZ, Dllpath, (_tcslen(path) + 1)*sizeof(TCHAR))!=ERROR_SUCCESS){printf("set error\n");return false;}DWORD dwValue = 1;if (RegSetValueEx(key, L"LoadAppInit_DLLs", 0, REG_DWORD,(BYTE*)&dwValue, sizeof(dwValue)) != ERROR_SUCCESS){printf("set2 error\n");return false;}return true;}

3.消息钩取

利用windows提供的setWindowsHook()API,我们可以利用其实现DLL注入。他会截取不同的消息,通过你设置的参数,来注入相应的进程。以下是MSDN给出的用法,

HHOOK SetWindowsHookExA(  int       idHook,    //钩子类型,比如键盘输入(WH_KEYBOARD),鼠标点击(WH_MOUSE)等  HOOKPROC  lpfn,      //钩子调用函数,当截取到想要的消息时,会调用这个函数  HINSTANCE hmod,     //dll句柄  DWORD     dwThreadId   //进程PID,为0表示为全局钩子);

当他监听到你想要的消息类型,会自动将dll注入到相应的进程,并执行相应的函数。

主要代码如下:

extern "C" _declspec(dllexport) void HookStart(){//    HHOOK hHook = NULL;    g_hHook=SetWindowsHookEx(WH_KEYBOARD, HookProc,        GetModuleHandle("E://Viusal Studio//kanxue//注入技术//SetWindowsHookEx//Inject_dll//Debug//Inject_dll.dll"), 0);    if (NULL == g_hHook)    {        MessageBox(NULL, "安装钩子失败", "提示", MB_OKCANCEL);    }}

三、Dll注入实战--扫雷的自动游戏

通过对扫雷程序的逆向研究(这个不属于本次的范围,我就不展开讲了),我们可以找到扫雷实现的一个原理:维护一段内存,并通过这段内存上的值来确定某个位置是炸弹还是空白区域,所以,我们要做的就是通过读取这块内存的值,从而判断某个地方是炸弹还是空白,要不要插旗子。

因为我们知道,dll注入后的dll文件可以访问和操作被注入文件的内存地址,所以我们就可以采用dll注入的方法,把dll文件注入到扫雷程序中去,然后执行一段代码,代替我们去点击方块。

39a07aee9d0d0630803f99c2c989d709.png

943559c2397ecd04c595e77870f7c735.png

以下是dll文件主要源码:

void _stdcall Kill(){FILE* f = NULL;BYTE Flag;//标志是否有雷int a;char s[10] = { 0 };for (int i = 1; i <= 9; i++){for (int ii = 1; ii <= 9; ii++){if (!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)(0x01005340 + i * 32 + ii), &Flag, 1, NULL))MessageBox(NULL, TEXT("读取失败"), NULL, MB_OK);if (Flag == 0x0f)  //0x0f表示没有雷,左键点击{a = ((63 + (i-1) * 16) << 16) + 19 + (ii-1) * 16;PostMessage(FindWindow(NULL, TEXT("扫雷")), WM_LBUTTONDOWN, 0, a);PostMessage(FindWindow(NULL, TEXT("扫雷")), WM_LBUTTONUP, 0, a);//Sleep(1000);}else if (Flag == 0x8f) //0x8f表示有雷,右键插旗子{a = ((63 + (i - 1) * 16) << 16) + 19 + (ii - 1) * 16;PostMessage(FindWindow(NULL, TEXT("扫雷")), WM_RBUTTONDOWN, 0, a);PostMessage(FindWindow(NULL, TEXT("扫雷")), WM_RBUTTONUP, 0, a);//Sleep(1000);}}}}BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved                     ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:Kill();break;    case DLL_THREAD_ATTACH:    case DLL_THREAD_DETACH:    case DLL_PROCESS_DETACH:        break;    }    return TRUE;}

参考:《逆向工程核心原理》

https://www.cnblogs.com/HsinTsao/p/6541883.html

https://bbs.pediy.com/thread-253918.htm

- END -

e75796354dd650904dc27a9ed2e8c9d7.png TimeKeeper扫码关注,学习更多
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值