Table of Contents

References


  • 《加密与解密》(第四版)第 12 章 注入技术
  • 《加密与解密》(第四版)随书文件下载地址
  • DllMain 详解

注入技术介绍


使用 DLL 注入目标进程再执行相关操作是优先使用的一种手段,不仅避免了跨进程操作带来的繁琐过程及安全限制上的问题,更重要的是能够直接执行我们自己的代码,从而方便地进行 Hook、Patch 等操作 ————《加密与解密》(第四版)第 12 章 注入技术

我的一个简单理解就是 DLL 注入可以让我们在目标程序中执行我们自己的代码,而这个自己的代码就是写在注入的 DLL 中

在程序被加载到内存前,即执行程序前,修改程序文件,在导入表中增加一个元素,这个元素就对应我们注入的一个 DLL 文件,程序在加载到内存时会将导入表中所有 DLL 也加载进来

实验具体


程序及工具准备

这次实验中我一共用到了两个程序,一个工具

  1. notepad.exe(Windows 自带)
  2. MsgDLL.dll(《加密与解密》随书文件提供,也可自己编译,随书文件下载地址)
  3. Stud_PE 汉化版(吾爱破解 WinXP 虚拟机工具包中提供,虚拟机镜像下载地址

MsgDLL.dll

MsgDll.dll的主要功能是在DllMain中弹出一个 MessageBox 来展示自己的存在

MsgDll.cpp文件:

/*-----------------------------------------------------------------------
第12章  注入技术
《加密与解密(第四版)》
(c)  看雪学院 www.kanxue.com 2000-2018
-----------------------------------------------------------------------*/

// MsgDll.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include <stdio.h>


VOID Msg();

DWORD WINAPI ThreadShow(LPVOID lpParameter);
void WriteLog(char *info,char *logfilename);

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        CreateThread(NULL,0,ThreadShow,NULL,0,NULL);
    }
    return TRUE;
}

DWORD WINAPI ThreadShow(LPVOID lpParameter)
{
    char szPath[MAX_PATH]={0};
    char szBuf[1024]={0};

    GetModuleFileName(NULL,szPath,MAX_PATH);
    sprintf(szBuf,"Dll已注入到进程 %s [Pid = %d]\n",szPath,GetCurrentProcessId());
    //以三种方式显示自己的存在
    //1.控制台
    //fprintf((FILE*)GetStdHandle(STD_ERROR_HANDLE),"%s",szBuf);
    printf("%s",szBuf);
    //2.调试器
    OutputDebugString(szBuf);
    //3.Msgbox
    Sleep(800);
    MessageBox(NULL,szBuf,"Dll Inject",MB_OK);
    return 0 ;
}

void WriteLog(char *info,char *logfilename)
{
    HANDLE  hFile;
    static char tmp[100];
    DWORD   dwwritten=0;
    static SYSTEMTIME systime;
    GetLocalTime(&systime);
    sprintf(tmp,"%04dd-%02d-%02d %02d:%02d:%02d  ",systime.wYear,systime.wMonth,systime.wDay,systime.wHour,systime.wMinute,systime.wSecond);
    hFile=CreateFile(logfilename,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
    if(INVALID_HANDLE_VALUE!=hFile)
    {
        SetFilePointer(hFile,0,0,SEEK_END);
        WriteFile(hFile,tmp,lstrlen(tmp),&dwwritten,NULL);
        WriteFile(hFile,info,lstrlen(info),&dwwritten,NULL);
        WriteFile(hFile,"\r\n",2,&dwwritten,NULL);
        CloseHandle(hFile);
    }

}
//导出函数
VOID Msg()
{

}

可见导出函数Msg里什么都没做,而DllMain函数就像是 DLL 文件的 Main 函数,在静态链接时,或动态链接时调用 LoadLibrary 和 FreeLibrary 都会调用 DllMain 函数

简单来说:在进行 DLL 注入后,我们在执行notepad.exe时会进行 DLL 的加载,而这时在加载我们注入的MsgDll.dll文件时,其中的DllMain函数会得到调用,而这DllMain函数内的代码是我们能控制的,即达到了任意命令执行的效果

既然随书文件中有了编译好的MsgDll.dll文件,那我直接拿来用好了 hhhh,就不自己编译一次了

利用 PE 工具进行 DLL 注入

Stud_PE打开notepad.exe然后点击导入表:

在输入函数框内右键后添加新的导入,添加前:

添加后:

添加成功

注入效果演示

注入后双击 notepad.exe 运行:

可见我们在DllMain中写入的代码得到了执行,DLL 注入成功

注入中到底修改了哪些部分


修改思路

这里可以参考《加密与解密》书中的介绍,逻辑非常清晰,这里就不重复了,但指的提出的是:书中的修改方法还是有些细节与改工具不同的:

  1. 书中是扩展了最后一个节的大小,然后在扩展的部分中进行了 Import Table 表的构造,而该工具是直接新增了一个节
  2. 书中新增 IID 的 OriginalFirstThunk 和 FirstThunk 等数据放到了原来的 IID 的位置,而工具中则是将 OriginalFirstThunk 和 FirstThunk 等数据安排到了新增的节

文件比较

使用 Stud_PE 中的文件比较比较注入前后的文件:

File Header(1 处修改)

  • 可以看出新增了一个 section

Optional Header(2 处修改)

  • SizeOfInitializedData:
  • SizeOfImage

Data_Directories(1 处修改)

  • Import Table

其值由原来的0xC800007604变成了0xDC00013000