12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
三国霸业 战车-珍宝-觉醒-攻城掠地SF-全新玩法 免费玩新区 攻城掠地私服 进入游戏
手游私服盒子 各类免费游戏 0.1折送海量资源 各类手游私服 进入游戏
皇家MU2 《奇迹 2:传奇》韩国网禅公司《奇迹》正统续作。 3D锁视角Mmrpg 暗黑3+传奇+流放之路+奇迹 进入游戏
查看: 206|回复: 0

《逆向工程核心原理》-- DLL注入与卸载

[复制链接]

312

主题

312

帖子

634

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
634
发表于 2020-7-22 10:24:46 | 显示全部楼层 |阅读模式
DLL注入和卸载

一、DLL注入

DLL注入:向运行中的其他进程强制插入特定的DLL文件,主要是下令其他进程自行调用LoadLibrary() API,加载用户指定的DLL文件。
DLL注入与一般DLL加载的主要区别是加载的目标进程是其自身或其他进程。
1. DLL

DLL(Dynamic Linked Library,动态链接库),DLL被加载到进程后会自动运行DllMain函数,用户可以把想要执行的额代码放到DllMain函数,每当加载DLL时,添加的代码就会自动得到执行。使用该特性可以修复程序BUG,或向程序添加新功能。
// DllMain()函数 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvRserved){  switch(dwReason)  {    case DLL_PROCESS_ATTACH:      // 添加想要执行的代码      break;    case DLL_THREAD_ATTACH:      break;    case DLL_THREAD_DETACH:      break;    case DLL_PROCESS_DETACH:      break;  }  return TRUE;}2. DLL注入实例

使用LoadLibrary()加载某个DLL时,该DLL中的DllMain()函数会被调用执行。DLL注入的原理就是从外部促使目标进程调用LoadLibrary() API。

  • 改善功能与修复BUG
  • 消息钩取--Windows 默认提供的消息钩取功能本质上应用的就是一种DLL注入技术
  • API钩取--先创建DLL形态的钩取函数,然后注入要钩取的目标进程,主要是应用了被注入的DLL拥有目标进程内存访问权限这一特性
  • 其他应用程序--监督、管理PC用户的应用程序
  • 恶意代码--非法注入,进行代码隐蔽
3. DLL注入的实现方法

1. 创建远程线程(CreateRemoteThread() API)

此处主要记录一下书上的源码分析,操作部分请自行实践。
// myhack.cpp#include "windows.h"#include "tchar.h"#pragma comment(lib, "urlmon.lib")#define DEF_URL             (L"http://www.naver.com/index.html")#define DEF_FILE_NAME   (L"index.html")HMODULE g_hMod = NULL;DWORD WINAPI ThreadProc(LPVOID lParam){    TCHAR szPath[_MAX_PATH] = {0,};    if( !GetModuleFileName( g_hMod, szPath, MAX_PATH ) )        return FALSE;    TCHAR *p = _tcsrchr( szPath, '\\' );    if( !p )        return FALSE;    _tcscpy_s(p+1, _MAX_PATH, DEF_FILE_NAME); //参数准备    URLDownloadToFile(NULL, DEF_URL, szPath, 0, NULL); //调用函数进行URL下载    return 0;}BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){    HANDLE hThread = NULL;    g_hMod = (HMODULE)hinstDLL;    switch( fdwReason )    {    case DLL_PROCESS_ATTACH :         OutputDebugString(L" Injection!!!");        //创建远程线程进行download        hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);        // 必要注意,切记随手关闭句柄,保持好习惯        CloseHandle(hThread);        break;    }    return TRUE;}// InjectDll.cpp#include "windows.h"#include "tchar.h"BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath){    HANDLE hProcess = NULL, hThread = NULL;    HMODULE hMod = NULL;    LPVOID pRemoteBuf = NULL;          //确定路径必要占用的缓冲区大小    DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);     LPTHREAD_START_ROUTINE pThreadProc;    // #1. 使用OpenProcess函数获取目标进程句柄(PROCESS_ALL_ACCESS权限)    if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )    {        _tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());        return FALSE;    }    // #2. 使用VirtualAllocEx函数在目标进程中分配内存,大小为szDllName          // VirtualAllocEx函数返回的是hProcess指向的目标进程的分配所得缓冲区的内存地址    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);    // #3.  将myhack.dll路径 ("c:\\myhack.dll")写入目标进程中分配到的内存    WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);    // #4. 获取LoadLibraryA() API的地址          // 这里主要使用来了kernel32.dll文件在每个进程中的加载地址都相同这一特点,以是不管是获取加载到                  // InjectDll.exe照旧notepad.exe进程的kernel32.dll中的LoadLibraryW函数的地址都是一样的。这里的加载地          // 址相同指的是在同一次系统运行中,如果再次启动系统kernel32.dll的加载地址会变,但是每个进程的          // kernerl32.dll的加载地址照旧一样的。          hMod = GetModuleHandle(L"kernel32.dll");    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");    // #5. 在目标进程notepad.exe中运行远程线程          // pThreadProc = notepad.exe进程内存中的LoadLibraryW()地址          // pRemoteBuf = notepad.exe进程内存中待加载注入dll的路径字符串的地址    hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);    WaitForSingleObject(hThread, INFINITE);                  //同样,记得关闭句柄    CloseHandle(hThread);    CloseHandle(hProcess);    return TRUE;}int _tmain(int argc, TCHAR *argv[]){    if( argc != 3)    {        _tprintf(L"USAGE : %s  \n", argv[0]);        return 1;    }    // change privilege    if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )        return 1;    // inject dll    if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) )        _tprintf(L"InjectDll(\"%s\") success!!!\n", argv[2]);    else        _tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]);    return 0;}main()函数主要检查输入程序的参数,然后调用InjectDll函数。InjectDll函数是实行DLL注入的核心函数,功能是下令目标进程自行调用LoadLibrary API。
重点介绍一下CreateRemoteThread()函数,该函数在进行DLL注入时会常常用到,其函数原型如下:
CreateRemoteThread()HANDLE WINAPI CreateRemoteThread(  __in HANDLE    hProcess,        //目标进程句柄  __in LPSECURITY_ATTRIBUTES   lpThreadAttributes,  __in SIZE_T dwStackSize,  __in LPTHREAD_START_ROUTNE        lpStartAddress,        //线程函数地址  __in LPVOID dwCreationFlags,        //线程参数地址  __out LPDOWRD lpThreadId);2. AppInit_DLLs

第二种方法是操作注册表,Windows的注册表中默认提供了AppInit_DLLs与LoadAppInit_DLLs两个注册表项,只要将要注入DLL的路径字符串写入AppInit_DLLs项目,并在LoadAppInit_DLLs中设置值为1,重启时,系统就会将指定的DLL注入到所有运行进程中。主要原理是User32.dll被加载到进程时,会读取AppInit_DLLs注册表项,若值为1,就调用LoadLibrary()函数加载用户DLL。以是严格来说,是将注入DLL加载到使用user32.dll的进程中。
// myhack2.cpp// 主要作用是以隐蔽模式运行IE,连接到指定网站#include "windows.h"#include "tchar.h"#define DEF_CMD  L"c:\\Program Files\\Internet Explorer\\iexplore.exe" #define DEF_ADDR L"http://www.naver.com"#define DEF_DST_PROC L"notepad.exe"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){    TCHAR szCmd[MAX_PATH]  = {0,};    TCHAR szPath[MAX_PATH] = {0,};    TCHAR *p = NULL;    STARTUPINFO si = {0,};    PROCESS_INFORMATION pi = {0,};    si.cb = sizeof(STARTUPINFO);    si.dwFlags = STARTF_USESHOWWINDOW;    si.wShowWindow = SW_HIDE;    switch( fdwReason )    {    case DLL_PROCESS_ATTACH :         if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )            break;        if( !(p = _tcsrchr(szPath, '\\')) )            break;        if( _tcsicmp(p+1, DEF_DST_PROC) )            break;        wsprintf(szCmd, L"%s %s", DEF_CMD, DEF_ADDR);        if( !CreateProcess(NULL, (LPTSTR)(LPCTSTR)szCmd,                             NULL, NULL, FALSE,                             NORMAL_PRIORITY_CLASS,                             NULL, NULL, &si, &pi) )            break;        if( pi.hProcess != NULL )            CloseHandle(pi.hProcess);        break;    }    return TRUE;}将上述dll文件复制到某个位置,修改注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microdoft\Windows NT\CurrentVersion\Windows,将AppInit_DLLs项的值修改为待注入DLL的绝对路径,然后修改LoadAppInit_DLLs注册表项的值为1,重启,运行notepad.exe,就会看到DLL已经被注入。
3. 使用SetWindowsHookEx()函数

第三个方法就是消息钩取,使用SetWindowsHookEx安装钩子,将指定DLL强制注入进程。
二、DLL卸载

DLL卸载原理:驱使目标进程调用FreeLibrary()函数,即将FreeLibrary()函数的地址通报给CreateRemoteThread()函数的lpStartAddress参数,并把待卸载的DLL句柄通报给lpParameter参数。
必要注意的一点是:引用计数问题。调用一次FreeLibrary()函数,引用计数就会-1。引用计数表示的是内核对象被使用的次数。
// EjectDll.exe#include "windows.h"#include "tlhelp32.h"#include "tchar.h"#define DEF_PROC_NAME        (L"notepad.exe")#define DEF_DLL_NAME        (L"myhack.dll")DWORD FindProcessID(LPCTSTR szProcessName){    DWORD dwPID = 0xFFFFFFFF;    HANDLE hSnapShot = INVALID_HANDLE_VALUE;    PROCESSENTRY32 pe;    // 获取系统快照    pe.dwSize = sizeof( PROCESSENTRY32 );    hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL );    // 查找进程    Process32First(hSnapShot, &pe);    do    {        if(!_tcsicmp(szProcessName, (LPCTSTR)pe.szExeFile))        {            dwPID = pe.th32ProcessID;            break;        }    }    while(Process32Next(hSnapShot, &pe));    CloseHandle(hSnapShot);    return dwPID;}BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) {    TOKEN_PRIVILEGES tp;    HANDLE hToken;    LUID luid;    if( !OpenProcessToken(GetCurrentProcess(),                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,                                       &hToken) )    {        _tprintf(L"OpenProcessToken error: %u\n", GetLastError());        return FALSE;    }    if( !LookupPrivilegeValue(NULL,           // lookup privilege on local system                              lpszPrivilege,  // privilege to lookup                               &luid) )        // receives LUID of privilege    {        _tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError() );         return FALSE;     }    tp.PrivilegeCount = 1;    tp.Privileges[0].Luid = luid;    if( bEnablePrivilege )        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;    else        tp.Privileges[0].Attributes = 0;    // Enable the privilege or disable all privileges.    if( !AdjustTokenPrivileges(hToken,                                FALSE,                                &tp,                                sizeof(TOKEN_PRIVILEGES),                                (PTOKEN_PRIVILEGES) NULL,                                (PDWORD) NULL) )    {         _tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError() );         return FALSE;     }     if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )    {        _tprintf(L"The token does not have the specified privilege. \n");        return FALSE;    }     return TRUE;}BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName){    BOOL bMore = FALSE, bFound = FALSE;    HANDLE hSnapshot, hProcess, hThread;    HMODULE hModule = NULL;    MODULEENTRY32 me = { sizeof(me) };    LPTHREAD_START_ROUTINE pThreadProc;    // dwPID = notepad 进程ID    // 使用TH32CS_SNAPMODULE参数,获取加载到notepad进程的DLL名称    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);    bMore = Module32First(hSnapshot, &me);    for( ; bMore ; bMore = Module32Next(hSnapshot, &me) )    {        if( !_tcsicmp((LPCTSTR)me.szModule, szDllName) ||             !_tcsicmp((LPCTSTR)me.szExePath, szDllName) )        {            bFound = TRUE;            break;        }    }    if( !bFound )    {        CloseHandle(hSnapshot);        return FALSE;    }    if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )    {        _tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());        return FALSE;    }    hModule = GetModuleHandle(L"kernel32.dll");          // 获取FreeLibrary函数加载地址,并使用CreateRemoteThread进行调用    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");    hThread = CreateRemoteThread(hProcess, NULL, 0,                                  pThreadProc, me.modBaseAddr,                                  0, NULL);    WaitForSingleObject(hThread, INFINITE);            CloseHandle(hThread);    CloseHandle(hProcess);    CloseHandle(hSnapshot);    return TRUE;}int _tmain(int argc, TCHAR* argv[]){    DWORD dwPID = 0xFFFFFFFF;    // 查找process    dwPID = FindProcessID(DEF_PROC_NAME);    if( dwPID == 0xFFFFFFFF )    {        _tprintf(L"There is no  process!\n", DEF_PROC_NAME);        return 1;    }    _tprintf(L"PID of \"%s\" is %d\n", DEF_PROC_NAME, dwPID);    // 更改 privilege    if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )        return 1;    // 注入 dll    if( EjectDll(dwPID, DEF_DLL_NAME) )        _tprintf(L"EjectDll(%d, \"%s\") success!!!\n", dwPID, DEF_DLL_NAME);    else        _tprintf(L"EjectDll(%d, \"%s\") failed!!!\n", dwPID, DEF_DLL_NAME);    return 0;}CreateToolhelp32Snapshot()函数主要用来获取加载到进程的模块信息,将获取的hSnapshot句柄通报给Module32First()/Module32Next()函数后,即可设置与MODULEENTRY32结构相关的模块信息,以下为该结构的具体界说:
typedef sturc tagMODULEENTRY32{        DWORD dwSize;  DWORD th32ModuleID;                // 该模块  DWORD th32ProcessID;        // 模块拥有的进程  DWORD GlbcntUsage;                //模块中的global usage计数  DWORD ProcessUsage;                  BYTE * modBaseAddr;                //在进程的上下文中的模块的基地址  DWORD modBaseSize;                // 在modBaseAddr开始位置的模块的大小(字节为单位)  HMODULE hModule;  char szModule[MAX_MODULE_NAME32+1];        //DLL名称  char szExePath[MAX_PATH];}MODULEENTRY32;参考

《逆向工程核心原理》


来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-11-25 09:46 , Processed in 0.078125 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表